DATAREDIS-973 - Fix database selection using Lettuce.

We now correctly set the requested database using RedisURI so the driver performs the database selection. We no longer need to call select ourselves.

For shared connections (pooled and single shared connection) we now no longer call select. This can leave connections with a different database associated.

Original Pull Request: #451
This commit is contained in:
Mark Paluch
2019-05-20 16:51:48 +02:00
committed by Christoph Strobl
parent 37e558b16a
commit 06e368b430
3 changed files with 120 additions and 35 deletions

View File

@@ -25,9 +25,11 @@ import io.lettuce.core.ReadFrom;
import io.lettuce.core.RedisException;
import io.lettuce.core.api.async.RedisAsyncCommands;
import io.lettuce.core.api.reactive.BaseRedisReactiveCommands;
import reactor.test.StepVerifier;
import java.io.File;
import java.time.Duration;
import java.util.function.Consumer;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.junit.After;
@@ -35,14 +37,15 @@ import org.junit.AfterClass;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.springframework.data.redis.ConnectionFactoryTracker;
import org.springframework.data.redis.RedisConnectionFailureException;
import org.springframework.data.redis.RedisSystemException;
import org.springframework.data.redis.SettingsUtils;
import org.springframework.data.redis.connection.DefaultStringRedisConnection;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.RedisStaticMasterReplicaConfiguration;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.RedisStaticMasterReplicaConfiguration;
import org.springframework.data.redis.connection.StringRedisConnection;
/**
@@ -131,30 +134,88 @@ public class LettuceConnectionFactoryTests {
assertSame(connection.getNativeConnection(), conn2.getNativeConnection());
}
@Test
@Test // DATAREDIS-973
public void testSelectDb() {
LettuceConnectionFactory factory2 = new LettuceConnectionFactory(SettingsUtils.getHost(), SettingsUtils.getPort());
factory2.setClientResources(LettuceTestClientResources.getSharedClientResources());
factory2.setShutdownTimeout(0);
factory2.setDatabase(1);
factory2.afterPropertiesSet();
// put an item in database 0
connection.set("sometestkey", "sometestvalue");
LettuceConnectionFactory sharingConnectionFactory = newConnectionFactory(cf -> {});
runSelectDbTest(sharingConnectionFactory);
LettuceConnectionFactory nonSharingConnectionFactory = newConnectionFactory(
cf -> cf.setShareNativeConnection(false));
runSelectDbTest(nonSharingConnectionFactory);
}
private void runSelectDbTest(LettuceConnectionFactory factory2) {
ConnectionFactoryTracker.add(factory2);
StringRedisConnection connection2 = new DefaultStringRedisConnection(factory2.getConnection());
connection2.flushDb();
StringRedisConnection separateDatabase = new DefaultStringRedisConnection(factory2.getConnection());
separateDatabase.flushDb();
// put an item in database 0
connection.set("sometestkey", "sometestvalue");
try {
// there should still be nothing in database 1
assertEquals(Long.valueOf(0), connection2.dbSize());
assertEquals(Long.valueOf(0), separateDatabase.dbSize());
} finally {
connection2.close();
separateDatabase.close();
factory2.destroy();
}
}
@Test // DATAREDIS-973
public void testSelectDbReactive() {
LettuceConnectionFactory sharingConnectionFactory = newConnectionFactory(cf -> {});
runSelectDbReactiveTest(sharingConnectionFactory);
LettuceConnectionFactory nonSharingConnectionFactory = newConnectionFactory(
cf -> cf.setShareNativeConnection(false));
runSelectDbTest(nonSharingConnectionFactory);
}
private void runSelectDbReactiveTest(LettuceConnectionFactory factory2) {
ConnectionFactoryTracker.add(factory2);
LettuceReactiveRedisConnection separateDatabase = factory2.getReactiveConnection();
separateDatabase.serverCommands().flushDb() //
.as(StepVerifier::create) //
.expectNextCount(1) //
.verifyComplete();
// put an item in database 0
connection.set("sometestkey", "sometestvalue");
try {
// there should still be nothing in database 1
separateDatabase.serverCommands().dbSize() //
.as(StepVerifier::create).expectNext(0L) //
.verifyComplete();
} finally {
separateDatabase.close();
factory2.destroy();
}
}
private static LettuceConnectionFactory newConnectionFactory(Consumer<LettuceConnectionFactory> customizer) {
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(SettingsUtils.getHost(),
SettingsUtils.getPort());
connectionFactory.setClientResources(LettuceTestClientResources.getSharedClientResources());
connectionFactory.setShutdownTimeout(0);
connectionFactory.setDatabase(1);
customizer.accept(connectionFactory);
connectionFactory.afterPropertiesSet();
return connectionFactory;
}
@SuppressWarnings("unchecked")
@Test
public void testDisableSharedConnection() throws Exception {
@@ -394,11 +455,10 @@ public class LettuceConnectionFactoryTests {
LettuceClientConfiguration configuration = LettuceTestClientConfiguration.builder().readFrom(ReadFrom.SLAVE)
.build();
RedisStaticMasterReplicaConfiguration elastiCache = new RedisStaticMasterReplicaConfiguration(SettingsUtils.getHost())
.node(SettingsUtils.getHost(), SettingsUtils.getPort() + 1);
RedisStaticMasterReplicaConfiguration elastiCache = new RedisStaticMasterReplicaConfiguration(
SettingsUtils.getHost()).node(SettingsUtils.getHost(), SettingsUtils.getPort() + 1);
LettuceConnectionFactory factory = new LettuceConnectionFactory(elastiCache,
configuration);
LettuceConnectionFactory factory = new LettuceConnectionFactory(elastiCache, configuration);
factory.afterPropertiesSet();
RedisConnection connection = factory.getConnection();
@@ -422,8 +482,8 @@ public class LettuceConnectionFactoryTests {
LettuceClientConfiguration configuration = LettuceTestClientConfiguration.builder().readFrom(ReadFrom.MASTER)
.build();
RedisStaticMasterReplicaConfiguration elastiCache = new RedisStaticMasterReplicaConfiguration(SettingsUtils.getHost(),
SettingsUtils.getPort() + 1);
RedisStaticMasterReplicaConfiguration elastiCache = new RedisStaticMasterReplicaConfiguration(
SettingsUtils.getHost(), SettingsUtils.getPort() + 1);
LettuceConnectionFactory factory = new LettuceConnectionFactory(elastiCache, configuration);
factory.afterPropertiesSet();

View File

@@ -21,7 +21,9 @@ import static org.hamcrest.core.IsEqual.equalTo;
import static org.junit.Assert.*;
import io.lettuce.core.ReadFrom;
import reactor.test.StepVerifier;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@@ -34,6 +36,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import org.springframework.data.redis.ConnectionFactoryTracker;
import org.springframework.data.redis.connection.AbstractConnectionIntegrationTests;
import org.springframework.data.redis.connection.DefaultStringRedisConnection;
@@ -65,7 +68,7 @@ public class LettuceSentinelIntegrationTests extends AbstractConnectionIntegrati
static {
SENTINEL_CONFIG = new RedisSentinelConfiguration() //
.master(MASTER_NAME).sentinel(SENTINEL_0).sentinel(SENTINEL_1);
.master(MASTER_NAME).sentinel(SENTINEL_0).sentinel(SENTINEL_1);
SENTINEL_CONFIG.setDatabase(5);
}
@@ -129,12 +132,12 @@ public class LettuceSentinelIntegrationTests extends AbstractConnectionIntegrati
assertThat(servers.get(0).getName(), is(MASTER_NAME));
}
@Test // DATAREDIS-842
@Test // DATAREDIS-842, DATAREDIS-973
public void shouldUseSpecifiedDatabase() {
RedisConnection connection = connectionFactory.getConnection();
connection.flushDb();
connection.flushAll();
connection.set("foo".getBytes(), "bar".getBytes());
connection.close();
@@ -142,17 +145,45 @@ public class LettuceSentinelIntegrationTests extends AbstractConnectionIntegrati
connectionFactory.setClientResources(LettuceTestClientResources.getSharedClientResources());
connectionFactory.setShutdownTimeout(0);
connectionFactory.setShareNativeConnection(false);
connectionFactory.setDatabase(5);
connectionFactory.afterPropertiesSet();
RedisConnection directConnection = connectionFactory.getConnection();
assertThat(directConnection.exists("foo".getBytes()), is(false));
directConnection.select(5);
assertThat(directConnection.exists("foo".getBytes()), is(true));
directConnection.select(0);
assertThat(directConnection.exists("foo".getBytes()), is(false));
directConnection.close();
connectionFactory.destroy();
}
@Test // DATAREDIS-973
public void reactiveShouldUseSpecifiedDatabase() {
RedisConnection connection = connectionFactory.getConnection();
connection.flushAll();
connection.set("foo".getBytes(), "bar".getBytes());
connection.close();
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory();
connectionFactory.setClientResources(LettuceTestClientResources.getSharedClientResources());
connectionFactory.setShutdownTimeout(0);
connectionFactory.setShareNativeConnection(false);
connectionFactory.setDatabase(5);
connectionFactory.afterPropertiesSet();
LettuceReactiveRedisConnection reactiveConnection = connectionFactory.getReactiveConnection();
reactiveConnection.keyCommands().exists(ByteBuffer.wrap("foo".getBytes())) //
.as(StepVerifier::create) //
.expectNext(true) //
.verifyComplete();
reactiveConnection.close();
connectionFactory.destroy();
}
@Test // DATAREDIS-348
public void shouldReadSlavesOfMastersCorrectly() {
@@ -248,8 +279,7 @@ public class LettuceSentinelIntegrationTests extends AbstractConnectionIntegrati
LettuceClientConfiguration configuration = LettuceTestClientConfiguration.builder().readFrom(ReadFrom.SLAVE)
.build();
LettuceConnectionFactory factory = new LettuceConnectionFactory(SENTINEL_CONFIG,
configuration);
LettuceConnectionFactory factory = new LettuceConnectionFactory(SENTINEL_CONFIG, configuration);
factory.afterPropertiesSet();
RedisConnection connection = factory.getConnection();