DATAREDIS-731 - Share native Lettuce Cluster connection across LettuceClusterConnection.

We now share Lettuce Cluster connections if configured on LettuceConnectionFactory (enabled by default) across multiple LettuceClusterConnections. Connection sharing prevents creation and disposal of cluster connections per template command execution which improves overall performance.

Original Pull Request: #297
This commit is contained in:
Mark Paluch
2017-12-18 10:13:14 +01:00
committed by Christoph Strobl
parent 09bd48c245
commit b656b09db5
5 changed files with 123 additions and 8 deletions

View File

@@ -24,13 +24,19 @@ import static org.springframework.data.redis.connection.ClusterTestVariables.*;
import static org.springframework.data.redis.test.util.MockitoUtils.*;
import io.lettuce.core.RedisURI;
import io.lettuce.core.api.StatefulConnection;
import io.lettuce.core.api.StatefulRedisConnection;
import io.lettuce.core.api.sync.RedisCommands;
import io.lettuce.core.cluster.RedisClusterClient;
import io.lettuce.core.cluster.api.StatefulRedisClusterConnection;
import io.lettuce.core.cluster.api.async.RedisClusterAsyncCommands;
import io.lettuce.core.cluster.api.sync.RedisAdvancedClusterCommands;
import io.lettuce.core.cluster.api.sync.RedisClusterCommands;
import io.lettuce.core.cluster.models.partitions.Partitions;
import io.lettuce.core.cluster.models.partitions.RedisClusterNode.NodeFlag;
import java.io.IOException;
import java.time.Duration;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@@ -62,7 +68,10 @@ public class LettuceClusterConnectionUnitTests {
@Mock RedisClusterClient clusterMock;
@Mock ClusterConnectionProvider connectionProviderMock;
@Mock ClusterCommandExecutor executorMock;
@Mock ClusterNodeResourceProvider resourceProvider;
@Mock StatefulRedisClusterConnection<byte[], byte[]> sharedConnectionMock;
@Mock RedisClusterAsyncCommands<byte[], byte[]> dedicatedConnectionMock;
@Mock RedisClusterCommands<byte[], byte[]> clusterConnection1Mock;
@Mock RedisClusterCommands<byte[], byte[]> clusterConnection2Mock;
@@ -346,4 +355,43 @@ public class LettuceClusterConnectionUnitTests {
verify(clusterConnection1Mock, never()).configResetstat();
}
@Test // DATAREDIS-731
public void shouldExecuteOnSharedConnection() {
RedisAdvancedClusterCommands<byte[], byte[]> sync = mock(RedisAdvancedClusterCommands.class);
when(connectionProviderMock.getClient()).thenReturn(clusterMock);
when(sharedConnectionMock.sync()).thenReturn(sync);
LettuceClusterConnection connection = new LettuceClusterConnection(sharedConnectionMock, connectionProviderMock,
executorMock, Duration.ZERO);
connection.keyCommands().del(KEY_1_BYTES);
verify(sync).del(KEY_1_BYTES);
verify(connectionProviderMock).getClient();
verifyNoMoreInteractions(connectionProviderMock);
}
@Test // DATAREDIS-731
public void shouldExecuteOnDedicatedConnection() {
RedisCommands<byte[], byte[]> sync = mock(RedisCommands.class);
StatefulRedisConnection<byte[], byte[]> dedicatedConnection = mock(StatefulRedisConnection.class);
when(connectionProviderMock.getClient()).thenReturn(clusterMock);
when(connectionProviderMock.getConnection(StatefulConnection.class)).thenReturn(dedicatedConnection);
when(dedicatedConnection.sync()).thenReturn(sync);
LettuceClusterConnection connection = new LettuceClusterConnection(sharedConnectionMock, connectionProviderMock,
executorMock, Duration.ZERO);
connection.listCommands().bLPop(1, KEY_1_BYTES);
verify(sync).blpop(1, KEY_1_BYTES);
verify(connectionProviderMock).getClient();
verify(connectionProviderMock).getConnection(StatefulConnection.class);
verifyNoMoreInteractions(connectionProviderMock);
verifyZeroInteractions(sharedConnectionMock);
}
}

View File

@@ -20,6 +20,7 @@ import static org.hamcrest.core.IsEqual.*;
import static org.hamcrest.core.IsInstanceOf.*;
import static org.hamcrest.core.IsNull.*;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import static org.springframework.data.redis.connection.ClusterTestVariables.*;
import static org.springframework.data.redis.connection.lettuce.LettuceTestClientResources.*;
import static org.springframework.test.util.ReflectionTestUtils.*;
@@ -29,6 +30,9 @@ import io.lettuce.core.ClientOptions;
import io.lettuce.core.RedisClient;
import io.lettuce.core.RedisURI;
import io.lettuce.core.cluster.RedisClusterClient;
import io.lettuce.core.cluster.api.StatefulRedisClusterConnection;
import io.lettuce.core.codec.ByteArrayCodec;
import io.lettuce.core.codec.RedisCodec;
import io.lettuce.core.resource.ClientResources;
import java.security.NoSuchAlgorithmException;
@@ -38,6 +42,8 @@ import java.util.Collections;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentMatchers;
import org.springframework.beans.DirectFieldAccessor;
import org.springframework.data.redis.ConnectionFactoryTracker;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.data.redis.connection.RedisClusterConnection;
@@ -552,6 +558,7 @@ public class LettuceConnectionFactoryUnitTests {
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(clusterConfig);
connectionFactory.setShutdownTimeout(0);
connectionFactory.setTimeout(2000);
connectionFactory.setShareNativeConnection(false);
connectionFactory.afterPropertiesSet();
ConnectionFactoryTracker.add(connectionFactory);
@@ -566,6 +573,7 @@ public class LettuceConnectionFactoryUnitTests {
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(clusterConfig, LettuceClientConfiguration
.builder().commandTimeout(Duration.ofSeconds(2)).shutdownTimeout(Duration.ZERO).build());
connectionFactory.setShareNativeConnection(false);
connectionFactory.afterPropertiesSet();
ConnectionFactoryTracker.add(connectionFactory);
@@ -575,4 +583,30 @@ public class LettuceConnectionFactoryUnitTests {
clusterConnection.close();
}
@Test // DATAREDIS-731
public void shouldShareNativeConnectionWithCluster() {
RedisClusterClient clientMock = mock(RedisClusterClient.class);
StatefulRedisClusterConnection<byte[], byte[]> connectionMock = mock(StatefulRedisClusterConnection.class);
when(clientMock.connect(ByteArrayCodec.INSTANCE)).thenReturn(connectionMock);
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(clusterConfig,
LettuceClientConfiguration.defaultConfiguration()) {
@Override
protected AbstractRedisClient createClient() {
return clientMock;
}
};
connectionFactory.afterPropertiesSet();
new DirectFieldAccessor(connectionFactory).setPropertyValue("client", clientMock);
connectionFactory.getClusterConnection().close();
connectionFactory.getClusterConnection().close();
verify(clientMock).connect(ArgumentMatchers.any(RedisCodec.class));
}
}