Merge branch 'master' into 3.0.0

# Conflicts:
#	pom.xml
#	redisson-all/pom.xml
#	redisson-spring-boot-starter/pom.xml
#	redisson-spring-data/pom.xml
#	redisson-spring-data/redisson-spring-data-16/pom.xml
#	redisson-spring-data/redisson-spring-data-17/pom.xml
#	redisson-spring-data/redisson-spring-data-18/pom.xml
#	redisson-spring-data/redisson-spring-data-20/pom.xml
#	redisson-tomcat/pom.xml
#	redisson-tomcat/redisson-tomcat-6/pom.xml
#	redisson-tomcat/redisson-tomcat-7/pom.xml
#	redisson-tomcat/redisson-tomcat-8/pom.xml
#	redisson-tomcat/redisson-tomcat-9/pom.xml
#	redisson/pom.xml
#	redisson/src/main/java/org/redisson/RedissonLongAdder.java
pull/1821/head
Nikita 7 years ago
commit 5bb7e17e97

@ -4,6 +4,25 @@ Redisson Releases History
Try __[Redisson PRO](https://redisson.pro)__ version.
### 03-Sep-2018 - versions 2.13.0 and 3.8.0 released
Feature - __Spring Data Redis__ integration. Please refer to [documentation](https://github.com/redisson/redisson/tree/master/redisson-spring-data#spring-data-redis-integration) for more details
Feature - __Spring Boot Starter__ implementation. Please refer to [documentation](https://github.com/redisson/redisson/tree/master/redisson-spring-boot-starter#spring-boot-starter) for more details
Feature - `RBlockingDequeReactive` object added
Feature - `sharedSession` setting for Tomcat Session Manager. Appropriate solution for migration of EAR based application with multiple WARs hosted previously on WebLogic or other servers. Please refer to [documentation](https://github.com/redisson/redisson/tree/master/redisson-tomcat) for more details
Improvement - Redis request/response handling performance improvement
Improvement - CompositeIterator decoupled from CompositeIterable (thanks to Pepe-Lu)
Fixed - task scheduled with time more than 1 hour is not executed
Fixed - RScheduledExecutorService doesn't handle delayed tasks correctly
Fixed - `RMapCache` and `RSetCache` objects should implement `RDestroyable`
Fixed - `RBucket.set` method with ttl throws NPE if value is null
Fixed - false HashedWheelTimer resource leak message
Fixed - `RExecutorService` task execution performance regression
Fixed - locking in multiple parallel transactions created with the same thread
Fixed - `JCache.removeAll` doesn't work
Fixed - Batch in `ExecutionMode.REDIS_WRITE_ATOMIC` and `ExecutionMode.REDIS_READ_ATOMIC` returns `QUEUED` instead of real result
Fixed - tasks scheduled with cron expression don't work in different timezones (thanks to Arpit Agrawal)
Fixed - global config codec is not registered in codec cache for reference objects (thanks to Rui Gu)
### 19-Jul-2018 - versions 2.12.5 and 3.7.5 released
Feature - `RScoredSortedSetReactive`, `RSetReactive`, `RListReactive` objects implement `RSortableReactive` interface
Feature - `RGeoReactive` object added

@ -6,8 +6,8 @@ Based on high-performance async and lock-free Java Redis client and [Netty](http
| Stable <br/> Release Version | Release Date | JDK Version<br/> compatibility | `CompletionStage` <br/> support | `ProjectReactor` version<br/> compatibility |
| ------------- | ------------- | ------------| -----------| -----------|
| 3.7.5 | 19.07.2018 | 1.8, 1.9, 1.10+ | Yes | 3.1.x |
| 2.12.5 | 19.07.2018 | 1.6, 1.7, 1.8, 1.9, 1.10, Android | No | 2.0.8 |
| 3.8.0 | 03.09.2018 | 1.8, 1.9, 1.10+ | Yes | 3.1.x |
| 2.13.0 | 03.09.2018 | 1.6, 1.7, 1.8, 1.9, 1.10, Android | No | 2.0.8 |
Features
@ -40,6 +40,8 @@ Features
* [Spring Framework](https://github.com/redisson/redisson/wiki/14.-Integration%20with%20frameworks#141-spring-framework)
* [Spring Cache](https://github.com/redisson/redisson/wiki/14.-Integration%20with%20frameworks/#142-spring-cache) implementation
* [Spring Transaction API](https://github.com/redisson/redisson/wiki/14.-Integration-with-frameworks/#147-spring-transaction-manager) implementation
* [Spring Data Redis](https://github.com/redisson/redisson/wiki/14.-Integration-with-frameworks/#148-spring-data-redis) integration
* [Spring Boot Starter](https://github.com/redisson/redisson/wiki/14.-Integration-with-frameworks/#149-spring-boot-starter) implementation
* [Hibernate Cache](https://github.com/redisson/redisson/wiki/14.-Integration%20with%20frameworks/#143-hibernate-cache) implementation
* [Transactions API](https://github.com/redisson/redisson/wiki/10.-Additional-features#104-transactions)
* [XA Transaction API](https://github.com/redisson/redisson/wiki/10.-additional-features/#105-xa-transactions) implementation
@ -106,23 +108,23 @@ Quick start
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.7.5</version>
<version>3.8.0</version>
</dependency>
<!-- JDK 1.6+ compatible -->
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>2.12.5</version>
<version>2.13.0</version>
</dependency>
#### Gradle
// JDK 1.8+ compatible
compile 'org.redisson:redisson:3.7.5'
compile 'org.redisson:redisson:3.8.0'
// JDK 1.6+ compatible
compile 'org.redisson:redisson:2.12.5'
compile 'org.redisson:redisson:2.13.0'
#### Java
@ -147,11 +149,11 @@ RExecutorService executor = redisson.getExecutorService("myExecutorService");
Downloads
===============================
[Redisson 3.7.5](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson&v=3.7.5&e=jar),
[Redisson node 3.7.5](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson-all&v=3.7.5&e=jar)
[Redisson 3.8.0](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson&v=3.8.0&e=jar),
[Redisson node 3.8.0](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson-all&v=3.8.0&e=jar)
[Redisson 2.12.5](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson&v=2.12.5&e=jar),
[Redisson node 2.12.5](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson-all&v=2.12.5&e=jar)
[Redisson 2.13.0](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson&v=2.13.0&e=jar),
[Redisson node 2.13.0](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson-all&v=2.13.0&e=jar)
FAQs
===============================

@ -20,6 +20,7 @@
<maven.test.skip>true</maven.test.skip>
<source.version>1.8</source.version>
<test.source.version>1.8</test.source.version>
<release.version>7</release.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
@ -144,6 +145,7 @@
<testOutputDirectory>${basedir}/target/test-classes</testOutputDirectory>
<sourceDirectory>${basedir}/src/main/java</sourceDirectory>
<testSourceDirectory>${basedir}/src/test/java</testSourceDirectory>
<plugins>
<plugin>
@ -177,6 +179,7 @@
<configuration>
<source>${source.version}</source>
<target>${source.version}</target>
<release>${release.version}</release>
<optimize>true</optimize>
<showDeprecations>true</showDeprecations>
</configuration>
@ -215,7 +218,6 @@
</configuration>
</plugin>
</plugins>
</build>
</project>

@ -42,5 +42,25 @@ Usage
compile 'org.redisson:redisson-spring-boot-starter:2.13.0'
```
### 2. Add settings into `application.settings` file
### 2. Get access to Redisson through spring bean with `RedissonClient` interface
```properties
# common spring boot settings
spring.redis.database=
spring.redis.host=
spring.redis.port=
spring.redis.password=
spring.redis.ssl=
spring.redis.timeout=
spring.redis.cluster.nodes=
spring.redis.sentinel.master=
spring.redis.sentinel.nodes=
# Redisson settings
#path to redisson.yaml or redisson.json
spring.redis.redisson.config=classpath:redisson.yaml
```
### 3. Get access to Redisson through spring bean with `RedissonClient` interface

@ -17,12 +17,11 @@ package org.redisson;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import org.redisson.api.RBlockingQueue;
@ -65,10 +64,33 @@ import io.netty.util.internal.PlatformDependent;
*/
public class RedissonRemoteService extends BaseRemoteService implements RRemoteService {
public static class Entry {
RFuture<String> future;
final AtomicInteger counter;
public Entry(int workers) {
counter = new AtomicInteger(workers);
}
public void setFuture(RFuture<String> future) {
this.future = future;
}
public RFuture<String> getFuture() {
return future;
}
public AtomicInteger getCounter() {
return counter;
}
}
private static final Logger log = LoggerFactory.getLogger(RedissonRemoteService.class);
private final Map<RemoteServiceKey, RemoteServiceMethod> beans = PlatformDependent.newConcurrentHashMap();
private final Map<Class<?>, Set<RFuture<String>>> futures = PlatformDependent.newConcurrentHashMap();
private final Map<Class<?>, Entry> remoteMap = PlatformDependent.newConcurrentHashMap();
public RedissonRemoteService(Codec codec, RedissonClient redisson, String name, CommandExecutor commandExecutor, String executorId, ConcurrentMap<String, ResponseEntry> responses) {
super(codec, redisson, name, commandExecutor, executorId, responses);
@ -110,20 +132,19 @@ public class RedissonRemoteService extends BaseRemoteService implements RRemoteS
beans.remove(key);
}
Set<RFuture<String>> removedFutures = futures.remove(remoteInterface);
if (removedFutures == null) {
return;
}
for (RFuture<String> future : removedFutures) {
future.cancel(false);
Entry entry = remoteMap.remove(remoteInterface);
if (entry != null && entry.getFuture() != null) {
entry.getFuture().cancel(false);
}
}
@Override
public int getFreeWorkers(Class<?> remoteInterface) {
Set<RFuture<String>> futuresSet = futures.get(remoteInterface);
return futuresSet.size();
Entry entry = remoteMap.remove(remoteInterface);
if (entry == null) {
return 0;
}
return entry.getCounter().get();
}
@Override
@ -144,32 +165,28 @@ public class RedissonRemoteService extends BaseRemoteService implements RRemoteS
}
}
Set<RFuture<String>> values = Collections.newSetFromMap(PlatformDependent.<RFuture<String>, Boolean>newConcurrentHashMap());
futures.put(remoteInterface, values);
remoteMap.put(remoteInterface, new Entry(workers));
String requestQueueName = getRequestQueueName(remoteInterface);
RBlockingQueue<String> requestQueue = redisson.getBlockingQueue(requestQueueName, StringCodec.INSTANCE);
for (int i = 0; i < workers; i++) {
subscribe(remoteInterface, requestQueue, executor);
}
subscribe(remoteInterface, requestQueue, executor);
}
private <T> void subscribe(final Class<T> remoteInterface, final RBlockingQueue<String> requestQueue,
final ExecutorService executor) {
Set<RFuture<String>> futuresSet = futures.get(remoteInterface);
if (futuresSet == null) {
final Entry entry = remoteMap.get(remoteInterface);
if (entry == null) {
return;
}
final RFuture<String> take = requestQueue.takeAsync();
futuresSet.add(take);
entry.setFuture(take);
take.addListener(new FutureListener<String>() {
@Override
public void operationComplete(Future<String> future) throws Exception {
Set<RFuture<String>> futuresSet = futures.get(remoteInterface);
if (futuresSet == null) {
public void operationComplete(Future<String> future) throws Exception {
Entry entry = remoteMap.get(remoteInterface);
if (entry == null) {
return;
}
futuresSet.remove(take);
if (!future.isSuccess()) {
if (future.cause() instanceof RedissonShutdownException) {
@ -184,6 +201,14 @@ public class RedissonRemoteService extends BaseRemoteService implements RRemoteS
// do not subscribe now, see
// https://github.com/mrniko/redisson/issues/493
// subscribe(remoteInterface, requestQueue);
if (entry.getCounter().get() == 0) {
return;
}
if (entry.getCounter().decrementAndGet() > 0) {
subscribe(remoteInterface, requestQueue, executor);
}
final String requestId = future.getNow();
RMap<String, RemoteServiceRequest> tasks = redisson.getMap(requestQueue.getName() + ":tasks", new CompositeCodec(StringCodec.INSTANCE, codec, codec));
@ -197,16 +222,18 @@ public class RedissonRemoteService extends BaseRemoteService implements RRemoteS
return;
}
log.error("Can't process the remote service request with id " + requestId, future.cause());
// re-subscribe after a failed takeAsync
subscribe(remoteInterface, requestQueue, executor);
resubscribe(remoteInterface, requestQueue, executor);
return;
}
final RemoteServiceRequest request = future.getNow();
if (request == null) {
log.debug("Task can't be found for request: {}", requestId);
// re-subscribe after a skipped ackTimeout
subscribe(remoteInterface, requestQueue, executor);
resubscribe(remoteInterface, requestQueue, executor);
return;
}
@ -215,8 +242,9 @@ public class RedissonRemoteService extends BaseRemoteService implements RRemoteS
if (request.getOptions().isAckExpected() && elapsedTime > request
.getOptions().getAckTimeoutInMillis()) {
log.debug("request: {} has been skipped due to ackTimeout. Elapsed time: {}ms", request.getId(), elapsedTime);
// re-subscribe after a skipped ackTimeout
subscribe(remoteInterface, requestQueue, executor);
resubscribe(remoteInterface, requestQueue, executor);
return;
}
@ -247,13 +275,14 @@ public class RedissonRemoteService extends BaseRemoteService implements RRemoteS
return;
}
log.error("Can't send ack for request: " + request, future.cause());
// re-subscribe after a failed send (ack)
subscribe(remoteInterface, requestQueue, executor);
resubscribe(remoteInterface, requestQueue, executor);
return;
}
if (!future.getNow()) {
subscribe(remoteInterface, requestQueue, executor);
resubscribe(remoteInterface, requestQueue, executor);
return;
}
@ -269,13 +298,14 @@ public class RedissonRemoteService extends BaseRemoteService implements RRemoteS
return;
}
log.error("Can't send ack for request: " + request, future.cause());
// re-subscribe after a failed send (ack)
subscribe(remoteInterface, requestQueue, executor);
resubscribe(remoteInterface, requestQueue, executor);
return;
}
if (!future.getNow()) {
subscribe(remoteInterface, requestQueue, executor);
resubscribe(remoteInterface, requestQueue, executor);
return;
}
@ -374,7 +404,7 @@ public class RedissonRemoteService extends BaseRemoteService implements RRemoteS
@Override
public void operationComplete(Future<Void> future) throws Exception {
// interface has been deregistered
if (futures.get(remoteInterface) == null) {
if (!remoteMap.containsKey(remoteInterface)) {
return;
}
@ -386,12 +416,17 @@ public class RedissonRemoteService extends BaseRemoteService implements RRemoteS
future.cause());
}
// re-subscribe anyways (fail or success) after the send
// (response)
subscribe(remoteInterface, requestQueue, executor);
resubscribe(remoteInterface, requestQueue, executor);
}
});
} else {
resubscribe(remoteInterface, requestQueue, executor);
}
}
private <T> void resubscribe(Class<T> remoteInterface, RBlockingQueue<String> requestQueue,
ExecutorService executor) {
if (remoteMap.get(remoteInterface).getCounter().getAndIncrement() == 0) {
// re-subscribe anyways after the method invocation
subscribe(remoteInterface, requestQueue, executor);
}

@ -19,9 +19,9 @@ import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit;
import org.redisson.RedissonListMultimapCache;
@ -38,7 +38,6 @@ import org.redisson.api.RScoredSortedSet;
import org.redisson.api.RTopic;
import org.redisson.api.listener.BaseStatusListener;
import org.redisson.api.listener.MessageListener;
import org.redisson.client.ChannelName;
import org.redisson.client.codec.ByteArrayCodec;
import org.redisson.client.codec.Codec;
import org.redisson.command.CommandAsyncExecutor;
@ -64,7 +63,7 @@ public abstract class LocalCacheListener {
public static final String DISABLED_KEYS_SUFFIX = "disabled-keys";
public static final String DISABLED_ACK_SUFFIX = ":topic";
private Map<CacheKey, String> disabledKeys = new ConcurrentHashMap<CacheKey, String>();
private ConcurrentMap<CacheKey, String> disabledKeys = new ConcurrentHashMap<CacheKey, String>();
private static final Logger log = LoggerFactory.getLogger(LocalCacheListener.class);

@ -45,6 +45,7 @@ import org.redisson.client.protocol.convertor.VoidReplayConvertor;
import org.redisson.client.protocol.decoder.ClusterNodesDecoder;
import org.redisson.client.protocol.decoder.ListFirstObjectDecoder;
import org.redisson.client.protocol.decoder.ListMultiDecoder;
import org.redisson.client.protocol.decoder.ListObjectDecoder;
import org.redisson.client.protocol.decoder.ListResultReplayDecoder;
import org.redisson.client.protocol.decoder.ListScanResult;
import org.redisson.client.protocol.decoder.ListScanResultReplayDecoder;
@ -58,7 +59,6 @@ import org.redisson.client.protocol.decoder.ObjectMapEntryReplayDecoder;
import org.redisson.client.protocol.decoder.ObjectMapJoinDecoder;
import org.redisson.client.protocol.decoder.ObjectMapReplayDecoder;
import org.redisson.client.protocol.decoder.ObjectSetReplayDecoder;
import org.redisson.client.protocol.decoder.ListObjectDecoder;
import org.redisson.client.protocol.decoder.ScoredSortedSetPolledObjectDecoder;
import org.redisson.client.protocol.decoder.ScoredSortedSetReplayDecoder;
import org.redisson.client.protocol.decoder.ScoredSortedSetScanDecoder;
@ -261,7 +261,7 @@ public interface RedisCommands {
RedisStrictCommand<Void> AUTH = new RedisStrictCommand<Void>("AUTH", new VoidReplayConvertor());
RedisStrictCommand<Void> SELECT = new RedisStrictCommand<Void>("SELECT", new VoidReplayConvertor());
RedisStrictCommand<Boolean> CLIENT_SETNAME = new RedisStrictCommand<Boolean>("CLIENT", "SETNAME", new BooleanReplayConvertor());
RedisStrictCommand<Void> CLIENT_SETNAME = new RedisStrictCommand<Void>("CLIENT", "SETNAME", new VoidReplayConvertor());
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());

@ -299,7 +299,7 @@ public class RedissonExecutorServiceTest extends BaseTest {
e.execute(new RunnableTask());
}
e.shutdown();
assertThat(e.awaitTermination(1000, TimeUnit.MILLISECONDS)).isTrue();
assertThat(e.awaitTermination(1500, TimeUnit.MILLISECONDS)).isTrue();
}
@Test

Loading…
Cancel
Save