Skip to content

Commit ebccfca

Browse files
committed
DATAREDIS-462 - Support lettuce ClientResources.
Add ClientResources to LettuceConnectionFactory. Add TestClientResources for managed resources during tests and reuse ClientResources as much as possible in tests.
1 parent bc3e5cd commit ebccfca

26 files changed

+410
-32
lines changed

src/main/java/org/springframework/data/redis/connection/lettuce/DefaultLettucePool.java

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2013-2015 the original author or authors.
2+
* Copyright 2013-2016 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -17,6 +17,7 @@
1717

1818
import java.util.concurrent.TimeUnit;
1919

20+
import com.lambdaworks.redis.resource.ClientResources;
2021
import org.apache.commons.pool2.BasePooledObjectFactory;
2122
import org.apache.commons.pool2.PooledObject;
2223
import org.apache.commons.pool2.impl.DefaultPooledObject;
@@ -50,6 +51,7 @@ public class DefaultLettucePool implements LettucePool, InitializingBean {
5051
private String password;
5152
private long timeout = TimeUnit.MILLISECONDS.convert(60, TimeUnit.SECONDS);
5253
private RedisSentinelConfiguration sentinelConfiguration;
54+
private ClientResources clientResources;
5355

5456
/**
5557
* Constructs a new <code>DefaultLettucePool</code> instance with default settings.
@@ -101,7 +103,14 @@ public boolean isRedisSentinelAware() {
101103

102104
@SuppressWarnings({ "rawtypes" })
103105
public void afterPropertiesSet() {
104-
this.client = new RedisClient(getRedisURI());
106+
107+
if(clientResources != null) {
108+
this.client = RedisClient.create(clientResources, getRedisURI());
109+
}
110+
else {
111+
this.client = RedisClient.create(getRedisURI());
112+
}
113+
105114
client.setDefaultTimeout(timeout, TimeUnit.MILLISECONDS);
106115
this.internalPool = new GenericObjectPool<RedisAsyncConnection>(new LettuceFactory(client, dbIndex), poolConfig);
107116
}
@@ -273,6 +282,24 @@ public void setTimeout(long timeout) {
273282
this.timeout = timeout;
274283
}
275284

285+
/**
286+
* Returns the client resources to reuse the client infrastructure.
287+
* @return client resources
288+
* @since 1.7
289+
*/
290+
public ClientResources getClientResources() {
291+
return clientResources;
292+
}
293+
294+
/**
295+
* Sets the client resources to reuse the client infrastructure.
296+
* @param clientResources
297+
* @since 1.7
298+
*/
299+
public void setClientResources(ClientResources clientResources) {
300+
this.clientResources = clientResources;
301+
}
302+
276303
@SuppressWarnings("rawtypes")
277304
private static class LettuceFactory extends BasePooledObjectFactory<RedisAsyncConnection> {
278305

src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactory.java

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import java.util.List;
2121
import java.util.concurrent.TimeUnit;
2222

23+
import com.lambdaworks.redis.resource.ClientResources;
2324
import org.apache.commons.logging.Log;
2425
import org.apache.commons.logging.LogFactory;
2526
import org.springframework.beans.factory.DisposableBean;
@@ -94,6 +95,7 @@ public class LettuceConnectionFactory implements InitializingBean, DisposableBea
9495
private RedisSentinelConfiguration sentinelConfiguration;
9596
private RedisClusterConfiguration clusterConfiguration;
9697
private ClusterCommandExecutor clusterCommandExecutor;
98+
private ClientResources clientResources;
9799

98100
/**
99101
* Constructs a new <code>LettuceConnectionFactory</code> instance with default settings.
@@ -377,6 +379,24 @@ public void setPassword(String password) {
377379
this.password = password;
378380
}
379381

382+
/**
383+
* Returns the client resources to reuse the client infrastructure.
384+
* @return client resources
385+
* @since 1.7
386+
*/
387+
public ClientResources getClientResources() {
388+
return clientResources;
389+
}
390+
391+
/**
392+
* Sets the client resources to reuse the client infrastructure.
393+
* @param clientResources
394+
* @since 1.7
395+
*/
396+
public void setClientResources(ClientResources clientResources) {
397+
this.clientResources = clientResources;
398+
}
399+
380400
/**
381401
* Returns the shutdown timeout for shutting down the RedisClient (in milliseconds).
382402
*
@@ -458,7 +478,11 @@ private AbstractRedisClient createRedisClient() {
458478

459479
if (isRedisSentinelAware()) {
460480
RedisURI redisURI = getSentinelRedisURI();
461-
return new RedisClient(redisURI);
481+
if(clientResources == null) {
482+
return RedisClient.create(redisURI);
483+
}
484+
485+
return RedisClient.create(clientResources, redisURI);
462486
}
463487

464488
if (isClusterAware()) {
@@ -475,7 +499,13 @@ private AbstractRedisClient createRedisClient() {
475499
initialUris.add(redisURI);
476500
}
477501

478-
RedisClusterClient clusterClient = new RedisClusterClient(initialUris);
502+
RedisClusterClient clusterClient;
503+
if(clientResources == null) {
504+
clusterClient = RedisClusterClient.create(initialUris);
505+
}
506+
else {
507+
clusterClient = RedisClusterClient.create(clientResources, initialUris);
508+
}
479509

480510
this.clusterCommandExecutor = new ClusterCommandExecutor(
481511
new LettuceClusterConnection.LettuceClusterTopologyProvider(clusterClient),
@@ -493,8 +523,11 @@ private AbstractRedisClient createRedisClient() {
493523
builder.withPassword(password);
494524
}
495525
builder.withTimeout(timeout, TimeUnit.MILLISECONDS);
496-
RedisClient client = new RedisClient(builder.build());
497-
return client;
526+
if(clientResources != null) {
527+
return RedisClient.create(clientResources, builder.build());
528+
}
529+
530+
return RedisClient.create(builder.build());
498531
}
499532

500533
private RedisURI getSentinelRedisURI() {

src/main/java/org/springframework/data/redis/connection/lettuce/LettuceSentinelConnection.java

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2014 the original author or authors.
2+
* Copyright 2014-2016 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -20,6 +20,8 @@
2020

2121
import com.lambdaworks.redis.RedisClient;
2222
import com.lambdaworks.redis.RedisSentinelAsyncConnection;
23+
import com.lambdaworks.redis.RedisURI;
24+
import com.lambdaworks.redis.resource.ClientResources;
2325
import org.springframework.data.redis.ExceptionTranslationStrategy;
2426
import org.springframework.data.redis.FallbackExceptionTranslationStrategy;
2527
import org.springframework.data.redis.connection.NamedNode;
@@ -51,12 +53,26 @@ public LettuceSentinelConnection(RedisNode sentinel) {
5153

5254
/**
5355
* Creates a {@link LettuceSentinelConnection} with a client for the supplied {@code host} and {@code port}.
54-
* @param host hostname
56+
* @param host hostname must not be {@literal null}
5557
* @param port sentinel port
5658
*/
5759
public LettuceSentinelConnection(String host, int port) {
58-
Assert.notNull(host, "Cannot created LettuceSentinelConnection using 'null' as host.");
59-
redisClient = new RedisClient(host, port);
60+
Assert.notNull(host, "Cannot create LettuceSentinelConnection using 'null' as host.");
61+
redisClient = RedisClient.create(new RedisURI.Builder().redis(host, port).build());
62+
init();
63+
}
64+
65+
/**
66+
* Creates a {@link LettuceSentinelConnection} with a client for the supplied {@code host} and {@code port} and reuse
67+
* existing {@code clientResources}.
68+
* @param clientResources must not be {@literal null}
69+
* @param host hostname must not be {@literal null}
70+
* @param port sentinel port
71+
*/
72+
public LettuceSentinelConnection(ClientResources clientResources, String host, int port) {
73+
Assert.notNull(clientResources, "Cannot create LettuceSentinelConnection using 'null' as ClientResources.");
74+
Assert.notNull(host, "Cannot create LettuceSentinelConnection using 'null' as host.");
75+
redisClient = RedisClient.create(clientResources, new RedisURI.Builder().redis(host, port).build());
6076
init();
6177
}
6278

src/test/java/org/springframework/data/redis/connection/lettuce/DefaultLettucePoolTests.java

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2013-2014 the original author or authors.
2+
* Copyright 2013-2016 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -57,6 +57,7 @@ public void tearDown() {
5757
@Test
5858
public void testGetResource() {
5959
this.pool = new DefaultLettucePool(SettingsUtils.getHost(), SettingsUtils.getPort());
60+
this.pool.setClientResources(TestClientResources.get());
6061
pool.afterPropertiesSet();
6162
RedisAsyncConnection<byte[], byte[]> client = pool.getResource();
6263
assertNotNull(client);
@@ -70,6 +71,7 @@ public void testGetResourcePoolExhausted() {
7071
poolConfig.setMaxTotal(1);
7172
poolConfig.setMaxWaitMillis(1);
7273
this.pool = new DefaultLettucePool(SettingsUtils.getHost(), SettingsUtils.getPort(), poolConfig);
74+
this.pool.setClientResources(TestClientResources.get());
7375
pool.afterPropertiesSet();
7476
RedisAsyncConnection<byte[], byte[]> client = pool.getResource();
7577
assertNotNull(client);
@@ -86,6 +88,7 @@ public void testGetResourceValidate() {
8688
PoolConfig poolConfig = new PoolConfig();
8789
poolConfig.setTestOnBorrow(true);
8890
this.pool = new DefaultLettucePool(SettingsUtils.getHost(), SettingsUtils.getPort(), poolConfig);
91+
this.pool.setClientResources(TestClientResources.get());
8992
pool.afterPropertiesSet();
9093
RedisAsyncConnection<byte[], byte[]> client = pool.getResource();
9194
assertNotNull(client);
@@ -95,6 +98,7 @@ public void testGetResourceValidate() {
9598
@Test(expected = PoolException.class)
9699
public void testGetResourceCreationUnsuccessful() throws Exception {
97100
this.pool = new DefaultLettucePool(SettingsUtils.getHost(), 3333);
101+
this.pool.setClientResources(TestClientResources.get());
98102
pool.afterPropertiesSet();
99103
pool.getResource();
100104
}
@@ -105,6 +109,7 @@ public void testReturnResource() {
105109
poolConfig.setMaxTotal(1);
106110
poolConfig.setMaxWaitMillis(1);
107111
this.pool = new DefaultLettucePool(SettingsUtils.getHost(), SettingsUtils.getPort(), poolConfig);
112+
this.pool.setClientResources(TestClientResources.get());
108113
pool.afterPropertiesSet();
109114
RedisAsyncConnection<byte[], byte[]> client = pool.getResource();
110115
assertNotNull(client);
@@ -119,6 +124,7 @@ public void testReturnBrokenResource() {
119124
poolConfig.setMaxTotal(1);
120125
poolConfig.setMaxWaitMillis(1);
121126
this.pool = new DefaultLettucePool(SettingsUtils.getHost(), SettingsUtils.getPort(), poolConfig);
127+
this.pool.setClientResources(TestClientResources.get());
122128
pool.afterPropertiesSet();
123129
RedisAsyncConnection<byte[], byte[]> client = pool.getResource();
124130
assertNotNull(client);
@@ -136,6 +142,18 @@ public void testReturnBrokenResource() {
136142

137143
@Test
138144
public void testCreateWithDbIndex() {
145+
this.pool = new DefaultLettucePool(SettingsUtils.getHost(), SettingsUtils.getPort());
146+
this.pool.setClientResources(TestClientResources.get());
147+
pool.setDatabase(1);
148+
pool.afterPropertiesSet();
149+
assertNotNull(pool.getResource());
150+
}
151+
152+
/**
153+
* @see DATAREDIS-462
154+
*/
155+
@Test
156+
public void poolWorksWithoutClientResources() {
139157
this.pool = new DefaultLettucePool(SettingsUtils.getHost(), SettingsUtils.getPort());
140158
pool.setDatabase(1);
141159
pool.afterPropertiesSet();
@@ -145,6 +163,7 @@ public void testCreateWithDbIndex() {
145163
@Test(expected = PoolException.class)
146164
public void testCreateWithDbIndexInvalid() {
147165
this.pool = new DefaultLettucePool(SettingsUtils.getHost(), SettingsUtils.getPort());
166+
this.pool.setClientResources(TestClientResources.get());
148167
pool.setDatabase(17);
149168
pool.afterPropertiesSet();
150169
pool.getResource();
@@ -153,6 +172,7 @@ public void testCreateWithDbIndexInvalid() {
153172
@Test(expected = PoolException.class)
154173
public void testCreateWithPasswordNoPassword() {
155174
this.pool = new DefaultLettucePool(SettingsUtils.getHost(), SettingsUtils.getPort());
175+
this.pool.setClientResources(TestClientResources.get());
156176
pool.setPassword("notthepassword");
157177
pool.afterPropertiesSet();
158178
pool.getResource();
@@ -162,6 +182,7 @@ public void testCreateWithPasswordNoPassword() {
162182
@Test
163183
public void testCreatePassword() {
164184
this.pool = new DefaultLettucePool(SettingsUtils.getHost(), SettingsUtils.getPort());
185+
this.pool.setClientResources(TestClientResources.get());
165186
pool.setPassword("foo");
166187
pool.afterPropertiesSet();
167188
RedisAsyncConnection<byte[], byte[]> conn = pool.getResource();
@@ -173,6 +194,7 @@ public void testCreatePassword() {
173194
@Test(expected = PoolException.class)
174195
public void testCreateInvalidPassword() {
175196
this.pool = new DefaultLettucePool(SettingsUtils.getHost(), SettingsUtils.getPort());
197+
this.pool.setClientResources(TestClientResources.get());
176198
pool.setPassword("bad");
177199
pool.afterPropertiesSet();
178200
pool.getResource();

src/test/java/org/springframework/data/redis/connection/lettuce/LettuceClusterConnectionTests.java

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2015 the original author or authors.
2+
* Copyright 2015-2016 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -15,9 +15,29 @@
1515
*/
1616
package org.springframework.data.redis.connection.lettuce;
1717

18-
import static org.hamcrest.CoreMatchers.*;
19-
import static org.junit.Assert.*;
20-
import static org.springframework.data.redis.connection.ClusterTestVariables.*;
18+
import static org.hamcrest.CoreMatchers.endsWith;
19+
import static org.hamcrest.CoreMatchers.hasItem;
20+
import static org.hamcrest.CoreMatchers.hasItems;
21+
import static org.hamcrest.CoreMatchers.is;
22+
import static org.hamcrest.CoreMatchers.not;
23+
import static org.hamcrest.CoreMatchers.notNullValue;
24+
import static org.hamcrest.CoreMatchers.nullValue;
25+
import static org.hamcrest.CoreMatchers.startsWith;
26+
import static org.junit.Assert.assertThat;
27+
import static org.springframework.data.redis.connection.ClusterTestVariables.CLUSTER_HOST;
28+
import static org.springframework.data.redis.connection.ClusterTestVariables.KEY_1;
29+
import static org.springframework.data.redis.connection.ClusterTestVariables.KEY_2;
30+
import static org.springframework.data.redis.connection.ClusterTestVariables.KEY_3;
31+
import static org.springframework.data.redis.connection.ClusterTestVariables.MASTER_NODE_1_PORT;
32+
import static org.springframework.data.redis.connection.ClusterTestVariables.MASTER_NODE_2_PORT;
33+
import static org.springframework.data.redis.connection.ClusterTestVariables.MASTER_NODE_3_PORT;
34+
import static org.springframework.data.redis.connection.ClusterTestVariables.SAME_SLOT_KEY_1;
35+
import static org.springframework.data.redis.connection.ClusterTestVariables.SAME_SLOT_KEY_2;
36+
import static org.springframework.data.redis.connection.ClusterTestVariables.SAME_SLOT_KEY_3;
37+
import static org.springframework.data.redis.connection.ClusterTestVariables.SLAVEOF_NODE_1_PORT;
38+
import static org.springframework.data.redis.connection.ClusterTestVariables.VALUE_1;
39+
import static org.springframework.data.redis.connection.ClusterTestVariables.VALUE_2;
40+
import static org.springframework.data.redis.connection.ClusterTestVariables.VALUE_3;
2141

2242
import java.util.Collection;
2343
import java.util.Collections;
@@ -82,8 +102,8 @@ public class LettuceClusterConnectionTests implements ClusterConnectionTests {
82102
@Before
83103
public void setUp() {
84104

85-
client = new RedisClusterClient(Builder.redis(CLUSTER_HOST, MASTER_NODE_1_PORT)
86-
.withTimeout(100, TimeUnit.MILLISECONDS).build());
105+
client = RedisClusterClient.create(TestClientResources.get(),
106+
Builder.redis(CLUSTER_HOST, MASTER_NODE_1_PORT).withTimeout(100, TimeUnit.MILLISECONDS).build());
87107
nativeConnection = client.connectCluster();
88108
clusterConnection = new LettuceClusterConnection(client);
89109
}

0 commit comments

Comments
 (0)