Merge branch 'master' into 3.0.0

# Conflicts:
#	pom.xml
#	redisson-all/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
pull/1821/head
Nikita 7 years ago
commit 7f9e320b80

@ -4,6 +4,18 @@ Redisson Releases History
Try __[Redisson PRO](https://redisson.pro)__ version.
### 14-Mar-2018 - versions 2.11.3 and 3.6.3 released
Feature - DNS monitoring for Sentinel nodes
Fixed - Old/stale nodes not removed from NodesGroup
Fixed - CertificateException while connecting over SSL to Azure or AWS Elasticache config endpoint
Fixed - publish subscribe connections couldn't be resubscribed during failover
Fixed - RedissonRedLock.tryLock doesn't work for some values of wait time parameter
Fixed - NPE in JCache.getAndRemoveValue
Fixed - memory leak in publish subscribe
Fixed - codec classLoader wasn't used in `ExecutorService` and `RemoteService` objects
Fixed - warning for disconnected slaves in sentinel mode
### 05-Mar-2018 - versions 2.11.2 and 3.6.2 released
[Redisson PRO](https://redisson.pro) performance improvements for follow `performanceMode` values:

@ -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.6.2 | 05.03.2018 | 1.8, 1.9+ | Yes | 3.1.x |
| 2.11.2 | 05.03.2018 | 1.6, 1.7, 1.8, 1.9 and Android | No | 2.0.8 |
| 3.6.3 | 14.03.2018 | 1.8, 1.9+ | Yes | 3.1.x |
| 2.11.3 | 14.03.2018 | 1.6, 1.7, 1.8, 1.9 and Android | No | 2.0.8 |
Features
@ -95,23 +95,23 @@ Quick start
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.6.2</version>
<version>3.6.3</version>
</dependency>
<!-- JDK 1.6+ compatible -->
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>2.11.2</version>
<version>2.11.3</version>
</dependency>
#### Gradle
// JDK 1.8+ compatible
compile 'org.redisson:redisson:3.6.2'
compile 'org.redisson:redisson:3.6.3'
// JDK 1.6+ compatible
compile 'org.redisson:redisson:2.11.2'
compile 'org.redisson:redisson:2.11.3'
#### Java
@ -136,11 +136,11 @@ RExecutorService executor = redisson.getExecutorService("myExecutorService");
Downloads
===============================
[Redisson 3.6.2](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson&v=3.6.2&e=jar),
[Redisson node 3.6.2](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson-all&v=3.6.2&e=jar)
[Redisson 3.6.3](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson&v=3.6.3&e=jar),
[Redisson node 3.6.3](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson-all&v=3.6.3&e=jar)
[Redisson 2.11.2](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson&v=2.11.2&e=jar),
[Redisson node 2.11.2](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson-all&v=2.11.2&e=jar)
[Redisson 2.11.3](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson&v=2.11.3&e=jar),
[Redisson node 2.11.3](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson-all&v=2.11.3&e=jar)
### Supported by

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

@ -17,7 +17,6 @@ package org.redisson;
import java.util.Arrays;
import java.util.Collection;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import org.redisson.api.RFuture;
@ -56,6 +55,7 @@ public class RedissonListMultimapCache<K, V> extends RedissonListMultimap<K, V>
baseCache = new RedissonMultimapCache<K>(connectionManager, this, getTimeoutSetName(), prefix);
}
@Override
public RFuture<Boolean> containsKeyAsync(Object key) {
ByteBuf keyState = encodeMapKey(key);
String keyHash = hash(keyState);
@ -83,7 +83,7 @@ public class RedissonListMultimapCache<K, V> extends RedissonListMultimap<K, V>
return suffixName(getName(), "redisson_list_multimap_ttl");
}
@Override
public RFuture<Boolean> containsValueAsync(Object value) {
ByteBuf valueState = encodeMapValue(value);
@ -114,6 +114,7 @@ public class RedissonListMultimapCache<K, V> extends RedissonListMultimap<K, V>
valueState, System.currentTimeMillis(), prefix);
}
@Override
public RFuture<Boolean> containsEntryAsync(Object key, Object value) {
ByteBuf keyState = encodeMapKey(key);
String keyHash = hash(keyState);
@ -148,6 +149,7 @@ public class RedissonListMultimapCache<K, V> extends RedissonListMultimap<K, V>
return new RedissonListMultimapValues<V>(codec, commandExecutor, valuesName, getTimeoutSetName(), key);
}
@Override
public RFuture<Collection<V>> getAllAsync(K key) {
ByteBuf keyState = encodeMapKey(key);
String keyHash = hash(keyState);
@ -166,12 +168,13 @@ public class RedissonListMultimapCache<K, V> extends RedissonListMultimap<K, V>
Arrays.<Object>asList(valuesName, getTimeoutSetName()), System.currentTimeMillis(), keyState);
}
@Override
public RFuture<Collection<V>> removeAllAsync(Object key) {
ByteBuf keyState = encodeMapKey(key);
String keyHash = hash(keyState);
String valuesName = getValuesName(keyHash);
return commandExecutor.evalWriteAsync(getName(), codec, RedisCommands.EVAL_SET,
return commandExecutor.evalWriteAsync(getName(), codec, RedisCommands.EVAL_LIST,
"redis.call('hdel', KEYS[1], ARGV[1]); " +
"local members = redis.call('lrange', KEYS[2], 0, -1); " +
"redis.call('del', KEYS[2]); " +

@ -119,7 +119,7 @@ public class RedissonSortedSet<V> extends RedissonObject implements RSortedSet<V
comparatorHolder = redisson.getBucket(getComparatorKeyName(), StringCodec.INSTANCE);
lock = redisson.getLock("redisson_sortedset_lock:{" + getName() + "}");
list = (RedissonList<V>) redisson.getList(getName());
list = (RedissonList<V>) redisson.getList(getName(), codec);
loadComparator();
}

@ -972,7 +972,7 @@ public interface RedissonClient {
/**
* Returns {@code true} if this Redisson instance has been shut down.
*
* @return code true} if this Redisson instance has been shut down overwise <code>false</code>
* @return {@code true} if this Redisson instance has been shut down overwise <code>false</code>
*/
boolean isShutdown();

@ -198,7 +198,8 @@ public class CommandDecoder extends ReplayingDecoder<State> {
decode(in, commandData, null, ctx.channel());
if (commandData != null && RedisCommands.EXEC.getName().equals(commandData.getCommand().getName())) {
if (commandData != null && RedisCommands.EXEC.getName().equals(commandData.getCommand().getName())
&& commandData.getPromise().isSuccess()) {
List<Object> objects = (List<Object>) commandData.getPromise().getNow();
Iterator<Object> iter = objects.iterator();
boolean multiFound = false;
@ -218,7 +219,9 @@ public class CommandDecoder extends ReplayingDecoder<State> {
}
}
} catch (Exception e) {
commandData.tryFailure(e);
if (commandData != null) {
commandData.tryFailure(e);
}
throw e;
}
i++;

@ -27,6 +27,7 @@ import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit;
@ -88,8 +89,8 @@ public class ClusterConnectionManager extends MasterSlaveConnectionManager {
private AddressResolver<InetSocketAddress> resolver;
public ClusterConnectionManager(ClusterServersConfig cfg, Config config) {
super(config);
public ClusterConnectionManager(ClusterServersConfig cfg, Config config, UUID id) {
super(config, id);
this.config = create(cfg);
initTimer(this.config);

@ -25,6 +25,7 @@ import java.lang.reflect.Modifier;
import java.net.URI;
import java.net.URL;
import java.util.List;
import java.util.UUID;
import org.redisson.api.RedissonNodeInitializer;
import org.redisson.client.codec.Codec;
@ -223,24 +224,26 @@ public class ConfigSupport {
}
public static ConnectionManager createConnectionManager(Config configCopy) {
UUID id = UUID.randomUUID();
if (configCopy.getMasterSlaveServersConfig() != null) {
validate(configCopy.getMasterSlaveServersConfig());
return new MasterSlaveConnectionManager(configCopy.getMasterSlaveServersConfig(), configCopy);
return new MasterSlaveConnectionManager(configCopy.getMasterSlaveServersConfig(), configCopy, id);
} else if (configCopy.getSingleServerConfig() != null) {
validate(configCopy.getSingleServerConfig());
return new SingleConnectionManager(configCopy.getSingleServerConfig(), configCopy);
return new SingleConnectionManager(configCopy.getSingleServerConfig(), configCopy, id);
} else if (configCopy.getSentinelServersConfig() != null) {
validate(configCopy.getSentinelServersConfig());
return new SentinelConnectionManager(configCopy.getSentinelServersConfig(), configCopy);
return new SentinelConnectionManager(configCopy.getSentinelServersConfig(), configCopy, id);
} else if (configCopy.getClusterServersConfig() != null) {
validate(configCopy.getClusterServersConfig());
return new ClusterConnectionManager(configCopy.getClusterServersConfig(), configCopy);
return new ClusterConnectionManager(configCopy.getClusterServersConfig(), configCopy, id);
} else if (configCopy.getElasticacheServersConfig() != null) {
validate(configCopy.getElasticacheServersConfig());
return new ElasticacheConnectionManager(configCopy.getElasticacheServersConfig(), configCopy);
return new ElasticacheConnectionManager(configCopy.getElasticacheServersConfig(), configCopy, id);
} else if (configCopy.getReplicatedServersConfig() != null) {
validate(configCopy.getReplicatedServersConfig());
return new ReplicatedConnectionManager(configCopy.getReplicatedServersConfig(), configCopy);
return new ReplicatedConnectionManager(configCopy.getReplicatedServersConfig(), configCopy, id);
} else if (configCopy.getConnectionManager() != null) {
return configCopy.getConnectionManager();
}else {

@ -141,6 +141,11 @@ public class ClientConnectionsEntry {
}
public void releaseConnection(RedisConnection connection) {
if (client != connection.getRedisClient()) {
connection.closeAsync();
return;
}
connection.setLastUsageTime(System.currentTimeMillis());
freeConnections.add(connection);
}
@ -215,6 +220,11 @@ public class ClientConnectionsEntry {
}
public void releaseSubscribeConnection(RedisPubSubConnection connection) {
if (client != connection.getRedisClient()) {
connection.closeAsync();
return;
}
connection.setLastUsageTime(System.currentTimeMillis());
freeSubscribeConnections.add(connection);
}
@ -227,17 +237,11 @@ public class ClientConnectionsEntry {
freeSubscribeConnectionsCounter.release();
}
public boolean freezeMaster(FreezeReason reason) {
public void freezeMaster(FreezeReason reason) {
synchronized (this) {
setFreezed(true);
// only RECONNECT freeze reason could be replaced
if (getFreezeReason() == null
|| getFreezeReason() == FreezeReason.RECONNECT) {
setFreezeReason(reason);
return true;
}
setFreezeReason(reason);
}
return false;
}
@Override

@ -15,14 +15,16 @@
*/
package org.redisson.connection;
import java.util.UUID;
import org.redisson.config.Config;
import org.redisson.config.ElasticacheServersConfig;
@Deprecated
public class ElasticacheConnectionManager extends ReplicatedConnectionManager {
public ElasticacheConnectionManager(ElasticacheServersConfig cfg, Config config) {
super(cfg, config);
public ElasticacheConnectionManager(ElasticacheServersConfig cfg, Config config, UUID id) {
super(cfg, config, id);
}
}

@ -111,7 +111,7 @@ public class MasterSlaveConnectionManager implements ConnectionManager {
}
};
protected final UUID id = UUID.randomUUID();
protected final UUID id;
public static final int MAX_SLOT = 16384;
@ -162,15 +162,16 @@ public class MasterSlaveConnectionManager implements ConnectionManager {
}
}
public MasterSlaveConnectionManager(MasterSlaveServersConfig cfg, Config config) {
this(config);
public MasterSlaveConnectionManager(MasterSlaveServersConfig cfg, Config config, UUID id) {
this(config, id);
this.config = cfg;
initTimer(cfg);
initSingleEntry();
}
public MasterSlaveConnectionManager(Config cfg) {
protected MasterSlaveConnectionManager(Config cfg, UUID id) {
this.id = id;
Version.logVersion();
if (cfg.getTransportMode() == TransportMode.EPOLL) {
@ -527,10 +528,16 @@ public class MasterSlaveConnectionManager implements ConnectionManager {
}
protected final void changeMaster(int slot, URI address) {
MasterSlaveEntry entry = getEntry(slot);
final MasterSlaveEntry entry = getEntry(slot);
client2entry.remove(entry.getClient());
entry.changeMaster(address);
client2entry.put(entry.getClient(), entry);
entry.changeMaster(address).addListener(new FutureListener<RedisClient>() {
@Override
public void operationComplete(Future<RedisClient> future) throws Exception {
if (future.isSuccess()) {
client2entry.put(entry.getClient(), entry);
}
}
});
}
protected final void addEntry(Integer slot, MasterSlaveEntry entry) {

@ -368,8 +368,9 @@ public class MasterSlaveEntry {
// exclude master from slaves
if (!config.checkSkipSlavesInit()
&& !addr.equals(entry.getClient().getAddr())) {
slaveDown(addr, FreezeReason.SYSTEM);
log.info("master {} excluded from slaves", addr);
if (slaveDown(addr, FreezeReason.SYSTEM)) {
log.info("master {} excluded from slaves", addr);
}
}
return true;
}
@ -387,8 +388,9 @@ public class MasterSlaveEntry {
// exclude master from slaves
if (!config.checkSkipSlavesInit()
&& !URIBuilder.compare(addr, address)) {
slaveDown(addr, FreezeReason.SYSTEM);
log.info("master {} excluded from slaves", addr);
if (slaveDown(addr, FreezeReason.SYSTEM)) {
log.info("master {} excluded from slaves", addr);
}
}
return true;
}
@ -402,8 +404,9 @@ public class MasterSlaveEntry {
// exclude master from slaves
if (!config.checkSkipSlavesInit()
&& !addr.equals(address)) {
slaveDown(addr, FreezeReason.SYSTEM);
log.info("master {} excluded from slaves", addr);
if (slaveDown(addr, FreezeReason.SYSTEM)) {
log.info("master {} excluded from slaves", addr);
}
}
return true;
}
@ -415,11 +418,13 @@ public class MasterSlaveEntry {
* Shutdown old master client.
*
* @param address of Redis
* @return
*/
public void changeMaster(URI address) {
public RFuture<RedisClient> changeMaster(URI address) {
final ClientConnectionsEntry oldMaster = masterEntry;
RFuture<RedisClient> future = setupMasterEntry(address);
changeMaster(address, oldMaster, future);
return future;
}
public void changeMaster(InetSocketAddress address, URI uri) {
@ -469,10 +474,6 @@ public class MasterSlaveEntry {
return masterEntry.getFreezeReason();
}
public void freeze() {
masterEntry.freezeMaster(FreezeReason.MANAGER);
}
public void unfreeze() {
masterEntry.resetFirstFail();
synchronized (masterEntry) {

@ -17,6 +17,7 @@ package org.redisson.connection;
import java.net.URI;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
@ -60,8 +61,8 @@ public class ReplicatedConnectionManager extends MasterSlaveConnectionManager {
slave
}
public ReplicatedConnectionManager(ReplicatedServersConfig cfg, Config config) {
super(config);
public ReplicatedConnectionManager(ReplicatedServersConfig cfg, Config config, UUID id) {
super(config, id);
this.config = create(cfg);
initTimer(this.config);

@ -24,6 +24,7 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
@ -32,14 +33,11 @@ import java.util.concurrent.atomic.AtomicReference;
import org.redisson.api.NodeType;
import org.redisson.api.RFuture;
import org.redisson.client.BaseRedisPubSubListener;
import org.redisson.client.RedisClient;
import org.redisson.client.RedisConnection;
import org.redisson.client.RedisConnectionException;
import org.redisson.client.RedisPubSubConnection;
import org.redisson.client.codec.StringCodec;
import org.redisson.client.protocol.RedisCommands;
import org.redisson.client.protocol.pubsub.PubSubType;
import org.redisson.cluster.ClusterSlotRange;
import org.redisson.config.BaseMasterSlaveServersConfig;
import org.redisson.config.Config;
@ -72,18 +70,16 @@ public class SentinelConnectionManager extends MasterSlaveConnectionManager {
private final Set<String> slaves = Collections.newSetFromMap(PlatformDependent.<String, Boolean>newConcurrentHashMap());
private final Set<URI> disconnectedSlaves = new HashSet<URI>();
private String masterName;
private ScheduledFuture<?> monitorFuture;
private AddressResolver<InetSocketAddress> sentinelResolver;
public SentinelConnectionManager(SentinelServersConfig cfg, Config config) {
super(config);
public SentinelConnectionManager(SentinelServersConfig cfg, Config config, UUID id) {
super(config, id);
if (cfg.getMasterName() == null) {
throw new IllegalArgumentException("masterName parameter is not defined!");
}
this.masterName = cfg.getMasterName();
this.config = create(cfg);
initTimer(this.config);
@ -175,7 +171,7 @@ public class SentinelConnectionManager extends MasterSlaveConnectionManager {
scheduleSentinelDNSCheck();
}
protected void scheduleSentinelDNSCheck() {
private void scheduleSentinelDNSCheck() {
monitorFuture = group.schedule(new Runnable() {
@Override
public void run() {
@ -250,7 +246,7 @@ public class SentinelConnectionManager extends MasterSlaveConnectionManager {
}, cfg.getScanInterval(), TimeUnit.MILLISECONDS);
}
protected void checkState(final SentinelServersConfig cfg, final Iterator<RedisClient> iterator, final AtomicReference<Throwable> lastException) {
private void checkState(final SentinelServersConfig cfg, final Iterator<RedisClient> iterator, final AtomicReference<Throwable> lastException) {
if (!iterator.hasNext()) {
log.error("Can't update cluster state", lastException.get());
scheduleChangeCheck(cfg, null);
@ -279,7 +275,7 @@ public class SentinelConnectionManager extends MasterSlaveConnectionManager {
}
protected void updateState(final SentinelServersConfig cfg, final RedisConnection connection, final Iterator<RedisClient> iterator) {
private void updateState(final SentinelServersConfig cfg, final RedisConnection connection, final Iterator<RedisClient> iterator) {
final AtomicInteger commands = new AtomicInteger(2);
FutureListener<Object> commonListener = new FutureListener<Object>() {
@ -350,7 +346,7 @@ public class SentinelConnectionManager extends MasterSlaveConnectionManager {
slaveDown(ip, port);
continue;
}
if (!isUseSameMaster(ip, port, masterHost, masterPort)) {
if (masterHost.equals("?") || !isUseSameMaster(ip, port, masterHost, masterPort)) {
continue;
}
@ -366,7 +362,6 @@ public class SentinelConnectionManager extends MasterSlaveConnectionManager {
Set<String> removedSlaves = new HashSet<String>(slaves);
removedSlaves.removeAll(currentSlaves);
for (String slave : removedSlaves) {
slaves.remove(slave);
String[] parts = slave.replace("redis://", "").split(":");
slaveDown(parts[0], parts[1]);
}
@ -434,92 +429,11 @@ public class SentinelConnectionManager extends MasterSlaveConnectionManager {
}
client = createClient(NodeType.SENTINEL, addr, c.getConnectTimeout(), c.getRetryInterval() * c.getRetryAttempts(), null);
RedisClient oldClient = sentinels.putIfAbsent(key, client);
if (oldClient != null) {
return RedissonPromise.newSucceededFuture(null);
}
RFuture<RedisPubSubConnection> pubsubFuture = client.connectPubSubAsync();
pubsubFuture.addListener(new FutureListener<RedisPubSubConnection>() {
@Override
public void operationComplete(Future<RedisPubSubConnection> future) throws Exception {
if (!future.isSuccess()) {
log.warn("Can't connect to sentinel: {}", addr);
return;
}
RedisPubSubConnection pubsub = future.getNow();
pubsub.addListener(new BaseRedisPubSubListener() {
@Override
public void onMessage(String channel, Object msg) {
log.debug("message {} from {}", msg, channel);
if ("+sentinel".equals(channel)) {
onSentinelAdded((String) msg, c);
}
if ("+slave".equals(channel)) {
onSlaveAdded(addr, (String) msg);
}
if ("+sdown".equals(channel)) {
onNodeDown(addr, (String) msg);
}
if ("-sdown".equals(channel)) {
onNodeUp(addr, (String) msg);
}
if ("+switch-master".equals(channel)) {
onMasterChange(addr, (String) msg);
}
}
@Override
public boolean onStatus(PubSubType type, String channel) {
if (type == PubSubType.SUBSCRIBE) {
log.debug("subscribed to channel: {} from Sentinel {}:{}", channel, addr.getHost(), addr.getPort());
}
return true;
}
});
pubsub.subscribe(StringCodec.INSTANCE, "+switch-master", "+sdown", "-sdown", "+slave", "+sentinel");
log.info("sentinel: {}:{} added", addr.getHost(), addr.getPort());
}
});
sentinels.putIfAbsent(key, client);
return RedissonPromise.newSucceededFuture(null);
}
protected void onSentinelAdded(String msg, MasterSlaveServersConfig c) {
String[] parts = msg.split(" ");
if ("sentinel".equals(parts[0])) {
String ip = parts[2];
String port = parts[3];
URI uri = convert(ip, port);
registerSentinel(uri, c);
}
}
protected void onSlaveAdded(URI addr, String msg) {
String[] parts = msg.split(" ");
if (parts.length > 4
&& "slave".equals(parts[0])) {
String ip = parts[2];
String port = parts[3];
if (!isUseSameMaster(parts)) {
return;
}
String slaveAddr = createAddress(ip, port);
addSlave(ip, port, slaveAddr);
} else {
log.warn("onSlaveAdded. Invalid message: {} from Sentinel {}:{}", msg, addr.getHost(), addr.getPort());
}
}
protected RFuture<Void> addSlave(final String ip, final String port, final String slaveAddr) {
private RFuture<Void> addSlave(final String ip, final String port, final String slaveAddr) {
final RPromise<Void> result = new RedissonPromise<Void>();
// to avoid addition twice
final MasterSlaveEntry entry = getEntry(singleSlotRange.getStartSlot());
@ -553,49 +467,12 @@ public class SentinelConnectionManager extends MasterSlaveConnectionManager {
return result;
}
protected URI convert(String ip, String port) {
private URI convert(String ip, String port) {
String addr = createAddress(ip, port);
URI uri = URIBuilder.create(addr);
return uri;
}
private void onNodeDown(URI sentinelAddr, String msg) {
String[] parts = msg.split(" ");
if (parts.length > 3) {
if ("slave".equals(parts[0])) {
String ip = parts[2];
String port = parts[3];
slaveDown(ip, port);
} else if ("sentinel".equals(parts[0])) {
String ip = parts[2];
String port = parts[3];
String addr = ip + ":" + port;
RedisClient sentinel = sentinels.remove(addr);
if (sentinel != null) {
sentinel.shutdownAsync();
log.warn("sentinel: {} has down", addr);
}
} else if ("master".equals(parts[0])) {
String ip = parts[2];
String port = parts[3];
// should be resolved by master switch event
//
// MasterSlaveEntry entry = getEntry(singleSlotRange.getStartSlot());
// if (entry.getFreezeReason() != FreezeReason.MANAGER) {
// entry.freeze();
// String addr = ip + ":" + port;
// log.warn("master: {} has down", addr);
// }
}
} else {
log.warn("onSlaveDown. Invalid message: {} from Sentinel {}:{}", msg, sentinelAddr.getHost(), sentinelAddr.getPort());
}
}
private void slaveDown(String ip, String port) {
if (config.checkSkipSlavesInit()) {
log.warn("slave: {}:{} has down", ip, port);
@ -608,11 +485,7 @@ public class SentinelConnectionManager extends MasterSlaveConnectionManager {
}
}
private boolean isUseSameMaster(String[] parts) {
return isUseSameMaster(parts[2], parts[3], parts[6], parts[7]);
}
protected boolean isUseSameMaster(String slaveIp, String slavePort, String slaveMasterHost, String slaveMasterPort) {
private boolean isUseSameMaster(String slaveIp, String slavePort, String slaveMasterHost, String slaveMasterPort) {
String master = currentMaster.get();
String slaveMaster = createAddress(slaveMasterHost, slaveMasterPort);
if (!master.equals(slaveMaster)) {
@ -622,37 +495,6 @@ public class SentinelConnectionManager extends MasterSlaveConnectionManager {
return true;
}
private void onNodeUp(URI addr, String msg) {
String[] parts = msg.split(" ");
if (parts.length > 3) {
if ("slave".equals(parts[0])) {
String ip = parts[2];
String port = parts[3];
if (!isUseSameMaster(parts)) {
return;
}
slaveUp(ip, port);
} else if ("master".equals(parts[0])) {
String ip = parts[2];
String port = parts[3];
URI uri = convert(ip, port);
MasterSlaveEntry entry = getEntry(singleSlotRange.getStartSlot());
if (entry.isFreezed()
&& URIBuilder.compare(entry.getClient().getAddr(), uri)) {
entry.unfreeze();
String masterAddr = ip + ":" + port;
log.info("master: {} has up", masterAddr);
}
} else {
log.warn("onSlaveUp. Invalid message: {} from Sentinel {}:{}", msg, addr.getHost(), addr.getPort());
}
}
}
private void slaveUp(String ip, String port) {
if (config.checkSkipSlavesInit()) {
String slaveAddr = ip + ":" + port;
@ -667,26 +509,6 @@ public class SentinelConnectionManager extends MasterSlaveConnectionManager {
}
}
private void onMasterChange(URI addr, String msg) {
String[] parts = msg.split(" ");
if (parts.length > 3) {
if (masterName.equals(parts[0])) {
String ip = parts[3];
String port = parts[4];
String current = currentMaster.get();
String newMaster = createAddress(ip, port);
if (!newMaster.equals(current)
&& currentMaster.compareAndSet(current, newMaster)) {
changeMaster(singleSlotRange.getStartSlot(), URIBuilder.create(newMaster));
}
}
} else {
log.warn("Invalid message: {} from Sentinel {}:{}", msg, addr.getHost(), addr.getPort());
}
}
@Override
protected MasterSlaveServersConfig create(BaseMasterSlaveServersConfig<?> cfg) {
MasterSlaveServersConfig res = super.create(cfg);

@ -15,6 +15,8 @@
*/
package org.redisson.connection;
import java.util.UUID;
import org.redisson.config.Config;
import org.redisson.config.MasterSlaveServersConfig;
import org.redisson.config.ReadMode;
@ -28,8 +30,8 @@ import org.redisson.config.SubscriptionMode;
*/
public class SingleConnectionManager extends MasterSlaveConnectionManager {
public SingleConnectionManager(SingleServerConfig cfg, Config config) {
super(create(cfg), config);
public SingleConnectionManager(SingleServerConfig cfg, Config config, UUID id) {
super(create(cfg), config, id);
}
private static MasterSlaveServersConfig create(SingleServerConfig cfg) {

@ -178,13 +178,13 @@ abstract class ConnectionPool<T extends RedisConnection> {
}
}
List<InetSocketAddress> failedAttempts = new LinkedList<InetSocketAddress>();
List<InetSocketAddress> failed = new LinkedList<InetSocketAddress>();
List<InetSocketAddress> freezed = new LinkedList<InetSocketAddress>();
for (ClientConnectionsEntry entry : entries) {
if (entry.isFreezed()) {
if (entry.isFailed()) {
failed.add(entry.getClient().getAddr());
} else if (entry.isFreezed()) {
freezed.add(entry.getClient().getAddr());
} else {
failedAttempts.add(entry.getClient().getAddr());
}
}
@ -192,8 +192,8 @@ abstract class ConnectionPool<T extends RedisConnection> {
if (!freezed.isEmpty()) {
errorMsg.append(" Disconnected hosts: " + freezed);
}
if (!failedAttempts.isEmpty()) {
errorMsg.append(" Hosts disconnected due to `failedAttempts` limit reached: " + failedAttempts);
if (!failed.isEmpty()) {
errorMsg.append(" Hosts disconnected due to errors during `failedSlaveCheckInterval`: " + failed);
}
RedisConnectionException exception = new RedisConnectionException(errorMsg.toString());

@ -598,7 +598,7 @@ public class JCache<K, V> extends RedissonObject implements Cache<K, V> {
args.add(System.currentTimeMillis());
encode(args, keys);
Map<K, V> res = evalWrite(getName(), codec, new RedisCommand<Map<Object, Object>>("EVAL", new MapGetAllDecoder(args, 2, true), ValueType.MAP_VALUE),
Map<K, V> res = evalWrite(getName(), codec, new RedisCommand<Map<Object, Object>>("EVAL", new MapGetAllDecoder(new ArrayList<Object>(keys), 0), ValueType.MAP_VALUE),
"local expireHead = redis.call('zrange', KEYS[2], 0, 0, 'withscores');"
+ "local accessTimeout = ARGV[1]; "
+ "local currentTime = tonumber(ARGV[2]); "

@ -12,6 +12,16 @@ public abstract class RedissonBaseMultimapCacheTest extends BaseTest {
abstract RMultimapCache<String, String> getMultimapCache(String name);
@Test
public void testRemoveAll() {
RMultimapCache<String, String> multimap = getMultimapCache("test");
multimap.put("1", "1");
multimap.put("1", "2");
multimap.removeAll("1");
assertThat(multimap.size()).isZero();
}
@Test
public void testContains() {
RMultimapCache<String, String> multimap = getMultimapCache("test");

@ -14,9 +14,21 @@ import org.junit.Assert;
import org.junit.Test;
import org.redisson.api.RFuture;
import org.redisson.api.RSortedSet;
import org.redisson.client.codec.LongCodec;
public class RedissonSortedSetTest extends BaseTest {
@Test
public void test1() {
RSortedSet<Long> set = redisson.getSortedSet("simple", LongCodec.INSTANCE);
set.add(2L);
set.add(0L);
set.add(1L);
set.add(5L);
assertThat(set.readAll()).containsExactly(0L, 1L, 2L, 5L);
}
@Test
public void testReadAll() {
RSortedSet<Integer> set = redisson.getSortedSet("simple");

@ -6,10 +6,13 @@ import static org.redisson.BaseTest.createInstance;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
@ -28,8 +31,12 @@ import org.redisson.RedisRunner.RedisProcess;
import org.redisson.api.ClusterNode;
import org.redisson.api.Node;
import org.redisson.api.Node.InfoSection;
import org.redisson.api.listener.MessageListener;
import org.redisson.api.listener.StatusListener;
import org.redisson.api.NodesGroup;
import org.redisson.api.RFuture;
import org.redisson.api.RMap;
import org.redisson.api.RTopic;
import org.redisson.api.RedissonClient;
import org.redisson.client.RedisClient;
import org.redisson.client.RedisConnectionException;
@ -39,6 +46,7 @@ import org.redisson.client.protocol.decoder.ScanObjectEntry;
import org.redisson.codec.SerializationCodec;
import org.redisson.config.Config;
import org.redisson.connection.ConnectionListener;
import org.redisson.connection.balancer.RandomLoadBalancer;
import org.redisson.misc.HashValue;
import io.netty.buffer.Unpooled;
@ -295,6 +303,127 @@ public class RedissonTest {
await().atMost(2, TimeUnit.SECONDS).until(() -> disconnectCounter.get() == 1);
}
@Test
public void testFailoverInSentinel() throws Exception {
RedisRunner.RedisProcess master = new RedisRunner()
.nosave()
.randomDir()
.run();
RedisRunner.RedisProcess slave1 = new RedisRunner()
.port(6380)
.nosave()
.randomDir()
.slaveof("127.0.0.1", 6379)
.run();
RedisRunner.RedisProcess slave2 = new RedisRunner()
.port(6381)
.nosave()
.randomDir()
.slaveof("127.0.0.1", 6379)
.run();
RedisRunner.RedisProcess sentinel1 = new RedisRunner()
.nosave()
.randomDir()
.port(26379)
.sentinel()
.sentinelMonitor("myMaster", "127.0.0.1", 6379, 2)
.run();
RedisRunner.RedisProcess sentinel2 = new RedisRunner()
.nosave()
.randomDir()
.port(26380)
.sentinel()
.sentinelMonitor("myMaster", "127.0.0.1", 6379, 2)
.run();
RedisRunner.RedisProcess sentinel3 = new RedisRunner()
.nosave()
.randomDir()
.port(26381)
.sentinel()
.sentinelMonitor("myMaster", "127.0.0.1", 6379, 2)
.run();
Thread.sleep(5000);
Config config = new Config();
config.useSentinelServers()
.setLoadBalancer(new RandomLoadBalancer())
.addSentinelAddress(sentinel3.getRedisServerAddressAndPort()).setMasterName("myMaster");
RedissonClient redisson = Redisson.create(config);
List<RFuture<?>> futures = new ArrayList<RFuture<?>>();
CountDownLatch latch = new CountDownLatch(1);
Thread t = new Thread() {
public void run() {
for (int i = 0; i < 1000; i++) {
RFuture<?> f1 = redisson.getBucket("i" + i).getAsync();
RFuture<?> f2 = redisson.getBucket("i" + i).setAsync("");
RFuture<?> f3 = redisson.getTopic("topic").publishAsync("testmsg");
futures.add(f1);
futures.add(f2);
futures.add(f3);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
latch.countDown();
};
};
t.start();
master.stop();
System.out.println("master " + master.getRedisServerAddressAndPort() + " stopped!");
Thread.sleep(TimeUnit.SECONDS.toMillis(70));
master = new RedisRunner()
.port(master.getRedisServerPort())
.nosave()
.randomDir()
.run();
System.out.println("master " + master.getRedisServerAddressAndPort() + " started!");
Thread.sleep(15000);
latch.await();
int errors = 0;
int success = 0;
int readonlyErrors = 0;
for (RFuture<?> rFuture : futures) {
rFuture.awaitUninterruptibly();
if (!rFuture.isSuccess()) {
System.out.println("cause " + rFuture.cause());
if (rFuture.cause().getMessage().contains("READONLY You can't write against")) {
readonlyErrors++;
}
errors++;
} else {
success++;
}
}
System.out.println("errors " + errors + " success " + success + " readonly " + readonlyErrors);
assertThat(errors).isLessThan(600);
assertThat(readonlyErrors).isZero();
redisson.shutdown();
sentinel1.stop();
sentinel2.stop();
sentinel3.stop();
master.stop();
slave1.stop();
slave2.stop();
}
@Test
public void testReconnection() throws IOException, InterruptedException, TimeoutException {
RedisProcess runner = new RedisRunner()

@ -8,6 +8,10 @@ import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@ -30,8 +34,6 @@ import org.redisson.RedisRunner;
import org.redisson.RedisRunner.FailedToStartRedisException;
import org.redisson.RedisRunner.RedisProcess;
import org.redisson.client.codec.JsonJacksonMapCodec;
import org.redisson.codec.JsonJacksonCodec;
import org.redisson.codec.SnappyCodec;
import org.redisson.config.Config;
import org.redisson.jcache.configuration.RedissonConfiguration;
@ -40,6 +42,35 @@ import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
public class JCacheTest extends BaseTest {
@Test
public void testGetAll() throws Exception {
RedisProcess runner = new RedisRunner()
.nosave()
.randomDir()
.port(6311)
.run();
URL configUrl = getClass().getResource("redisson-jcache.json");
Config cfg = Config.fromJSON(configUrl);
cfg.useSingleServer().setTimeout(300000);
Configuration<String, String> config = RedissonConfiguration.fromConfig(cfg);
Cache<String, String> cache = Caching.getCachingProvider().getCacheManager()
.createCache("test", config);
cache.put("1", "2");
cache.put("3", "4");
Map<String, String> entries = cache.getAll(new HashSet<String>(Arrays.asList("1", "3", "7")));
Map<String, String> expected = new HashMap<String, String>();
expected.put("1", "2");
expected.put("3", "4");
assertThat(entries).isEqualTo(expected);
cache.close();
runner.stop();
}
@Test
public void testJson() throws InterruptedException, IllegalArgumentException, URISyntaxException, IOException {
RedisProcess runner = new RedisRunner()
@ -64,7 +95,6 @@ public class JCacheTest extends BaseTest {
cache.close();
runner.stop();
}
@Test

Loading…
Cancel
Save