DATAREDIS-580 - Polishing.

Fix tests not closing connections properly. Remove usage of Optional in constructors, avoid recreating DirectFieldAccessor on every getConnection call and update documentation.

Original Pull Request: #287
This commit is contained in:
Christoph Strobl
2017-11-20 14:15:02 +01:00
parent b414fdf6f1
commit fe2bacda92
12 changed files with 145 additions and 38 deletions

View File

@@ -21,10 +21,12 @@ import io.lettuce.core.cluster.RedisClusterClient;
import io.lettuce.core.cluster.api.StatefulRedisClusterConnection;
import io.lettuce.core.codec.RedisCodec;
import io.lettuce.core.pubsub.StatefulRedisPubSubConnection;
import lombok.RequiredArgsConstructor;
import java.util.Optional;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* Connection provider for Cluster connections.
*
@@ -32,13 +34,40 @@ import java.util.Optional;
* @author Christoph Strobl
* @since 2.0
*/
@RequiredArgsConstructor
class ClusterConnectionProvider implements LettuceConnectionProvider {
private final RedisClusterClient client;
private final RedisCodec<?, ?> codec;
private final Optional<ReadFrom> readFrom;
/**
* Create new {@link ClusterConnectionProvider}.
*
* @param client must not be {@literal null}.
* @param codec must not be {@literal null}.
*/
ClusterConnectionProvider(RedisClusterClient client, RedisCodec<?, ?> codec) {
this(client, codec, null);
}
/**
* Create new {@link ClusterConnectionProvider}.
*
* @param client must not be {@literal null}.
* @param codec must not be {@literal null}.
* @param readFrom can be {@literal null}.
* @since 2.1
*/
ClusterConnectionProvider(RedisClusterClient client, RedisCodec<?, ?> codec, @Nullable ReadFrom readFrom) {
Assert.notNull(client, "Client must not be null!");
Assert.notNull(codec, "Codec must not be null!");
this.client = client;
this.codec = codec;
this.readFrom = Optional.ofNullable(readFrom);
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.lettuce.LettuceConnectionProvider#getConnection(java.lang.Class)

View File

@@ -95,7 +95,8 @@ class DefaultLettuceClientConfiguration implements LettuceClientConfiguration {
return clientResources;
}
/* (non-Javadoc)
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration#getClientOptions()
*/
@Override

View File

@@ -30,7 +30,6 @@ import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import org.apache.commons.logging.Log;
@@ -75,7 +74,7 @@ public class LettuceClusterConnection extends LettuceConnection implements Defau
* @param clusterClient must not be {@literal null}.
*/
public LettuceClusterConnection(RedisClusterClient clusterClient) {
this(new ClusterConnectionProvider(clusterClient, CODEC, Optional.empty()));
this(new ClusterConnectionProvider(clusterClient, CODEC));
}
/**
@@ -99,7 +98,7 @@ public class LettuceClusterConnection extends LettuceConnection implements Defau
* @since 2.0
*/
public LettuceClusterConnection(RedisClusterClient clusterClient, ClusterCommandExecutor executor, Duration timeout) {
this(new ClusterConnectionProvider(clusterClient, CODEC, Optional.empty()), executor, timeout);
this(new ClusterConnectionProvider(clusterClient, CODEC), executor, timeout);
}
/**

View File

@@ -49,7 +49,6 @@ import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Queue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Future;
@@ -225,7 +224,7 @@ public class LettuceConnection extends AbstractRedisConnection {
if (pool != null) {
this.connectionProvider = new LettucePoolConnectionProvider(pool);
} else {
this.connectionProvider = new StandaloneConnectionProvider((RedisClient) client, CODEC, Optional.empty());
this.connectionProvider = new StandaloneConnectionProvider((RedisClient) client, CODEC);
}
this.asyncSharedConn = sharedConnection;

View File

@@ -899,7 +899,7 @@ public class LettuceConnectionFactory
}
/**
* Create a {@link LettuceConnectionProvider } given {@link AbstractRedisClient} and {@link RedisCodec}. Configuration
* Create a {@link LettuceConnectionProvider} given {@link AbstractRedisClient} and {@link RedisCodec}. Configuration
* of this connection factory specifies the type of the created connection provider. This method creates either a
* {@link LettuceConnectionProvider} for either {@link RedisClient} or {@link RedisClusterClient}. Subclasses may
* override this method to decorate the connection provider.
@@ -909,10 +909,11 @@ public class LettuceConnectionFactory
* Reactive connections require a {@link java.nio.ByteBuffer} codec.
* @return the connection provider.
* @since 2.1
* @see io.lettuce.core.codec.ByteArrayCodec
* @see org.springframework.data.redis.connection.lettuce.LettuceReactiveRedisConnection.ByteBufferCodec
*/
protected LettuceConnectionProvider doCreateConnectionProvider(AbstractRedisClient client, RedisCodec<?, ?> codec) {Optional<ReadFrom> readFrom = getClientConfiguration().getReadFrom();
protected LettuceConnectionProvider doCreateConnectionProvider(AbstractRedisClient client, RedisCodec<?, ?> codec) {
ReadFrom readFrom = getClientConfiguration().getReadFrom().orElse(null);
if (isClusterAware()) {
return new ClusterConnectionProvider((RedisClusterClient) client, codec, readFrom);
}
@@ -1216,7 +1217,8 @@ public class LettuceConnectionFactory
return Optional.empty();
}
/* (non-Javadoc)
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration#getReadFrom()
*/
@Override

View File

@@ -19,29 +19,77 @@ import io.lettuce.core.ReadFrom;
import io.lettuce.core.RedisClient;
import io.lettuce.core.RedisURI;
import io.lettuce.core.api.StatefulConnection;
import io.lettuce.core.api.StatefulRedisConnection;
import io.lettuce.core.codec.RedisCodec;
import io.lettuce.core.masterslave.MasterSlave;
import io.lettuce.core.masterslave.StatefulRedisMasterSlaveConnection;
import io.lettuce.core.pubsub.StatefulRedisPubSubConnection;
import io.lettuce.core.sentinel.api.StatefulRedisSentinelConnection;
import lombok.RequiredArgsConstructor;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Supplier;
import org.springframework.beans.DirectFieldAccessor;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionProvider.TargetAware;
import org.springframework.lang.Nullable;
/**
* {@link LettuceConnectionProvider} implementation for a standalone Redis setup.
*
* @author Mark Paluch
* @author Christoph Strobl
* @since 2.0
*/
@RequiredArgsConstructor
class StandaloneConnectionProvider implements LettuceConnectionProvider, TargetAware {
private final RedisClient client;
private final RedisCodec<?, ?> codec;
private final Optional<ReadFrom> readFrom;
private final Supplier<RedisURI> redisURISupplier;
/**
* Create new {@link StandaloneConnectionProvider}.
*
* @param client must not be {@literal null}.
* @param codec must not be {@literal null}.
*/
StandaloneConnectionProvider(RedisClient client, RedisCodec<?, ?> codec) {
this(client, codec, null);
}
/**
* Create new {@link StandaloneConnectionProvider}.
*
* @param client must not be {@literal null}.
* @param codec must not be {@literal null}.
* @param readFrom can be {@literal null}.
* @since 2.1
*/
StandaloneConnectionProvider(RedisClient client, RedisCodec<?, ?> codec, @Nullable ReadFrom readFrom) {
this.client = client;
this.codec = codec;
this.readFrom = Optional.ofNullable(readFrom);
redisURISupplier = new Supplier<RedisURI>() {
AtomicReference<RedisURI> uriFieldReference = new AtomicReference();
@Override
public RedisURI get() {
RedisURI uri = uriFieldReference.get();
if (uri != null) {
return uri;
}
uri = RedisURI.class.cast(new DirectFieldAccessor(client).getPropertyValue("redisURI"));
return uriFieldReference.compareAndSet(null, uri) ? uri : uriFieldReference.get();
}
};
}
/*
* (non-Javadoc)
@@ -61,16 +109,8 @@ class StandaloneConnectionProvider implements LettuceConnectionProvider, TargetA
if (StatefulConnection.class.isAssignableFrom(connectionType)) {
return readFrom.map(it -> {
DirectFieldAccessor fieldAccessor = new DirectFieldAccessor(client);
RedisURI redisURI = RedisURI.class.cast(fieldAccessor.getPropertyValue("redisURI"));
StatefulRedisMasterSlaveConnection<?, ?> connection = MasterSlave.connect(client, codec, redisURI);
connection.setReadFrom(it);
return connectionType.cast(connection);
}).orElseGet(() -> connectionType.cast(client.connect(codec)));
return connectionType.cast(readFrom.map(it -> this.masterSlaveConnection(redisURISupplier.get(), it))
.orElseGet(() -> client.connect(codec)));
}
throw new UnsupportedOperationException("Connection type " + connectionType + " not supported!");
@@ -93,9 +133,20 @@ class StandaloneConnectionProvider implements LettuceConnectionProvider, TargetA
}
if (StatefulConnection.class.isAssignableFrom(connectionType)) {
return connectionType.cast(client.connect(codec, redisURI));
return connectionType
.cast(readFrom.map(it -> this.masterSlaveConnection(redisURI, it)).orElseGet(() -> client.connect(codec)));
}
throw new UnsupportedOperationException("Connection type " + connectionType + " not supported!");
}
private StatefulRedisConnection masterSlaveConnection(RedisURI redisUri, ReadFrom readFrom) {
StatefulRedisMasterSlaveConnection<?, ?> connection = MasterSlave.connect(client, codec, redisUri);
connection.setReadFrom(readFrom);
return connection;
}
}