Merge branch 'master' into 3.0.0

pull/985/head
Nikita 8 years ago
commit 70e019a5cd

@ -2,9 +2,30 @@ Redisson Releases History
================================
### Please Note: trunk is current development branch.
### 10-Jun-2017 - versions 2.9.3 and 3.4.3 released
__[Redisson PRO](https://redisson.pro)__ now costs only __$975__ per year and supports unlimited Redisson instances
### 12-Jul-2017 - versions 2.9.4 and 3.4.4 released
Feature - [Config.performanceMode](https://github.com/redisson/redisson/wiki/2.-Configuration/_edit#performancemode) setting added
Feature - JsonJacksonMapCodec codec added
Feature - [Amazon Ion](https://amzn.github.io/ion-docs/) codec added
Feature - [read-through, write-through and write-behind](https://github.com/redisson/redisson/wiki/7.-Distributed-collections/#714-map-persistence) support for RMap objects
Feature - `RExecutorService` should return RExecutorFuture object with taskId
Feature - added `RList.get` method to load elements in a batch
Feature - ability to submit few tasks atomically (in batch) through `RExecutorService` interface
Feature - [Config.keepPubSubOrder](https://github.com/redisson/redisson/wiki/2.-Configuration#keeppubsuborder) setting added
Improvement - make `RMapReactive` and `RMapCacheReactive` interfaces match with `RMap` and `RMapCache`
Improvement - `RLexSortedSet` should extend `RSortedSet`
Fixed - `RMapCache` `remove`, `put`, `putIfAbsent` and `replace` methods aren't respect entry expiration
Fixed - `SCAN` command should be used in `RKeys.deleteByPattern` method
Fixed - `RBinaryStream` doesn't work in Redis cluster environment
Fixed - `SELECT` command shouldn't be executed on Sentinel servers
Fixed - Stackoverflow error arise during decoding of large amount of PubSub messages
Fixed - `LocalCachedMapInvalidate` object can't be serialized by Kryo codec
Fixed - `XMLGregorianCalendar` type handling in JSON codec
Fixed - Reactive Stream methods shouldn't be executed immediately after `Publisher` object creation
__!PRICE REDUCTION!__ - __Ultra-fast [Redisson PRO](https://redisson.pro)__ now costs only __$975__ per year and supports unlimited Redisson instances
### 10-Jun-2017 - versions 2.9.3 and 3.4.3 released
Since this version, if you use programmatic config definition you should define full url with schema.

@ -6,8 +6,8 @@ Based on high-performance async and lock-free Java Redis client and [Netty](http
| Stable Release Version | JDK Version compatibility | Release Date |
| ------------- | ------------- | ------------|
| 3.4.3 | 1.8+ | 10.06.2017 |
| 2.9.3 | 1.6, 1.7, 1.8 and Android | 10.06.2017 |
| 3.4.4 | 1.8+ | 12.07.2017 |
| 2.9.4 | 1.6, 1.7, 1.8 and Android | 12.07.2017 |
__NOTE__: Both version lines have same features except `CompletionStage` interface added in 3.x.x
@ -67,6 +67,7 @@ Used by
[![Datorama](https://redisson.org/assets/logos/client8.png "Datorama")](https://datorama.com/)    
[![OptionsHouse](https://redisson.org/assets/logos/client9.png "OptionsHouse")](https://www.optionshouse.com/)    
[![Invaluable](https://redisson.org/assets/logos/client13.png "Invaluable")](http://www.invaluable.com/)
[![Ticketmaster](https://redisson.org/assets/logos/client14.png "Ticketmaster")](http://www.ticketmaster.com/)
Success stories
================================
@ -81,23 +82,23 @@ Quick start
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.4.3</version>
<version>3.4.4</version>
</dependency>
<!-- JDK 1.6+ compatible -->
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>2.9.3</version>
<version>2.9.4</version>
</dependency>
#### Gradle
// JDK 1.8+ compatible
compile 'org.redisson:redisson:3.4.3'
compile 'org.redisson:redisson:3.4.4'
// JDK 1.6+ compatible
compile 'org.redisson:redisson:2.9.3'
compile 'org.redisson:redisson:2.9.4'
#### Java
@ -122,11 +123,11 @@ RExecutorService executor = redisson.getExecutorService("myExecutorService");
Downloads
===============================
[Redisson 3.4.3](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson&v=3.4.3&e=jar),
[Redisson node 3.4.3](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson-all&v=3.4.3&e=jar)
[Redisson 3.4.4](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson&v=3.4.4&e=jar),
[Redisson node 3.4.4](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson-all&v=3.4.4&e=jar)
[Redisson 2.9.3](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson&v=2.9.3&e=jar),
[Redisson node 2.9.3](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson-all&v=2.9.3&e=jar)
[Redisson 2.9.4](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson&v=2.9.4&e=jar),
[Redisson node 2.9.4](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson-all&v=2.9.4&e=jar)
### Supported by

@ -26,22 +26,22 @@ Usage
**2** Copy two jars into `TOMCAT_BASE/lib` directory:
1. __For JDK 1.8+__
[redisson-all-3.4.3.jar](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson-all&v=3.4.3&e=jar)
[redisson-all-3.4.4.jar](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson-all&v=3.4.4&e=jar)
for Tomcat 6.x
[redisson-tomcat-6-3.4.3.jar](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson-tomcat-6&v=3.4.3&e=jar)
[redisson-tomcat-6-3.4.4.jar](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson-tomcat-6&v=3.4.4&e=jar)
for Tomcat 7.x
[redisson-tomcat-7-3.4.3.jar](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson-tomcat-7&v=3.4.3&e=jar)
[redisson-tomcat-7-3.4.4.jar](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson-tomcat-7&v=3.4.4&e=jar)
for Tomcat 8.x
[redisson-tomcat-8-3.4.3.jar](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson-tomcat-8&v=3.4.3&e=jar)
[redisson-tomcat-8-3.4.4.jar](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson-tomcat-8&v=3.4.4&e=jar)
2. __For JDK 1.6+__
[redisson-all-2.9.3.jar](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson-all&v=2.9.3&e=jar)
[redisson-all-2.9.4.jar](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson-all&v=2.9.4&e=jar)
for Tomcat 6.x
[redisson-tomcat-6-2.9.3.jar](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson-tomcat-6&v=2.9.3&e=jar)
[redisson-tomcat-6-2.9.4.jar](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson-tomcat-6&v=2.9.4&e=jar)
for Tomcat 7.x
[redisson-tomcat-7-2.9.3.jar](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson-tomcat-7&v=2.9.3&e=jar)
[redisson-tomcat-7-2.9.4.jar](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson-tomcat-7&v=2.9.4&e=jar)
for Tomcat 8.x
[redisson-tomcat-8-2.9.3.jar](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson-tomcat-8&v=2.9.3&e=jar)
[redisson-tomcat-8-2.9.4.jar](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson-tomcat-8&v=2.9.4&e=jar)

@ -1,6 +1,8 @@
package org.redisson.tomcat;
import java.io.File;
import java.io.IOException;
import java.nio.file.Paths;
import org.apache.catalina.LifecycleException;
import org.apache.http.client.ClientProtocolException;
@ -10,6 +12,9 @@ import org.apache.http.cookie.Cookie;
import org.apache.http.impl.client.BasicCookieStore;
import org.junit.Assert;
import org.junit.Test;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
public class RedissonSessionManagerTest {
@ -95,7 +100,12 @@ public class RedissonSessionManagerTest {
@Test
public void testInvalidate() throws LifecycleException, InterruptedException, ClientProtocolException, IOException {
public void testInvalidate() throws Exception {
File f = Paths.get("").toAbsolutePath().resolve("src/test/webapp/WEB-INF/redisson.yaml").toFile();
Config config = Config.fromYAML(f);
RedissonClient r = Redisson.create(config);
r.getKeys().flushall();
// start the server at http://localhost:8080/myapp
TomcatServer server = new TomcatServer("myapp", 8080, "/src/test/");
server.start();
@ -115,9 +125,12 @@ public class RedissonSessionManagerTest {
cookieStore.addCookie(cookie);
executor.use(cookieStore);
read(executor, "test", "null");
invalidate(executor);
Executor.closeIdleConnections();
server.stop();
Assert.assertEquals(0, r.getKeys().count());
}
private void write(Executor executor, String key, String value) throws IOException, ClientProtocolException {

@ -56,6 +56,11 @@ public class RedissonSession extends StandardSession {
map = redissonManager.getMap(id);
}
public void delete() {
map.delete();
map = null;
}
@Override
public void setCreationTime(long time) {
super.setCreationTime(time);

@ -106,10 +106,12 @@ public class RedissonSessionManager extends ManagerBase {
}
@Override
public void remove(Session session) {
super.remove(session);
public void remove(Session session, boolean update) {
super.remove(session, update);
getMap(session.getId()).delete();
if (session.getIdInternal() != null) {
((RedissonSession)session).delete();
}
}
public RedissonClient getRedisson() {

@ -1,6 +1,8 @@
package org.redisson.tomcat;
import java.io.File;
import java.io.IOException;
import java.nio.file.Paths;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.fluent.Executor;
@ -9,6 +11,9 @@ import org.apache.http.cookie.Cookie;
import org.apache.http.impl.client.BasicCookieStore;
import org.junit.Assert;
import org.junit.Test;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
public class RedissonSessionManagerTest {
@ -95,6 +100,11 @@ public class RedissonSessionManagerTest {
@Test
public void testInvalidate() throws Exception {
File f = Paths.get("").toAbsolutePath().resolve("src/test/webapp/WEB-INF/redisson.yaml").toFile();
Config config = Config.fromYAML(f);
RedissonClient r = Redisson.create(config);
r.getKeys().flushall();
// start the server at http://localhost:8080/myapp
TomcatServer server = new TomcatServer("myapp", 8080, "src/test/");
server.start();
@ -114,9 +124,12 @@ public class RedissonSessionManagerTest {
cookieStore.addCookie(cookie);
executor.use(cookieStore);
read(executor, "test", "null");
invalidate(executor);
Executor.closeIdleConnections();
server.stop();
Assert.assertEquals(0, r.getKeys().count());
}
private void write(Executor executor, String key, String value) throws IOException, ClientProtocolException {

@ -40,7 +40,6 @@ public class RedissonSession extends StandardSession {
public RedissonSession(RedissonSessionManager manager) {
super(manager);
this.redissonManager = manager;
try {
Field attr = StandardSession.class.getDeclaredField("attributes");
attrs = (Map<String, Object>) attr.get(this);
@ -57,6 +56,11 @@ public class RedissonSession extends StandardSession {
map = redissonManager.getMap(id);
}
public void delete() {
map.delete();
map = null;
}
@Override
public void setCreationTime(long time) {
super.setCreationTime(time);

@ -105,10 +105,12 @@ public class RedissonSessionManager extends ManagerBase {
}
@Override
public void remove(Session session) {
super.remove(session);
public void remove(Session session, boolean update) {
super.remove(session, update);
getMap(session.getId()).delete();
if (session.getIdInternal() != null) {
((RedissonSession)session).delete();
}
}
public RedissonClient getRedisson() {

@ -1,6 +1,8 @@
package org.redisson.tomcat;
import java.io.File;
import java.io.IOException;
import java.nio.file.Paths;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.fluent.Executor;
@ -9,6 +11,9 @@ import org.apache.http.cookie.Cookie;
import org.apache.http.impl.client.BasicCookieStore;
import org.junit.Assert;
import org.junit.Test;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
public class RedissonSessionManagerTest {
@ -95,6 +100,11 @@ public class RedissonSessionManagerTest {
@Test
public void testInvalidate() throws Exception {
File f = Paths.get("").toAbsolutePath().resolve("src/test/webapp/WEB-INF/redisson.yaml").toFile();
Config config = Config.fromYAML(f);
RedissonClient r = Redisson.create(config);
r.getKeys().flushall();
// start the server at http://localhost:8080/myapp
TomcatServer server = new TomcatServer("myapp", 8080, "src/test/");
server.start();
@ -114,9 +124,12 @@ public class RedissonSessionManagerTest {
cookieStore.addCookie(cookie);
executor.use(cookieStore);
read(executor, "test", "null");
invalidate(executor);
Executor.closeIdleConnections();
server.stop();
Assert.assertEquals(0, r.getKeys().count());
}
private void write(Executor executor, String key, String value) throws IOException, ClientProtocolException {

@ -28,7 +28,7 @@ public class TomcatServer {
tomcat.setBaseDir("."); // location where temp dir is created
tomcat.setPort(port);
tomcat.getHost().setAppBase(".");
tomcat.getHost().setAppBase(appBase);
tomcat.addWebapp(contextPath, appBase + "webapp");
}

@ -30,7 +30,6 @@ import org.redisson.api.RBatch;
import org.redisson.api.RBinaryStream;
import org.redisson.api.RBitSet;
import org.redisson.api.RBlockingDeque;
import org.redisson.api.RBlockingFairQueue;
import org.redisson.api.RBlockingQueue;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RBoundedBlockingQueue;
@ -453,16 +452,6 @@ public class Redisson implements RedissonClient {
return new RedissonPatternTopic<M>(codec, connectionManager.getCommandExecutor(), pattern);
}
@Override
public <V> RBlockingFairQueue<V> getBlockingFairQueue(String name) {
return new RedissonBlockingFairQueue<V>(connectionManager.getCommandExecutor(), name, semaphorePubSub, id, this);
}
@Override
public <V> RBlockingFairQueue<V> getBlockingFairQueue(String name, Codec codec) {
return new RedissonBlockingFairQueue<V>(codec, connectionManager.getCommandExecutor(), name, semaphorePubSub, id, this);
}
@Override
public <V> RDelayedQueue<V> getDelayedQueue(RQueue<V> destinationQueue) {
if (destinationQueue == null) {

@ -1,782 +0,0 @@
/**
* 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.Arrays;
import java.util.Collections;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import org.redisson.api.RBlockingFairQueue;
import org.redisson.api.RFuture;
import org.redisson.api.RedissonClient;
import org.redisson.client.codec.Codec;
import org.redisson.client.codec.LongCodec;
import org.redisson.client.codec.StringCodec;
import org.redisson.client.protocol.RedisCommands;
import org.redisson.command.CommandExecutor;
import org.redisson.misc.RPromise;
import org.redisson.pubsub.SemaphorePubSub;
import io.netty.util.Timeout;
import io.netty.util.TimerTask;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.FutureListener;
/**
*
* @author Nikita Koksharov
*
*/
public class RedissonBlockingFairQueue<V> extends RedissonBlockingQueue<V> implements RBlockingFairQueue<V> {
public static final long TIMEOUT_SECONDS = 30;
private final UUID id;
private final AtomicInteger instances = new AtomicInteger();
private final SemaphorePubSub semaphorePubSub;
protected RedissonBlockingFairQueue(CommandExecutor commandExecutor, String name, SemaphorePubSub semaphorePubSub, UUID id, RedissonClient redisson) {
super(commandExecutor, name, redisson);
this.semaphorePubSub = semaphorePubSub;
this.id = id;
instances.incrementAndGet();
}
protected RedissonBlockingFairQueue(Codec codec, CommandExecutor commandExecutor, String name, SemaphorePubSub semaphorePubSub, UUID id, RedissonClient redisson) {
super(codec, commandExecutor, name, redisson);
this.semaphorePubSub = semaphorePubSub;
this.id = id;
instances.incrementAndGet();
}
private String getIdsListName() {
return suffixName(getName(), "list");
}
private String getTimeoutName() {
return suffixName(getName(), "timeout");
}
private String getChannelName() {
return suffixName(getName(), getCurrentId() + ":channel");
}
private RedissonLockEntry getEntry() {
return semaphorePubSub.getEntry(getName());
}
private RFuture<RedissonLockEntry> subscribe() {
return semaphorePubSub.subscribe(getName(), getChannelName(), commandExecutor.getConnectionManager());
}
private void unsubscribe(RFuture<RedissonLockEntry> future) {
semaphorePubSub.unsubscribe(future.getNow(), getName(), getChannelName(), commandExecutor.getConnectionManager());
}
@Override
public RFuture<Boolean> deleteAsync() {
return commandExecutor.writeAsync(getName(), RedisCommands.DEL_OBJECTS, getName(), getIdsListName(), getTimeoutName());
}
private Long tryAcquire() {
return get(tryAcquireAsync());
}
private RFuture<Long> tryAcquireAsync() {
long timeout = System.currentTimeMillis() + TIMEOUT_SECONDS*1000;
return commandExecutor.evalWriteAsync(getName(), LongCodec.INSTANCE, RedisCommands.EVAL_LONG,
"local timeout = redis.call('get', KEYS[3]);"
+ "if timeout ~= false and tonumber(timeout) <= tonumber(ARGV[3]) then "
+ "redis.call('lpop', KEYS[2]); "
+ "local nextValue = redis.call('lindex', KEYS[2], 0); "
+ "if nextValue ~= false and nextValue ~= ARGV[1] then "
+ "redis.call('set', KEYS[3], ARGV[2]);"
+ "redis.call('publish', '{' .. KEYS[1] .. '}:' .. nextValue .. ':channel', 1);"
+ "end; "
+ "end; "
+ "local items = redis.call('lrange', KEYS[2], 0, -1) "
+ "local found = false; "
+ "for i=1,#items do "
+ "if items[i] == ARGV[1] then "
+ "found = true; "
+ "break;"
+ "end; "
+ "end; "
+ "if found == false then "
+ "redis.call('lpush', KEYS[2], ARGV[1]); "
+ "end; "
+ "local value = redis.call('lindex', KEYS[2], 0); "
+ "if value == ARGV[1] then "
+ "redis.call('set', KEYS[3], ARGV[2]);"
+ "local size = redis.call('llen', KEYS[2]); "
+ "if size > 1 then "
+ "redis.call('lpop', KEYS[2]);"
+ "redis.call('rpush', KEYS[2], value);"
+ "local nextValue = redis.call('lindex', KEYS[2], 0); "
+ "redis.call('publish', '{' .. KEYS[1] .. '}:' .. nextValue .. ':channel', 1);"
+ "end; "
+ "return nil;"
+ "end;"
+ "return tonumber(timeout) - tonumber(ARGV[3]);",
Arrays.<Object>asList(getName(), getIdsListName(), getTimeoutName()), getCurrentId(), timeout, System.currentTimeMillis());
}
private String getCurrentId() {
return id.toString();
}
@Override
public V take() throws InterruptedException {
Long currentTimeout = tryAcquire();
if (currentTimeout == null) {
return super.take();
}
RFuture<RedissonLockEntry> future = subscribe();
commandExecutor.syncSubscription(future);
try {
while (true) {
currentTimeout = tryAcquire();
if (currentTimeout == null) {
return super.take();
}
getEntry().getLatch().tryAcquire(currentTimeout, TimeUnit.MILLISECONDS);
}
} finally {
unsubscribe(future);
}
}
@Override
public void destroy() {
if (instances.decrementAndGet() == 0) {
get(commandExecutor.evalWriteAsync(getName(), StringCodec.INSTANCE, RedisCommands.EVAL_VOID,
"for i = 1, #ARGV, 1 do "
+ "redis.call('lrem', KEYS[1], 0, ARGV[i]);"
+"end; ",
Collections.<Object>singletonList(getIdsListName()), getCurrentId()));
}
}
@Override
public RFuture<V> takeAsync() {
final RPromise<V> promise = newPromise();
RFuture<Long> tryAcquireFuture = tryAcquireAsync();
tryAcquireFuture.addListener(new FutureListener<Long>() {
@Override
public void operationComplete(Future<Long> future) throws Exception {
if (!future.isSuccess()) {
promise.tryFailure(future.cause());
return;
}
final Long currentTimeout = future.getNow();
if (currentTimeout == null) {
final RFuture<V> pollFuture = RedissonBlockingFairQueue.super.takeAsync();
pollFuture.addListener(new FutureListener<V>() {
@Override
public void operationComplete(Future<V> future) throws Exception {
if (!future.isSuccess()) {
promise.tryFailure(future.cause());
return;
}
promise.trySuccess(future.getNow());
}
});
} else {
final RFuture<RedissonLockEntry> subscribeFuture = subscribe();
final AtomicReference<Timeout> futureRef = new AtomicReference<Timeout>();
subscribeFuture.addListener(new FutureListener<RedissonLockEntry>() {
@Override
public void operationComplete(Future<RedissonLockEntry> future) throws Exception {
if (!future.isSuccess()) {
promise.tryFailure(future.cause());
return;
}
if (futureRef.get() != null) {
futureRef.get().cancel();
}
tryTakeAsync(subscribeFuture, promise);
}
});
}
}
});
return promise;
}
@Override
public V poll() {
Long currentTimeout = tryAcquire();
if (currentTimeout == null) {
return super.poll();
}
return null;
}
@Override
public RFuture<V> pollAsync() {
final RPromise<V> promise = newPromise();
RFuture<Long> tryAcquireFuture = tryAcquireAsync();
tryAcquireFuture.addListener(new FutureListener<Long>() {
@Override
public void operationComplete(Future<Long> future) throws Exception {
if (!future.isSuccess()) {
promise.tryFailure(future.cause());
return;
}
final Long currentTimeout = future.getNow();
if (currentTimeout == null) {
final RFuture<V> pollFuture = RedissonBlockingFairQueue.super.pollAsync();
pollFuture.addListener(new FutureListener<V>() {
@Override
public void operationComplete(Future<V> future) throws Exception {
if (!future.isSuccess()) {
promise.tryFailure(future.cause());
return;
}
promise.trySuccess(future.getNow());
}
});
} else {
promise.trySuccess(null);
}
}
});
return promise;
}
@Override
public V poll(long timeout, TimeUnit unit) throws InterruptedException {
long startTime = System.currentTimeMillis();
Long currentTimeout = tryAcquire();
if (currentTimeout == null) {
long spentTime = System.currentTimeMillis() - startTime;
long remainTime = unit.toMillis(timeout) - spentTime;
if (remainTime > 0) {
return super.poll(remainTime, TimeUnit.MILLISECONDS);
}
return null;
}
RFuture<RedissonLockEntry> future = subscribe();
long spentTime = System.currentTimeMillis() - startTime;
long remainTime = unit.toMillis(timeout) - spentTime;
if (!future.awaitUninterruptibly(remainTime, TimeUnit.MILLISECONDS)) {
return null;
}
try {
while (true) {
currentTimeout = tryAcquire();
if (currentTimeout == null) {
spentTime = System.currentTimeMillis() - startTime;
remainTime = unit.toMillis(timeout) - spentTime;
if (remainTime > 0) {
return super.poll(remainTime, TimeUnit.MILLISECONDS);
}
return null;
}
spentTime = System.currentTimeMillis() - startTime;
remainTime = unit.toMillis(timeout) - spentTime;
remainTime = Math.min(remainTime, currentTimeout);
if (remainTime <= 0 || !getEntry().getLatch().tryAcquire(remainTime, TimeUnit.MILLISECONDS)) {
return null;
}
}
} finally {
unsubscribe(future);
}
}
@Override
public RFuture<V> pollAsync(final long timeout, final TimeUnit unit) {
final long startTime = System.currentTimeMillis();
final RPromise<V> promise = newPromise();
RFuture<Long> tryAcquireFuture = tryAcquireAsync();
tryAcquireFuture.addListener(new FutureListener<Long>() {
@Override
public void operationComplete(Future<Long> future) throws Exception {
if (!future.isSuccess()) {
promise.tryFailure(future.cause());
return;
}
Long currentTimeout = future.getNow();
if (currentTimeout == null) {
long spentTime = System.currentTimeMillis() - startTime;
long remainTime = unit.toMillis(timeout) - spentTime;
if (remainTime > 0) {
final RFuture<V> pollFuture = RedissonBlockingFairQueue.super.pollAsync(remainTime, TimeUnit.MILLISECONDS);
pollFuture.addListener(new FutureListener<V>() {
@Override
public void operationComplete(Future<V> future) throws Exception {
if (!future.isSuccess()) {
promise.tryFailure(future.cause());
return;
}
promise.trySuccess(future.getNow());
}
});
} else {
promise.trySuccess(null);
}
} else {
long spentTime = System.currentTimeMillis() - startTime;
long remainTime = unit.toMillis(timeout) - spentTime;
remainTime = Math.min(remainTime, currentTimeout);
if (remainTime <= 0) {
promise.trySuccess(null);
return;
}
final RFuture<RedissonLockEntry> subscribeFuture = subscribe();
final AtomicReference<Timeout> futureRef = new AtomicReference<Timeout>();
subscribeFuture.addListener(new FutureListener<RedissonLockEntry>() {
@Override
public void operationComplete(Future<RedissonLockEntry> future) throws Exception {
if (!future.isSuccess()) {
promise.tryFailure(future.cause());
return;
}
if (futureRef.get() != null) {
futureRef.get().cancel();
}
tryPollAsync(startTime, timeout, unit, subscribeFuture, promise);
}
});
if (!subscribeFuture.isDone()) {
Timeout scheduledFuture = commandExecutor.getConnectionManager().newTimeout(new TimerTask() {
@Override
public void run(Timeout timeout) throws Exception {
if (!subscribeFuture.isDone()) {
subscribeFuture.cancel(false);
promise.trySuccess(null);
}
}
}, remainTime, TimeUnit.MILLISECONDS);
futureRef.set(scheduledFuture);
}
}
}
});
return promise;
}
private void tryTakeAsync(final RFuture<RedissonLockEntry> subscribeFuture, final RPromise<V> promise) {
if (promise.isDone()) {
unsubscribe(subscribeFuture);
return;
}
RFuture<Long> tryAcquireFuture = tryAcquireAsync();
tryAcquireFuture.addListener(new FutureListener<Long>() {
@Override
public void operationComplete(Future<Long> future) throws Exception {
if (!future.isSuccess()) {
unsubscribe(subscribeFuture);
promise.tryFailure(future.cause());
return;
}
Long currentTimeout = future.getNow();
if (currentTimeout == null) {
final RFuture<V> pollFuture = RedissonBlockingFairQueue.super.takeAsync();
pollFuture.addListener(new FutureListener<V>() {
@Override
public void operationComplete(Future<V> future) throws Exception {
unsubscribe(subscribeFuture);
if (!future.isSuccess()) {
promise.tryFailure(future.cause());
return;
}
promise.trySuccess(future.getNow());
}
});
} else {
final RedissonLockEntry entry = getEntry();
synchronized (entry) {
if (entry.getLatch().tryAcquire()) {
tryTakeAsync(subscribeFuture, promise);
} else {
final AtomicBoolean executed = new AtomicBoolean();
final AtomicReference<Timeout> futureRef = new AtomicReference<Timeout>();
final Runnable listener = new Runnable() {
@Override
public void run() {
executed.set(true);
if (futureRef.get() != null) {
futureRef.get().cancel();
}
tryTakeAsync(subscribeFuture, promise);
}
};
entry.addListener(listener);
if (!executed.get()) {
Timeout scheduledFuture = commandExecutor.getConnectionManager().newTimeout(new TimerTask() {
@Override
public void run(Timeout t) throws Exception {
synchronized (entry) {
if (entry.removeListener(listener)) {
tryTakeAsync(subscribeFuture, promise);
}
}
}
}, currentTimeout, TimeUnit.MILLISECONDS);
futureRef.set(scheduledFuture);
}
}
}
}
};
});
}
private void tryPollAsync(final long startTime, final long timeout, final TimeUnit unit,
final RFuture<RedissonLockEntry> subscribeFuture, final RPromise<V> promise) {
if (promise.isDone()) {
unsubscribe(subscribeFuture);
return;
}
long spentTime = System.currentTimeMillis() - startTime;
long remainTime = unit.toMillis(timeout) - spentTime;
if (remainTime <= 0) {
unsubscribe(subscribeFuture);
promise.trySuccess(null);
return;
}
RFuture<Long> tryAcquireFuture = tryAcquireAsync();
tryAcquireFuture.addListener(new FutureListener<Long>() {
@Override
public void operationComplete(Future<Long> future) throws Exception {
if (!future.isSuccess()) {
unsubscribe(subscribeFuture);
promise.tryFailure(future.cause());
return;
}
Long currentTimeout = future.getNow();
if (currentTimeout == null) {
long spentTime = System.currentTimeMillis() - startTime;
long remainTime = unit.toMillis(timeout) - spentTime;
if (remainTime > 0) {
final RFuture<V> pollFuture = RedissonBlockingFairQueue.super.pollAsync(remainTime, TimeUnit.MILLISECONDS);
pollFuture.addListener(new FutureListener<V>() {
@Override
public void operationComplete(Future<V> future) throws Exception {
unsubscribe(subscribeFuture);
if (!future.isSuccess()) {
promise.tryFailure(future.cause());
return;
}
promise.trySuccess(future.getNow());
}
});
} else {
unsubscribe(subscribeFuture);
promise.trySuccess(null);
}
} else {
final RedissonLockEntry entry = getEntry();
synchronized (entry) {
if (entry.getLatch().tryAcquire()) {
tryPollAsync(startTime, timeout, unit, subscribeFuture, promise);
} else {
final AtomicBoolean executed = new AtomicBoolean();
final AtomicReference<Timeout> futureRef = new AtomicReference<Timeout>();
final Runnable listener = new Runnable() {
@Override
public void run() {
executed.set(true);
if (futureRef.get() != null) {
futureRef.get().cancel();
}
tryPollAsync(startTime, timeout, unit, subscribeFuture, promise);
}
};
entry.addListener(listener);
if (!executed.get()) {
long spentTime = System.currentTimeMillis() - startTime;
long remainTime = unit.toMillis(timeout) - spentTime;
Timeout scheduledFuture = commandExecutor.getConnectionManager().newTimeout(new TimerTask() {
@Override
public void run(Timeout t) throws Exception {
synchronized (entry) {
if (entry.removeListener(listener)) {
tryPollAsync(startTime, timeout, unit, subscribeFuture, promise);
}
}
}
}, remainTime, TimeUnit.MILLISECONDS);
futureRef.set(scheduledFuture);
}
}
}
}
};
});
}
@Override
public V pollLastAndOfferFirstTo(String queueName, long timeout, TimeUnit unit) throws InterruptedException {
long startTime = System.currentTimeMillis();
Long currentTimeout = tryAcquire();
if (currentTimeout == null) {
long spentTime = System.currentTimeMillis() - startTime;
long remainTime = unit.toMillis(timeout) - spentTime;
if (remainTime > 0) {
return super.pollLastAndOfferFirstTo(queueName, remainTime, TimeUnit.MILLISECONDS);
}
return null;
}
RFuture<RedissonLockEntry> future = subscribe();
long spentTime = System.currentTimeMillis() - startTime;
long remainTime = unit.toMillis(timeout) - spentTime;
if (!future.awaitUninterruptibly(remainTime, TimeUnit.MILLISECONDS)) {
return null;
}
try {
while (true) {
currentTimeout = tryAcquire();
if (currentTimeout == null) {
spentTime = System.currentTimeMillis() - startTime;
remainTime = unit.toMillis(timeout) - spentTime;
if (remainTime > 0) {
return super.pollLastAndOfferFirstTo(queueName, remainTime, TimeUnit.MILLISECONDS);
}
return null;
}
spentTime = System.currentTimeMillis() - startTime;
remainTime = unit.toMillis(timeout) - spentTime;
remainTime = Math.min(remainTime, currentTimeout);
if (remainTime <= 0 || !getEntry().getLatch().tryAcquire(remainTime, TimeUnit.MILLISECONDS)) {
return null;
}
}
} finally {
unsubscribe(future);
}
}
@Override
public RFuture<V> pollLastAndOfferFirstToAsync(final String queueName, final long timeout, final TimeUnit unit) {
final long startTime = System.currentTimeMillis();
final RPromise<V> promise = newPromise();
RFuture<Long> tryAcquireFuture = tryAcquireAsync();
tryAcquireFuture.addListener(new FutureListener<Long>() {
@Override
public void operationComplete(Future<Long> future) throws Exception {
if (!future.isSuccess()) {
promise.tryFailure(future.cause());
return;
}
Long currentTimeout = future.getNow();
if (currentTimeout == null) {
long spentTime = System.currentTimeMillis() - startTime;
long remainTime = unit.toMillis(timeout) - spentTime;
if (remainTime > 0) {
final RFuture<V> pollFuture = RedissonBlockingFairQueue.super.pollLastAndOfferFirstToAsync(queueName, remainTime, TimeUnit.MILLISECONDS);
pollFuture.addListener(new FutureListener<V>() {
@Override
public void operationComplete(Future<V> future) throws Exception {
if (!future.isSuccess()) {
promise.tryFailure(future.cause());
return;
}
promise.trySuccess(future.getNow());
}
});
} else {
promise.trySuccess(null);
}
} else {
long spentTime = System.currentTimeMillis() - startTime;
long remainTime = unit.toMillis(timeout) - spentTime;
remainTime = Math.min(remainTime, currentTimeout);
if (remainTime <= 0) {
promise.trySuccess(null);
return;
}
final RFuture<RedissonLockEntry> subscribeFuture = subscribe();
final AtomicReference<Timeout> futureRef = new AtomicReference<Timeout>();
subscribeFuture.addListener(new FutureListener<RedissonLockEntry>() {
@Override
public void operationComplete(Future<RedissonLockEntry> future) throws Exception {
if (!future.isSuccess()) {
promise.tryFailure(future.cause());
return;
}
if (futureRef.get() != null) {
futureRef.get().cancel();
}
tryPollLastAndOfferFirstToAsync(startTime, timeout, unit, subscribeFuture, promise, queueName);
}
});
if (!subscribeFuture.isDone()) {
Timeout scheduledFuture = commandExecutor.getConnectionManager().newTimeout(new TimerTask() {
@Override
public void run(Timeout timeout) throws Exception {
if (!subscribeFuture.isDone()) {
subscribeFuture.cancel(false);
promise.trySuccess(null);
}
}
}, remainTime, TimeUnit.MILLISECONDS);
futureRef.set(scheduledFuture);
}
}
}
});
return promise;
}
private void tryPollLastAndOfferFirstToAsync(final long startTime, final long timeout, final TimeUnit unit,
final RFuture<RedissonLockEntry> subscribeFuture, final RPromise<V> promise, final String queueName) {
if (promise.isDone()) {
unsubscribe(subscribeFuture);
return;
}
long spentTime = System.currentTimeMillis() - startTime;
long remainTime = unit.toMillis(timeout) - spentTime;
if (remainTime <= 0) {
unsubscribe(subscribeFuture);
promise.trySuccess(null);
return;
}
RFuture<Long> tryAcquireFuture = tryAcquireAsync();
tryAcquireFuture.addListener(new FutureListener<Long>() {
@Override
public void operationComplete(Future<Long> future) throws Exception {
if (!future.isSuccess()) {
unsubscribe(subscribeFuture);
promise.tryFailure(future.cause());
return;
}
Long currentTimeout = future.getNow();
if (currentTimeout == null) {
long spentTime = System.currentTimeMillis() - startTime;
long remainTime = unit.toMillis(timeout) - spentTime;
if (remainTime > 0) {
final RFuture<V> pollFuture = RedissonBlockingFairQueue.super.pollLastAndOfferFirstToAsync(queueName, remainTime, TimeUnit.MILLISECONDS);
pollFuture.addListener(new FutureListener<V>() {
@Override
public void operationComplete(Future<V> future) throws Exception {
unsubscribe(subscribeFuture);
if (!future.isSuccess()) {
promise.tryFailure(future.cause());
return;
}
promise.trySuccess(future.getNow());
}
});
} else {
unsubscribe(subscribeFuture);
promise.trySuccess(null);
}
} else {
final RedissonLockEntry entry = getEntry();
synchronized (entry) {
if (entry.getLatch().tryAcquire()) {
tryPollAsync(startTime, timeout, unit, subscribeFuture, promise);
} else {
final AtomicBoolean executed = new AtomicBoolean();
final AtomicReference<Timeout> futureRef = new AtomicReference<Timeout>();
final Runnable listener = new Runnable() {
@Override
public void run() {
executed.set(true);
if (futureRef.get() != null) {
futureRef.get().cancel();
}
tryPollLastAndOfferFirstToAsync(startTime, timeout, unit, subscribeFuture, promise, queueName);
}
};
entry.addListener(listener);
if (!executed.get()) {
long spentTime = System.currentTimeMillis() - startTime;
long remainTime = unit.toMillis(timeout) - spentTime;
Timeout scheduledFuture = commandExecutor.getConnectionManager().newTimeout(new TimerTask() {
@Override
public void run(Timeout t) throws Exception {
synchronized (entry) {
if (entry.removeListener(listener)) {
tryPollLastAndOfferFirstToAsync(startTime, timeout, unit, subscribeFuture, promise, queueName);
}
}
}
}, remainTime, TimeUnit.MILLISECONDS);
futureRef.set(scheduledFuture);
}
}
}
}
};
});
}
}

@ -36,6 +36,7 @@ import org.redisson.client.RedisException;
import org.redisson.client.codec.ScanCodec;
import org.redisson.client.codec.StringCodec;
import org.redisson.client.protocol.RedisCommands;
import org.redisson.client.protocol.RedisStrictCommand;
import org.redisson.client.protocol.decoder.ListScanResult;
import org.redisson.client.protocol.decoder.ScanObjectEntry;
import org.redisson.command.CommandAsyncExecutor;
@ -277,10 +278,24 @@ public class RedissonKeys implements RKeys {
return deleteAsync(keys.toArray(new String[keys.size()]));
}
@Override
public long unlink(String ... keys) {
return commandExecutor.get(deleteAsync(keys));
}
@Override
public RFuture<Long> unlinkAsync(String ... keys) {
return executeAsync(RedisCommands.UNLINK, keys);
}
@Override
public RFuture<Long> deleteAsync(String ... keys) {
return executeAsync(RedisCommands.DEL, keys);
}
private RFuture<Long> executeAsync(RedisStrictCommand<Long> command, String ... keys) {
if (!commandExecutor.getConnectionManager().isClusterMode()) {
return commandExecutor.writeAsync(null, RedisCommands.DEL, keys);
return commandExecutor.writeAsync(null, command, keys);
}
Map<MasterSlaveEntry, List<String>> range2key = new HashMap<MasterSlaveEntry, List<String>>();
@ -320,7 +335,7 @@ public class RedissonKeys implements RKeys {
// executes in batch due to CROSSLOT error
CommandBatchService executorService = new CommandBatchService(commandExecutor.getConnectionManager());
for (String key : entry.getValue()) {
executorService.writeAsync(entry.getKey(), null, RedisCommands.DEL, key);
executorService.writeAsync(entry.getKey(), null, command, key);
}
RFuture<List<?>> future = executorService.executeAsync();
@ -351,6 +366,27 @@ public class RedissonKeys implements RKeys {
});
}
@Override
public void flushdbParallel() {
commandExecutor.get(flushdbParallelAsync());
}
@Override
public RFuture<Void> flushdbParallelAsync() {
return commandExecutor.writeAllAsync(RedisCommands.FLUSHDB_ASYNC);
}
@Override
public void flushallParallel() {
commandExecutor.get(flushallParallelAsync());
}
@Override
public RFuture<Void> flushallParallelAsync() {
return commandExecutor.writeAllAsync(RedisCommands.FLUSHALL_ASYNC);
}
@Override
public void flushdb() {
commandExecutor.get(flushdbAsync());

@ -30,7 +30,7 @@ import org.redisson.api.RLock;
import org.redisson.client.codec.LongCodec;
import org.redisson.client.protocol.RedisCommands;
import org.redisson.client.protocol.RedisStrictCommand;
import org.redisson.command.CommandExecutor;
import org.redisson.command.CommandAsyncExecutor;
import org.redisson.misc.RPromise;
import org.redisson.pubsub.LockPubSub;
import org.slf4j.Logger;
@ -63,9 +63,9 @@ public class RedissonLock extends RedissonExpirable implements RLock {
protected static final LockPubSub PUBSUB = new LockPubSub();
final CommandExecutor commandExecutor;
final CommandAsyncExecutor commandExecutor;
protected RedissonLock(CommandExecutor commandExecutor, String name, UUID id) {
public RedissonLock(CommandAsyncExecutor commandExecutor, String name, UUID id) {
super(commandExecutor, name);
this.commandExecutor = commandExecutor;
this.id = id;
@ -417,12 +417,14 @@ public class RedissonLock extends RedissonExpirable implements RLock {
@Override
public boolean isHeldByCurrentThread() {
return commandExecutor.write(getName(), LongCodec.INSTANCE, RedisCommands.HEXISTS, getName(), getLockName(Thread.currentThread().getId()));
RFuture<Boolean> future = commandExecutor.writeAsync(getName(), LongCodec.INSTANCE, RedisCommands.HEXISTS, getName(), getLockName(Thread.currentThread().getId()));
return get(future);
}
@Override
public int getHoldCount() {
Long res = commandExecutor.write(getName(), LongCodec.INSTANCE, RedisCommands.HGET, getName(), getLockName(Thread.currentThread().getId()));
RFuture<Long> future = commandExecutor.writeAsync(getName(), LongCodec.INSTANCE, RedisCommands.HGET, getName(), getLockName(Thread.currentThread().getId()));
Long res = get(future);
if (res == null) {
return 0;
}

@ -136,6 +136,16 @@ public abstract class RedissonObject implements RObject {
public RFuture<Boolean> deleteAsync() {
return commandExecutor.writeAsync(getName(), RedisCommands.DEL_BOOL, getName());
}
@Override
public boolean unlink() {
return get(unlinkAsync());
}
@Override
public RFuture<Boolean> unlinkAsync() {
return commandExecutor.writeAsync(getName(), RedisCommands.UNLINK_BOOL, getName());
}
@Override
public boolean touch() {

@ -22,11 +22,14 @@ import org.redisson.api.RFuture;
import org.redisson.api.RPriorityDeque;
import org.redisson.client.codec.Codec;
import org.redisson.client.protocol.RedisCommand;
import org.redisson.client.protocol.RedisCommand.ValueType;
import org.redisson.client.protocol.RedisCommands;
import org.redisson.client.protocol.convertor.VoidReplayConvertor;
import org.redisson.client.protocol.decoder.ListFirstObjectDecoder;
import org.redisson.command.CommandExecutor;
import org.redisson.misc.RPromise;
import org.redisson.misc.RedissonPromise;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.FutureListener;
/**
* Distributed and concurrent implementation of {@link java.util.Queue}
@ -37,7 +40,6 @@ import org.redisson.command.CommandExecutor;
*/
public class RedissonPriorityDeque<V> extends RedissonPriorityQueue<V> implements RPriorityDeque<V> {
private static final RedisCommand<Void> RPUSH_VOID = new RedisCommand<Void>("RPUSH", new VoidReplayConvertor(), 2, ValueType.OBJECTS);
private static final RedisCommand<Object> LRANGE_SINGLE = new RedisCommand<Object>("LRANGE", new ListFirstObjectDecoder());
@ -51,25 +53,14 @@ public class RedissonPriorityDeque<V> extends RedissonPriorityQueue<V> implement
@Override
public void addFirst(V e) {
get(addFirstAsync(e));
}
// @Override
public RFuture<Void> addFirstAsync(V e) {
return commandExecutor.writeAsync(getName(), codec, RedisCommands.LPUSH_VOID, getName(), e);
throw new UnsupportedOperationException();
}
@Override
public void addLast(V e) {
get(addLastAsync(e));
throw new UnsupportedOperationException();
}
// @Override
public RFuture<Void> addLastAsync(V e) {
return commandExecutor.writeAsync(getName(), codec, RPUSH_VOID, getName(), e);
}
@Override
public Iterator<V> descendingIterator() {
return new Iterator<V>() {
@ -122,22 +113,12 @@ public class RedissonPriorityDeque<V> extends RedissonPriorityQueue<V> implement
@Override
public boolean offerFirst(V e) {
return get(offerFirstAsync(e));
}
// @Override
public RFuture<Boolean> offerFirstAsync(V e) {
return commandExecutor.writeAsync(getName(), codec, RedisCommands.LPUSH_BOOLEAN, getName(), e);
}
// @Override
public RFuture<Boolean> offerLastAsync(V e) {
return offerAsync(e);
throw new UnsupportedOperationException();
}
@Override
public boolean offerLast(V e) {
return get(offerLastAsync(e));
throw new UnsupportedOperationException();
}
// @Override
@ -150,32 +131,55 @@ public class RedissonPriorityDeque<V> extends RedissonPriorityQueue<V> implement
return get(peekFirstAsync());
}
// @Override
public RFuture<V> peekLastAsync() {
return getLastAsync();
}
@Override
public V peekLast() {
return get(getLastAsync());
}
// @Override
public RFuture<V> pollFirstAsync() {
return pollAsync();
}
@Override
public V pollFirst() {
return poll();
}
// @Override
public RFuture<V> pollLastAsync() {
return commandExecutor.writeAsync(getName(), codec, RedisCommands.RPOP, getName());
final long threadId = Thread.currentThread().getId();
final RPromise<V> result = new RedissonPromise<V>();
lock.lockAsync(threadId).addListener(new FutureListener<Void>() {
@Override
public void operationComplete(Future<Void> future) throws Exception {
if (!future.isSuccess()) {
result.tryFailure(future.cause());
return;
}
RFuture<V> f = commandExecutor.writeAsync(getName(), codec, RedisCommands.RPOP, getName());
f.addListener(new FutureListener<V>() {
@Override
public void operationComplete(Future<V> future) throws Exception {
if (!future.isSuccess()) {
result.tryFailure(future.cause());
return;
}
final V value = future.getNow();
lock.unlockAsync(threadId).addListener(new FutureListener<Void>() {
@Override
public void operationComplete(Future<Void> future) throws Exception {
if (!future.isSuccess()) {
result.tryFailure(future.cause());
return;
}
result.trySuccess(value);
}
});
}
});
}
});
return result;
}
@Override
public V pollLast() {
return get(pollLastAsync());
@ -191,14 +195,9 @@ public class RedissonPriorityDeque<V> extends RedissonPriorityQueue<V> implement
return removeFirst();
}
// @Override
public RFuture<Void> pushAsync(V e) {
return addFirstAsync(e);
}
@Override
public void push(V e) {
addFirst(e);
throw new UnsupportedOperationException();
}
// @Override
@ -218,7 +217,7 @@ public class RedissonPriorityDeque<V> extends RedissonPriorityQueue<V> implement
// @Override
public RFuture<V> removeLastAsync() {
return commandExecutor.writeAsync(getName(), codec, RedisCommands.RPOP, getName());
return pollLastAsync();
}
@Override

@ -35,6 +35,11 @@ import org.redisson.client.codec.Codec;
import org.redisson.client.codec.StringCodec;
import org.redisson.client.protocol.RedisCommands;
import org.redisson.command.CommandExecutor;
import org.redisson.misc.RPromise;
import org.redisson.misc.RedissonPromise;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.FutureListener;
/**
*
@ -89,7 +94,7 @@ public class RedissonPriorityQueue<V> extends RedissonList<V> implements RPriori
CommandExecutor commandExecutor;
private RLock lock;
RLock lock;
private RBucket<String> comparatorHolder;
protected RedissonPriorityQueue(CommandExecutor commandExecutor, String name, Redisson redisson) {
@ -298,7 +303,42 @@ public class RedissonPriorityQueue<V> extends RedissonList<V> implements RPriori
// @Override
public RFuture<V> pollAsync() {
return commandExecutor.writeAsync(getName(), codec, RedisCommands.LPOP, getName());
final long threadId = Thread.currentThread().getId();
final RPromise<V> result = new RedissonPromise<V>();
lock.lockAsync(threadId).addListener(new FutureListener<Void>() {
@Override
public void operationComplete(Future<Void> future) throws Exception {
if (!future.isSuccess()) {
result.tryFailure(future.cause());
return;
}
RFuture<V> f = commandExecutor.writeAsync(getName(), codec, RedisCommands.LPOP, getName());
f.addListener(new FutureListener<V>() {
@Override
public void operationComplete(Future<V> future) throws Exception {
if (!future.isSuccess()) {
result.tryFailure(future.cause());
return;
}
final V value = future.getNow();
lock.unlockAsync(threadId).addListener(new FutureListener<Void>() {
@Override
public void operationComplete(Future<Void> future) throws Exception {
if (!future.isSuccess()) {
result.tryFailure(future.cause());
return;
}
result.trySuccess(value);
}
});
}
});
}
});
return result;
}
public V getFirst() {

@ -35,10 +35,12 @@ import org.redisson.api.RHyperLogLogReactive;
import org.redisson.api.RKeysReactive;
import org.redisson.api.RLexSortedSetReactive;
import org.redisson.api.RListReactive;
import org.redisson.api.RLockReactive;
import org.redisson.api.RMapCacheReactive;
import org.redisson.api.RMapReactive;
import org.redisson.api.RPatternTopicReactive;
import org.redisson.api.RQueueReactive;
import org.redisson.api.RReadWriteLockReactive;
import org.redisson.api.RScoredSortedSetReactive;
import org.redisson.api.RScriptReactive;
import org.redisson.api.RSetCacheReactive;
@ -63,10 +65,12 @@ import org.redisson.reactive.RedissonHyperLogLogReactive;
import org.redisson.reactive.RedissonKeysReactive;
import org.redisson.reactive.RedissonLexSortedSetReactive;
import org.redisson.reactive.RedissonListReactive;
import org.redisson.reactive.RedissonLockReactive;
import org.redisson.reactive.RedissonMapCacheReactive;
import org.redisson.reactive.RedissonMapReactive;
import org.redisson.reactive.RedissonPatternTopicReactive;
import org.redisson.reactive.RedissonQueueReactive;
import org.redisson.reactive.RedissonReadWriteLockReactive;
import org.redisson.reactive.RedissonScoredSortedSetReactive;
import org.redisson.reactive.RedissonScriptReactive;
import org.redisson.reactive.RedissonSetCacheReactive;
@ -99,6 +103,15 @@ public class RedissonReactive implements RedissonReactiveClient {
codecProvider = config.getCodecProvider();
}
@Override
public RReadWriteLockReactive getReadWriteLock(String name) {
return new RedissonReadWriteLockReactive(commandExecutor, name, id);
}
@Override
public RLockReactive getLock(String name) {
return new RedissonLockReactive(commandExecutor, name, id);
}
@Override
public <K, V> RMapCacheReactive<K, V> getMapCache(String name, Codec codec) {

@ -26,7 +26,7 @@ import org.redisson.client.codec.LongCodec;
import org.redisson.client.codec.StringCodec;
import org.redisson.client.protocol.RedisCommands;
import org.redisson.client.protocol.RedisStrictCommand;
import org.redisson.command.CommandExecutor;
import org.redisson.command.CommandAsyncExecutor;
import org.redisson.pubsub.LockPubSub;
import io.netty.util.concurrent.Future;
@ -40,16 +40,13 @@ import io.netty.util.concurrent.FutureListener;
*/
public class RedissonReadLock extends RedissonLock implements RLock {
private final CommandExecutor commandExecutor;
protected RedissonReadLock(CommandExecutor commandExecutor, String name, UUID id) {
public RedissonReadLock(CommandAsyncExecutor commandExecutor, String name, UUID id) {
super(commandExecutor, name, id);
this.commandExecutor = commandExecutor;
}
@Override
String getChannelName() {
return "redisson_rwlock__{" + getName() + "}";
return prefixName("redisson_rwlock", getName());
}
String getWriteLockName(long threadId) {
@ -159,7 +156,8 @@ public class RedissonReadLock extends RedissonLock implements RLock {
@Override
public boolean isLocked() {
String res = commandExecutor.write(getName(), StringCodec.INSTANCE, RedisCommands.HGET, getName(), "mode");
RFuture<String> future = commandExecutor.writeAsync(getName(), StringCodec.INSTANCE, RedisCommands.HGET, getName(), "mode");
String res = get(future);
return "read".equals(res);
}

@ -20,7 +20,7 @@ import java.util.concurrent.locks.Lock;
import org.redisson.api.RLock;
import org.redisson.api.RReadWriteLock;
import org.redisson.command.CommandExecutor;
import org.redisson.command.CommandAsyncExecutor;
/**
* A {@code ReadWriteLock} maintains a pair of associated {@link
@ -38,11 +38,9 @@ import org.redisson.command.CommandExecutor;
public class RedissonReadWriteLock extends RedissonExpirable implements RReadWriteLock {
private final UUID id;
private final CommandExecutor commandExecutor;
RedissonReadWriteLock(CommandExecutor commandExecutor, String name, UUID id) {
public RedissonReadWriteLock(CommandAsyncExecutor commandExecutor, String name, UUID id) {
super(commandExecutor, name);
this.commandExecutor = commandExecutor;
this.id = id;
}

@ -495,22 +495,6 @@ public class RedissonSemaphore extends RedissonExpirable implements RSemaphore {
return res.intValue();
}
@Override
public void setPermits(int permits) {
get(setPermitsAsync(permits));
}
@Override
public RFuture<Void> setPermitsAsync(int permits) {
return commandExecutor.evalWriteAsync(getName(), LongCodec.INSTANCE, RedisCommands.EVAL_VOID,
"local value = redis.call('get', KEYS[1]); " +
"if (value == false or value == 0) then "
+ "redis.call('set', KEYS[1], ARGV[1]); "
+ "redis.call('publish', KEYS[2], ARGV[1]); "
+ "end;",
Arrays.<Object>asList(getName(), getChannelName()), permits);
}
@Override
public boolean trySetPermits(int permits) {
return get(trySetPermitsAsync(permits));

@ -26,7 +26,7 @@ import org.redisson.client.codec.LongCodec;
import org.redisson.client.codec.StringCodec;
import org.redisson.client.protocol.RedisCommands;
import org.redisson.client.protocol.RedisStrictCommand;
import org.redisson.command.CommandExecutor;
import org.redisson.command.CommandAsyncExecutor;
import org.redisson.pubsub.LockPubSub;
import io.netty.util.concurrent.Future;
@ -40,16 +40,13 @@ import io.netty.util.concurrent.FutureListener;
*/
public class RedissonWriteLock extends RedissonLock implements RLock {
private final CommandExecutor commandExecutor;
protected RedissonWriteLock(CommandExecutor commandExecutor, String name, UUID id) {
protected RedissonWriteLock(CommandAsyncExecutor commandExecutor, String name, UUID id) {
super(commandExecutor, name, id);
this.commandExecutor = commandExecutor;
}
@Override
String getChannelName() {
return "redisson_rwlock__{" + getName() + "}";
return prefixName("redisson_rwlock", getName());
}
@Override
@ -144,7 +141,8 @@ public class RedissonWriteLock extends RedissonLock implements RLock {
@Override
public boolean isLocked() {
String res = commandExecutor.write(getName(), StringCodec.INSTANCE, RedisCommands.HGET, getName(), "mode");
RFuture<String> future = commandExecutor.writeAsync(getName(), StringCodec.INSTANCE, RedisCommands.HGET, getName(), "mode");
String res = get(future);
return "write".equals(res);
}

@ -1,28 +0,0 @@
/**
* 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;
/**
* Blocking queue with fair polling and
* guarantees access order for poll and take methods.
*
* @author Nikita Koksharov
*
* @param <V> value
*/
public interface RBlockingFairQueue<V> extends RBlockingQueue<V>, RDestroyable {
}

@ -230,6 +230,17 @@ public interface RKeys extends RKeysAsync {
*/
long delete(String ... keys);
/**
* Delete multiple objects by name.
* Actual removal will happen later asynchronously.
* <p>
* Requires Redis 4.0+
*
* @param keys
* @return number of removed keys
*/
long unlink(String ... keys);
/**
* Returns the number of keys in the currently-selected database
*
@ -242,9 +253,27 @@ public interface RKeys extends RKeysAsync {
*/
void flushdb();
/**
* Delete all keys of currently selected database
* in background without blocking server.
* <p>
* Requires Redis 4.0+
*
*/
void flushdbParallel();
/**
* Delete all keys of all existing databases
*/
void flushall();
/**
* Delete all keys of all existing databases
* in background without blocking server.
* <p>
* Requires Redis 4.0+
*
*/
void flushallParallel();
}

@ -188,6 +188,17 @@ public interface RKeysAsync {
*/
RFuture<Long> deleteAsync(String ... keys);
/**
* Delete multiple objects by name.
* Actual removal will happen later asynchronously.
* <p>
* Requires Redis 4.0+
*
* @param keys
* @return number of removed keys
*/
RFuture<Long> unlinkAsync(String ... keys);
/**
* Returns the number of keys in the currently-selected database in async mode
*
@ -207,4 +218,24 @@ public interface RKeysAsync {
*/
RFuture<Void> flushallAsync();
/**
* Delete all keys of currently selected database
* in background without blocking server.
* <p>
* Requires Redis 4.0+
*
* @return void
*/
RFuture<Void> flushdbParallelAsync();
/**
* Delete all keys of all existing databases
* in background without blocking server.
* <p>
* Requires Redis 4.0+
*
* @return void
*/
RFuture<Void> flushallParallelAsync();
}

@ -0,0 +1,54 @@
/**
* 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;
import org.reactivestreams.Publisher;
/**
*
* @author Nikita Koksharov
*
*/
public interface RLockReactive extends RExpirableReactive {
Publisher<Boolean> forceUnlock();
Publisher<Void> unlock();
Publisher<Void> unlock(long threadId);
Publisher<Boolean> tryLock();
Publisher<Void> lock();
Publisher<Void> lock(long threadId);
Publisher<Void> lock(long leaseTime, TimeUnit unit);
Publisher<Void> lock(long leaseTime, TimeUnit unit, long threadId);
Publisher<Boolean> tryLock(long threadId);
Publisher<Boolean> tryLock(long waitTime, TimeUnit unit);
Publisher<Boolean> tryLock(long waitTime, long leaseTime, TimeUnit unit);
Publisher<Boolean> tryLock(long waitTime, long leaseTime, TimeUnit unit, long threadId);
}

@ -63,6 +63,16 @@ public interface RObject extends RObjectAsync {
*/
boolean delete();
/**
* Delete the objects.
* Actual removal will happen later asynchronously.
* <p>
* Requires Redis 4.0+
*
* @return <code>true</code> if it was exist and deleted else <code>false</code>
*/
boolean unlink();
/**
* Rename current object key to <code>newName</code>
*

@ -56,6 +56,16 @@ public interface RObjectAsync {
*/
RFuture<Boolean> deleteAsync();
/**
* Delete the objects.
* Actual removal will happen later asynchronously.
* <p>
* Requires Redis 4.0+
*
* @return <code>true</code> if it was exist and deleted else <code>false</code>
*/
RFuture<Boolean> unlinkAsync();
/**
* Rename current object key to <code>newName</code>
* in async mode

@ -0,0 +1,49 @@
/**
* 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.locks.Lock;
/**
* A {@code ReadWriteLock} maintains a pair of associated {@link
* Lock locks}, one for read-only operations and one for writing.
* The {@link #readLock read lock} may be held simultaneously by
* multiple reader threads, so long as there are no writers. The
* {@link #writeLock write lock} is exclusive.
*
* Works in non-fair mode. Therefore order of read and write
* locking is unspecified.
*
* @author Nikita Koksharov
*
*/
public interface RReadWriteLockReactive extends RExpirableReactive {
/**
* Returns the lock used for reading.
*
* @return the lock used for reading
*/
RLockReactive readLock();
/**
* Returns the lock used for writing.
*
* @return the lock used for writing
*/
RLockReactive writeLock();
}

@ -220,14 +220,6 @@ public interface RSemaphore extends RExpirable, RSemaphoreAsync {
*/
int drainPermits();
/**
* Use {@link #trySetPermits(int)}
*
* @param permits amount
*/
@Deprecated
void setPermits(int permits);
/**
* Sets number of permits.
*

@ -115,15 +115,6 @@ public interface RSemaphoreAsync extends RExpirableAsync {
*/
RFuture<Void> releaseAsync(int permits);
/**
* Use {@link #trySetPermitsAsync(int)}
*
* @param permits amount
* @return void
*/
@Deprecated
RFuture<Void> setPermitsAsync(int permits);
/**
* Sets number of permits.
*

@ -558,17 +558,6 @@ public interface RedissonClient {
*/
<M> RPatternTopic<M> getPatternTopic(String pattern, Codec codec);
/**
* Returns unbounded fair queue instance by name.
*
* @param <V> type of value
* @param name of queue
* @return queue
*/
<V> RBlockingFairQueue<V> getBlockingFairQueue(String name);
<V> RBlockingFairQueue<V> getBlockingFairQueue(String name, Codec codec);
/**
* Returns unbounded queue instance by name.
*

@ -30,6 +30,24 @@ import org.redisson.config.Config;
*/
public interface RedissonReactiveClient {
/**
* Returns readWriteLock instance by name.
*
* @param name - name of object
* @return Lock object
*/
RReadWriteLockReactive getReadWriteLock(String name);
/**
* Returns lock instance by name.
* <p>
* Implements a <b>non-fair</b> locking so doesn't guarantee an acquire order by threads.
*
* @param name - name of object
* @return Lock object
*/
RLockReactive getLock(String name);
/**
* Returns set-based cache instance by <code>name</code>.
* Supports value eviction with a given TTL value.

@ -245,6 +245,9 @@ public interface RedisCommands {
RedisStrictCommand<String> CLIENT_GETNAME = new RedisStrictCommand<String>("CLIENT", "GETNAME", new StringDataDecoder());
RedisStrictCommand<Void> FLUSHDB = new RedisStrictCommand<Void>("FLUSHDB", new VoidReplayConvertor());
RedisStrictCommand<Void> FLUSHALL = new RedisStrictCommand<Void>("FLUSHALL", new VoidReplayConvertor());
RedisStrictCommand<Void> FLUSHDB_ASYNC = new RedisStrictCommand<Void>("FLUSHDB", "ASYNC", new VoidReplayConvertor());
RedisStrictCommand<Void> FLUSHALL_ASYNC = new RedisStrictCommand<Void>("FLUSHALL", "ASYNC", new VoidReplayConvertor());
RedisStrictCommand<List<String>> KEYS = new RedisStrictCommand<List<String>>("KEYS", new StringListReplayDecoder());
RedisCommand<List<Object>> MGET = new RedisCommand<List<Object>>("MGET", new ObjectListReplayDecoder<Object>());
@ -272,6 +275,9 @@ public interface RedisCommands {
RedisStrictCommand<Boolean> DEL_BOOL = new RedisStrictCommand<Boolean>("DEL", new BooleanNullSafeReplayConvertor());
RedisStrictCommand<Boolean> DEL_OBJECTS = new RedisStrictCommand<Boolean>("DEL", new BooleanNullSafeReplayConvertor());
RedisStrictCommand<Void> DEL_VOID = new RedisStrictCommand<Void>("DEL", new VoidReplayConvertor());
RedisStrictCommand<Long> UNLINK = new RedisStrictCommand<Long>("UNLINK");
RedisStrictCommand<Boolean> UNLINK_BOOL = new RedisStrictCommand<Boolean>("UNLINK", new BooleanNullSafeReplayConvertor());
RedisCommand<Object> GET = new RedisCommand<Object>("GET");
RedisStrictCommand<Long> GET_LONG = new RedisStrictCommand<Long>("GET", new LongReplayConvertor());

@ -19,15 +19,11 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.Deque;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import org.reactivestreams.Publisher;
import org.reactivestreams.Subscription;
import org.redisson.RedissonReference;
import org.redisson.RedissonShutdownException;
import org.redisson.api.RFuture;
@ -51,7 +47,6 @@ import org.redisson.connection.NodeSource;
import org.redisson.connection.NodeSource.Redirect;
import org.redisson.misc.RPromise;
import org.redisson.misc.RedissonObjectFactory;
import org.redisson.reactive.NettyFuturePublisher;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
@ -60,10 +55,13 @@ import io.netty.util.TimerTask;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.FutureListener;
import io.netty.util.internal.PlatformDependent;
import reactor.fn.Supplier;
import reactor.rx.action.support.DefaultSubscriber;
public class CommandBatchService extends CommandReactiveService {
/**
*
* @author Nikita Koksharov
*
*/
public class CommandBatchService extends CommandAsyncService {
public static class Entry {
@ -93,7 +91,6 @@ public class CommandBatchService extends CommandReactiveService {
private final AtomicInteger index = new AtomicInteger();
private Queue<Publisher<?>> publishers = new ConcurrentLinkedQueue<Publisher<?>>();
private ConcurrentMap<MasterSlaveEntry, Entry> commands = PlatformDependent.newConcurrentHashMap();
private volatile boolean executed;
@ -102,13 +99,6 @@ public class CommandBatchService extends CommandReactiveService {
super(connectionManager);
}
@Override
public <R> Publisher<R> reactive(Supplier<RFuture<R>> supplier) {
NettyFuturePublisher<R> publisher = new NettyFuturePublisher<R>(supplier);
publishers.add(publisher);
return publisher;
}
@Override
protected <V, R> void async(boolean readOnlyMode, NodeSource nodeSource,
Codec codec, RedisCommand<V> command, Object[] params, RPromise<R> mainPromise, int attempt) {
@ -151,20 +141,11 @@ public class CommandBatchService extends CommandReactiveService {
return executeAsyncVoid(false, 0, 0, 0);
}
private RFuture<Void> executeAsyncVoid(boolean noResult, long responseTimeout, int retryAttempts, long retryInterval) {
protected RFuture<Void> executeAsyncVoid(boolean noResult, long responseTimeout, int retryAttempts, long retryInterval) {
if (executed) {
throw new IllegalStateException("Batch already executed!");
}
for (Publisher<?> publisher : publishers) {
publisher.subscribe(new DefaultSubscriber<Object>() {
@Override
public void onSubscribe(Subscription s) {
s.request(1);
}
});
}
if (commands.isEmpty()) {
return connectionManager.newSucceededFuture(null);
}
@ -214,15 +195,6 @@ public class CommandBatchService extends CommandReactiveService {
throw new IllegalStateException("Batch already executed!");
}
for (Publisher<?> publisher : publishers) {
publisher.subscribe(new DefaultSubscriber<Object>() {
@Override
public void onSubscribe(Subscription s) {
s.request(1);
}
});
}
if (commands.isEmpty()) {
return connectionManager.newSucceededFuture(null);
}
@ -267,7 +239,7 @@ public class CommandBatchService extends CommandReactiveService {
return promise;
}
private void execute(final Entry entry, final NodeSource source, final RPromise<Void> mainPromise, final AtomicInteger slots,
protected void execute(final Entry entry, final NodeSource source, final RPromise<Void> mainPromise, final AtomicInteger slots,
final int attempt, final boolean noResult, final long responseTimeout, final int retryAttempts, final long retryInterval) {
if (mainPromise.isCancelled()) {
return;

@ -0,0 +1,119 @@
/**
* 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.command;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import org.reactivestreams.Publisher;
import org.reactivestreams.Subscription;
import org.redisson.api.RFuture;
import org.redisson.api.RedissonReactiveClient;
import org.redisson.client.codec.Codec;
import org.redisson.client.protocol.RedisCommand;
import org.redisson.connection.ConnectionManager;
import org.redisson.connection.NodeSource;
import org.redisson.misc.RPromise;
import org.redisson.reactive.NettyFuturePublisher;
import reactor.fn.Supplier;
import reactor.rx.action.support.DefaultSubscriber;
/**
*
* @author Nikita Koksharov
*
*/
public class CommandReactiveBatchService extends CommandReactiveService {
private final CommandBatchService batchService;
private final Queue<Publisher<?>> publishers = new ConcurrentLinkedQueue<Publisher<?>>();
public CommandReactiveBatchService(ConnectionManager connectionManager) {
super(connectionManager);
batchService = new CommandBatchService(connectionManager);
}
@Override
public <R> Publisher<R> reactive(Supplier<RFuture<R>> supplier) {
NettyFuturePublisher<R> publisher = new NettyFuturePublisher<R>(supplier);
publishers.add(publisher);
return publisher;
}
@Override
protected <V, R> void async(boolean readOnlyMode, NodeSource nodeSource,
Codec codec, RedisCommand<V> command, Object[] params, RPromise<R> mainPromise, int attempt) {
batchService.async(readOnlyMode, nodeSource, codec, command, params, mainPromise, attempt);
}
public List<?> execute() {
return get(executeAsync(0, 0, 0));
}
public List<?> execute(long responseTimeout, int retryAttempts, long retryInterval) {
return get(executeAsync(responseTimeout, retryAttempts, retryInterval));
}
public RFuture<Void> executeAsyncVoid() {
return executeAsyncVoid(false, 0, 0, 0);
}
private RFuture<Void> executeAsyncVoid(boolean noResult, long responseTimeout, int retryAttempts, long retryInterval) {
for (Publisher<?> publisher : publishers) {
publisher.subscribe(new DefaultSubscriber<Object>() {
@Override
public void onSubscribe(Subscription s) {
s.request(1);
}
});
}
return batchService.executeAsyncVoid(noResult, responseTimeout, retryAttempts, retryInterval);
}
public void executeSkipResult(long timeout, int retryAttempts, long retryInterval) {
get(executeSkipResultAsync(timeout, retryAttempts, retryInterval));
}
public RFuture<Void> executeSkipResultAsync(long timeout, int retryAttempts, long retryInterval) {
return executeAsyncVoid(true, timeout, retryAttempts, retryInterval);
}
public RFuture<List<?>> executeAsync() {
return executeAsync(0, 0, 0);
}
public RFuture<List<?>> executeAsync(long responseTimeout, int retryAttempts, long retryInterval) {
for (Publisher<?> publisher : publishers) {
publisher.subscribe(new DefaultSubscriber<Object>() {
@Override
public void onSubscribe(Subscription s) {
s.request(1);
}
});
}
return batchService.executeAsync(responseTimeout, retryAttempts, retryInterval);
}
@Override
public CommandAsyncExecutor enableRedissonReferenceSupport(RedissonReactiveClient redissonReactive) {
batchService.enableRedissonReferenceSupport(redissonReactive);
return super.enableRedissonReferenceSupport(redissonReactive);
}
}

@ -38,8 +38,6 @@ public interface CommandReactiveExecutor extends CommandAsyncExecutor {
<R> Publisher<R> reactive(Supplier<RFuture<R>> supplier);
ConnectionManager getConnectionManager();
<T, R> Publisher<R> evalReadReactive(InetSocketAddress client, String key, Codec codec, RedisCommand<T> evalCommandType,
String script, List<Object> keys, Object ... params);

@ -39,7 +39,7 @@ import org.redisson.api.RSetReactive;
import org.redisson.api.RTopicReactive;
import org.redisson.api.RedissonReactiveClient;
import org.redisson.client.codec.Codec;
import org.redisson.command.CommandBatchService;
import org.redisson.command.CommandReactiveBatchService;
import org.redisson.connection.ConnectionManager;
import org.redisson.eviction.EvictionScheduler;
@ -53,11 +53,11 @@ import reactor.fn.Supplier;
public class RedissonBatchReactive implements RBatchReactive {
private final EvictionScheduler evictionScheduler;
private final CommandBatchService executorService;
private final CommandReactiveBatchService executorService;
public RedissonBatchReactive(EvictionScheduler evictionScheduler, ConnectionManager connectionManager) {
this.evictionScheduler = evictionScheduler;
this.executorService = new CommandBatchService(connectionManager);
this.executorService = new CommandReactiveBatchService(connectionManager);
}
@Override

@ -0,0 +1,169 @@
/**
* 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.reactive;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import org.reactivestreams.Publisher;
import org.redisson.RedissonLock;
import org.redisson.api.RFuture;
import org.redisson.api.RLockAsync;
import org.redisson.api.RLockReactive;
import org.redisson.command.CommandAsyncExecutor;
import org.redisson.command.CommandReactiveExecutor;
import reactor.fn.Supplier;
/**
*
* @author Nikita Koksharov
*
*/
public class RedissonLockReactive extends RedissonExpirableReactive implements RLockReactive {
private final RLockAsync instance;
public RedissonLockReactive(CommandReactiveExecutor connectionManager, String name, UUID id) {
super(connectionManager, name);
instance = createLock(connectionManager, name, id);
}
protected RLockAsync createLock(CommandAsyncExecutor connectionManager, String name, UUID id) {
return new RedissonLock(commandExecutor, name, id);
}
@Override
public Publisher<Boolean> forceUnlock() {
return reactive(new Supplier<RFuture<Boolean>>() {
@Override
public RFuture<Boolean> get() {
return instance.forceUnlockAsync();
}
});
}
@Override
public Publisher<Void> unlock() {
return reactive(new Supplier<RFuture<Void>>() {
@Override
public RFuture<Void> get() {
return instance.unlockAsync();
}
});
}
@Override
public Publisher<Void> unlock(final long threadId) {
return reactive(new Supplier<RFuture<Void>>() {
@Override
public RFuture<Void> get() {
return instance.unlockAsync(threadId);
}
});
}
@Override
public Publisher<Boolean> tryLock() {
return reactive(new Supplier<RFuture<Boolean>>() {
@Override
public RFuture<Boolean> get() {
return instance.tryLockAsync();
}
});
}
@Override
public Publisher<Void> lock() {
return reactive(new Supplier<RFuture<Void>>() {
@Override
public RFuture<Void> get() {
return instance.lockAsync();
}
});
}
@Override
public Publisher<Void> lock(final long threadId) {
return reactive(new Supplier<RFuture<Void>>() {
@Override
public RFuture<Void> get() {
return instance.lockAsync(threadId);
}
});
}
@Override
public Publisher<Void> lock(final long leaseTime, final TimeUnit unit) {
return reactive(new Supplier<RFuture<Void>>() {
@Override
public RFuture<Void> get() {
return instance.lockAsync(leaseTime, unit);
}
});
}
@Override
public Publisher<Void> lock(final long leaseTime, final TimeUnit unit, final long threadId) {
return reactive(new Supplier<RFuture<Void>>() {
@Override
public RFuture<Void> get() {
return instance.lockAsync(leaseTime, unit, threadId);
}
});
}
@Override
public Publisher<Boolean> tryLock(final long threadId) {
return reactive(new Supplier<RFuture<Boolean>>() {
@Override
public RFuture<Boolean> get() {
return instance.tryLockAsync(threadId);
}
});
}
@Override
public Publisher<Boolean> tryLock(final long waitTime, final TimeUnit unit) {
return reactive(new Supplier<RFuture<Boolean>>() {
@Override
public RFuture<Boolean> get() {
return instance.tryLockAsync(waitTime, unit);
}
});
}
@Override
public Publisher<Boolean> tryLock(final long waitTime, final long leaseTime, final TimeUnit unit) {
return reactive(new Supplier<RFuture<Boolean>>() {
@Override
public RFuture<Boolean> get() {
return instance.tryLockAsync(waitTime, leaseTime, unit);
}
});
}
@Override
public Publisher<Boolean> tryLock(final long waitTime, final long leaseTime, final TimeUnit unit, final long threadId) {
return reactive(new Supplier<RFuture<Boolean>>() {
@Override
public RFuture<Boolean> get() {
return instance.tryLockAsync(waitTime, leaseTime, unit, threadId);
}
});
}
}

@ -0,0 +1,65 @@
/**
* 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.reactive;
import java.util.UUID;
import org.redisson.RedissonReadWriteLock;
import org.redisson.api.RLockAsync;
import org.redisson.api.RLockReactive;
import org.redisson.api.RReadWriteLock;
import org.redisson.api.RReadWriteLockReactive;
import org.redisson.command.CommandAsyncExecutor;
import org.redisson.command.CommandReactiveExecutor;
/**
*
* @author Nikita Koksharov
*
*/
public class RedissonReadWriteLockReactive extends RedissonExpirableReactive implements RReadWriteLockReactive {
private final RReadWriteLock instance;
private final UUID id;
public RedissonReadWriteLockReactive(CommandReactiveExecutor commandExecutor, String name, UUID id) {
super(commandExecutor, name);
this.id = id;
this.instance = new RedissonReadWriteLock(commandExecutor, name, id);
}
@Override
public RLockReactive readLock() {
return new RedissonLockReactive(commandExecutor, getName(), id) {
@Override
protected RLockAsync createLock(CommandAsyncExecutor connectionManager, String name, UUID id) {
return instance.readLock();
}
};
}
@Override
public RLockReactive writeLock() {
return new RedissonLockReactive(commandExecutor, getName(), id) {
@Override
protected RLockAsync createLock(CommandAsyncExecutor connectionManager, String name, UUID id) {
return instance.writeLock();
}
};
}
}

@ -31,6 +31,7 @@ import org.redisson.api.listener.PatternMessageListener;
import org.redisson.client.codec.StringCodec;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
@ -267,7 +268,7 @@ public class RedissonSessionRepository implements FindByIndexNameSessionReposito
}
}
private void publishEvent(Object event) {
private void publishEvent(ApplicationEvent event) {
try {
eventPublisher.publishEvent(event);
} catch (Exception e) {

@ -1,226 +0,0 @@
package org.redisson;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import org.junit.Test;
import org.redisson.api.RBlockingFairQueue;
import org.redisson.api.RBlockingQueue;
import org.redisson.api.RedissonClient;
public class RedissonBlockingFairQueueTest extends BaseTest {
@Test
public void testTimeout() throws InterruptedException {
int size = 1000;
CountDownLatch latch = new CountDownLatch(size);
AtomicInteger t1Counter = new AtomicInteger();
AtomicInteger t2Counter = new AtomicInteger();
AtomicInteger t3Counter = new AtomicInteger();
RedissonClient redisson1 = createInstance();
RBlockingFairQueue<String> queue1 = redisson1.getBlockingFairQueue("test");
Thread t1 = new Thread("test-thread1") {
public void run() {
while (true) {
try {
String a = queue1.poll(5, TimeUnit.SECONDS);
if (latch.getCount() == 0) {
break;
}
if (a == null) {
continue;
}
latch.countDown();
t1Counter.incrementAndGet();
} catch (InterruptedException e) {
}
}
};
};
RedissonClient redisson2 = createInstance();
RBlockingFairQueue<String> queue2 = redisson2.getBlockingFairQueue("test");
Thread t2 = new Thread("test-thread2") {
public void run() {
try {
String a = queue2.poll(2, TimeUnit.SECONDS);
if (a != null) {
latch.countDown();
t2Counter.incrementAndGet();
}
} catch (InterruptedException e) {
}
};
};
RedissonClient redisson3 = createInstance();
RBlockingFairQueue<String> queue3 = redisson3.getBlockingFairQueue("test");
Thread t3 = new Thread("test-thread3") {
public void run() {
while (true) {
try {
String a = queue3.poll(5, TimeUnit.SECONDS);
if (latch.getCount() == 0) {
break;
}
if (a == null) {
continue;
}
latch.countDown();
t3Counter.incrementAndGet();
} catch (InterruptedException e) {
}
}
};
};
t1.start();
t1.join(500);
t2.start();
t2.join(500);
t3.start();
t3.join(500);
RBlockingQueue<String> queue = redisson.getBlockingFairQueue("test");
assertThat(redisson.getList("{" + queue.getName() + "}:list").size()).isEqualTo(3);
for (int i = 0; i < size; i++) {
queue.add("" + i);
}
t1.join();
t2.join();
t3.join();
assertThat(latch.await(50, TimeUnit.SECONDS)).isTrue();
assertThat(t1Counter.get()).isBetween(499, 500);
assertThat(t2Counter.get()).isEqualTo(1);
assertThat(t3Counter.get()).isBetween(499, 500);
assertThat(redisson.getList("{" + queue.getName() + "}:list").size()).isEqualTo(2);
}
@Test
public void testFairness() throws InterruptedException {
int size = 1000;
CountDownLatch latch = new CountDownLatch(size);
AtomicInteger t1Counter = new AtomicInteger();
AtomicInteger t2Counter = new AtomicInteger();
AtomicInteger t3Counter = new AtomicInteger();
AtomicInteger t4Counter = new AtomicInteger();
RedissonClient redisson1 = createInstance();
RBlockingFairQueue<String> queue1 = redisson1.getBlockingFairQueue("test");
Thread t1 = new Thread("test-thread1") {
public void run() {
while (true) {
try {
String a = queue1.poll(1, TimeUnit.SECONDS);
if (a == null) {
break;
}
latch.countDown();
t1Counter.incrementAndGet();
} catch (InterruptedException e) {
}
}
};
};
RedissonClient redisson2 = createInstance();
RBlockingFairQueue<String> queue2 = redisson2.getBlockingFairQueue("test");
Thread t2 = new Thread("test-thread2") {
public void run() {
while (true) {
try {
String a = queue2.poll(1, TimeUnit.SECONDS);
if (a == null) {
break;
}
Thread.sleep(50);
latch.countDown();
t2Counter.incrementAndGet();
} catch (InterruptedException e) {
}
}
};
};
RedissonClient redisson3 = createInstance();
RBlockingFairQueue<String> queue3 = redisson3.getBlockingFairQueue("test");
Thread t3 = new Thread("test-thread3") {
public void run() {
while (true) {
try {
String a = queue3.poll(1, TimeUnit.SECONDS);
if (a == null) {
break;
}
Thread.sleep(10);
latch.countDown();
t3Counter.incrementAndGet();
} catch (InterruptedException e) {
}
}
};
};
RedissonClient redisson4 = createInstance();
RBlockingFairQueue<String> queue4 = redisson4.getBlockingFairQueue("test");
Thread t4 = new Thread("test-thread4") {
public void run() {
while (true) {
try {
String a = queue4.poll(1, TimeUnit.SECONDS);
if (a == null) {
break;
}
latch.countDown();
t4Counter.incrementAndGet();
} catch (InterruptedException e) {
}
}
};
};
RBlockingQueue<String> queue = redisson.getBlockingFairQueue("test");
for (int i = 0; i < size; i++) {
queue.add("" + i);
}
t1.start();
t2.start();
t3.start();
t4.start();
t1.join();
t2.join();
t3.join();
t4.join();
assertThat(latch.await(5, TimeUnit.SECONDS)).isTrue();
queue1.destroy();
queue2.destroy();
queue3.destroy();
queue4.destroy();
redisson1.shutdown();
redisson2.shutdown();
redisson3.shutdown();
redisson4.shutdown();
assertThat(t1Counter.get()).isEqualTo(250);
assertThat(t2Counter.get()).isEqualTo(250);
assertThat(t3Counter.get()).isEqualTo(250);
assertThat(t4Counter.get()).isEqualTo(250);
assertThat(redisson.getKeys().count()).isEqualTo(1);
}
}

@ -6,7 +6,7 @@ import java.util.Arrays;
import java.util.concurrent.TimeUnit;
import org.junit.Test;
import org.redisson.api.RBlockingFairQueue;
import org.redisson.api.RBlockingQueue;
import org.redisson.api.RDelayedQueue;
import org.redisson.api.RQueue;
@ -14,7 +14,7 @@ public class RedissonDelayedQueueTest extends BaseTest {
@Test
public void testRemove() throws InterruptedException {
RBlockingFairQueue<String> blockingFairQueue = redisson.getBlockingFairQueue("delay_queue");
RBlockingQueue<String> blockingFairQueue = redisson.getBlockingQueue("delay_queue");
RDelayedQueue<String> delayedQueue = redisson.getDelayedQueue(blockingFairQueue);
delayedQueue.offer("1_1_1", 3, TimeUnit.SECONDS);
@ -30,7 +30,7 @@ public class RedissonDelayedQueueTest extends BaseTest {
@Test
public void testRemoveAll() throws InterruptedException {
RBlockingFairQueue<String> blockingFairQueue = redisson.getBlockingFairQueue("delay_queue");
RBlockingQueue<String> blockingFairQueue = redisson.getBlockingQueue("delay_queue");
RDelayedQueue<String> delayedQueue = redisson.getDelayedQueue(blockingFairQueue);
delayedQueue.offer("1_1_1", 3, TimeUnit.SECONDS);
@ -49,7 +49,7 @@ public class RedissonDelayedQueueTest extends BaseTest {
@Test
public void testDealyedQueueRetainAll() {
RBlockingFairQueue<Integer> queue1 = redisson.getBlockingFairQueue("test");
RBlockingQueue<Integer> queue1 = redisson.getBlockingQueue("test");
RDelayedQueue<Integer> dealyedQueue = redisson.getDelayedQueue(queue1);
dealyedQueue.offer(3, 5, TimeUnit.SECONDS);
dealyedQueue.offer(1, 2, TimeUnit.SECONDS);
@ -67,7 +67,7 @@ public class RedissonDelayedQueueTest extends BaseTest {
@Test
public void testDealyedQueueReadAll() {
RBlockingFairQueue<Integer> queue1 = redisson.getBlockingFairQueue("test");
RBlockingQueue<Integer> queue1 = redisson.getBlockingQueue("test");
RDelayedQueue<Integer> dealyedQueue = redisson.getDelayedQueue(queue1);
dealyedQueue.offer(3, 5, TimeUnit.SECONDS);
dealyedQueue.offer(1, 2, TimeUnit.SECONDS);
@ -80,7 +80,7 @@ public class RedissonDelayedQueueTest extends BaseTest {
@Test
public void testDealyedQueueRemoveAll() {
RBlockingFairQueue<Integer> queue1 = redisson.getBlockingFairQueue("test");
RBlockingQueue<Integer> queue1 = redisson.getBlockingQueue("test");
RDelayedQueue<Integer> dealyedQueue = redisson.getDelayedQueue(queue1);
dealyedQueue.offer(3, 5, TimeUnit.SECONDS);
dealyedQueue.offer(1, 2, TimeUnit.SECONDS);
@ -96,7 +96,7 @@ public class RedissonDelayedQueueTest extends BaseTest {
@Test
public void testDealyedQueueContainsAll() {
RBlockingFairQueue<Integer> queue1 = redisson.getBlockingFairQueue("test");
RBlockingQueue<Integer> queue1 = redisson.getBlockingQueue("test");
RDelayedQueue<Integer> dealyedQueue = redisson.getDelayedQueue(queue1);
dealyedQueue.offer(3, 5, TimeUnit.SECONDS);
@ -111,7 +111,7 @@ public class RedissonDelayedQueueTest extends BaseTest {
@Test
public void testDealyedQueueContains() {
RBlockingFairQueue<Integer> queue1 = redisson.getBlockingFairQueue("test");
RBlockingQueue<Integer> queue1 = redisson.getBlockingQueue("test");
RDelayedQueue<Integer> dealyedQueue = redisson.getDelayedQueue(queue1);
dealyedQueue.offer(3, 5, TimeUnit.SECONDS);
@ -126,7 +126,7 @@ public class RedissonDelayedQueueTest extends BaseTest {
@Test
public void testDealyedQueueRemove() {
RBlockingFairQueue<Integer> queue1 = redisson.getBlockingFairQueue("test");
RBlockingQueue<Integer> queue1 = redisson.getBlockingQueue("test");
RDelayedQueue<Integer> dealyedQueue = redisson.getDelayedQueue(queue1);
dealyedQueue.offer(3, 5, TimeUnit.SECONDS);
@ -142,7 +142,7 @@ public class RedissonDelayedQueueTest extends BaseTest {
@Test
public void testDealyedQueuePeek() {
RBlockingFairQueue<Integer> queue1 = redisson.getBlockingFairQueue("test");
RBlockingQueue<Integer> queue1 = redisson.getBlockingQueue("test");
RDelayedQueue<Integer> dealyedQueue = redisson.getDelayedQueue(queue1);
dealyedQueue.offer(3, 5, TimeUnit.SECONDS);
@ -156,7 +156,7 @@ public class RedissonDelayedQueueTest extends BaseTest {
@Test
public void testDealyedQueuePollLastAndOfferFirstTo() {
RBlockingFairQueue<Integer> queue1 = redisson.getBlockingFairQueue("test");
RBlockingQueue<Integer> queue1 = redisson.getBlockingQueue("test");
RDelayedQueue<Integer> dealyedQueue = redisson.getDelayedQueue(queue1);
dealyedQueue.offer(3, 5, TimeUnit.SECONDS);
@ -176,7 +176,7 @@ public class RedissonDelayedQueueTest extends BaseTest {
@Test
public void testDelayedQueueOrder() {
RBlockingFairQueue<String> queue = redisson.getBlockingFairQueue("test");
RBlockingQueue<String> queue = redisson.getBlockingQueue("test");
RDelayedQueue<String> dealyedQueue = redisson.getDelayedQueue(queue);
dealyedQueue.offer("1", 1, TimeUnit.SECONDS);
@ -200,7 +200,7 @@ public class RedissonDelayedQueueTest extends BaseTest {
@Test
public void testDealyedQueuePoll() throws InterruptedException {
RBlockingFairQueue<String> queue = redisson.getBlockingFairQueue("test");
RBlockingQueue<String> queue = redisson.getBlockingQueue("test");
RDelayedQueue<String> dealyedQueue = redisson.getDelayedQueue(queue);
dealyedQueue.offer("1", 1, TimeUnit.SECONDS);
@ -224,7 +224,7 @@ public class RedissonDelayedQueueTest extends BaseTest {
@Test
public void testDealyedQueue() throws InterruptedException {
RBlockingFairQueue<String> queue = redisson.getBlockingFairQueue("test");
RBlockingQueue<String> queue = redisson.getBlockingQueue("test");
RDelayedQueue<String> dealyedQueue = redisson.getDelayedQueue(queue);
dealyedQueue.offer("1", 1, TimeUnit.SECONDS);

@ -27,7 +27,6 @@ import org.redisson.api.RAtomicLong;
import org.redisson.api.RBinaryStream;
import org.redisson.api.RBitSet;
import org.redisson.api.RBlockingDeque;
import org.redisson.api.RBlockingFairQueue;
import org.redisson.api.RBlockingQueue;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RBoundedBlockingQueue;
@ -169,7 +168,6 @@ public class SpringNamespaceObjectTest extends BaseTest {
{"lex-sorted-set", RLexSortedSet.class, null},
{"topic", RTopic.class, null},
{"pattern-topic", RPatternTopic.class, null},
{"blocking-fair-queue", RBlockingFairQueue.class, null},
{"queue", RQueue.class, null},
{"delayed-queue", RDelayedQueue.class, "queue"},
{"priority-queue", RPriorityQueue.class, null},
@ -228,7 +226,6 @@ public class SpringNamespaceObjectTest extends BaseTest {
{"lex-sorted-set-ext", RLexSortedSet.class, null},
{"topic-ext", RTopic.class, null},
{"pattern-topic-ext", RPatternTopic.class, null},
{"blocking-fair-queue-ext", RBlockingFairQueue.class, null},
{"queue-ext", RQueue.class, null},
{"delayed-queue-ext", RDelayedQueue.class, "queue-ext"},
{"priority-queue-ext", RPriorityQueue.class, null},

Loading…
Cancel
Save