Skip to content

Commit f9b3515

Browse files
prateek-kumar-improvingalexr-bq
authored andcommitted
Java: Update JedisPool implementation and add UnifiedJedis initial setup for cluster support (#4647)
* Java: Update JedisPool implementation Signed-off-by: Prateek Kumar <prateek.kumar@improving.com> Signed-off-by: Alex Rehnby-Martin <alex.rehnby-martin@improving.com>
1 parent 9b844f1 commit f9b3515

26 files changed

+3138
-1729
lines changed

java/client/src/main/java/module-info.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,12 @@
2222
exports redis.clients.jedis.resps;
2323
exports redis.clients.jedis.util;
2424

25+
// Open Jedis compatibility layer for reflection access in tests
26+
opens redis.clients.jedis to
27+
glide.integTest;
28+
2529
requires java.logging; // required by shadowed protobuf
30+
requires java.management; // required by Apache Commons Pool for JMX
2631
requires static lombok;
2732
requires org.apache.commons.lang3;
2833
requires org.apache.commons.pool2; // Required for Jedis compatibility layer

java/client/src/main/java/redis/clients/jedis/ClusterConfigurationMapper.java

Lines changed: 333 additions & 56 deletions
Large diffs are not rendered by default.
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/** Copyright Valkey GLIDE Project Contributors - SPDX Identifier: Apache-2.0 */
2+
package redis.clients.jedis;
3+
4+
import java.util.Set;
5+
6+
/** Connection provider for Valkey Cluster. This is part of the Jedis compatibility layer. */
7+
public class ClusterConnectionProvider implements ConnectionProvider {
8+
9+
private final Set<HostAndPort> nodes;
10+
private final JedisClientConfig clientConfig;
11+
12+
public ClusterConnectionProvider(Set<HostAndPort> nodes, JedisClientConfig clientConfig) {
13+
this.nodes = nodes;
14+
this.clientConfig = clientConfig;
15+
}
16+
17+
@Override
18+
public Connection getConnection() {
19+
// Return connection to first node for compatibility
20+
HostAndPort firstNode = nodes.iterator().next();
21+
return new Connection(firstNode);
22+
}
23+
24+
@Override
25+
public JedisClientConfig getClientConfig() {
26+
return clientConfig;
27+
}
28+
29+
/** Get all configured cluster nodes */
30+
public Set<HostAndPort> getNodes() {
31+
return nodes;
32+
}
33+
34+
@Override
35+
public void close() {
36+
// Implementation for closing cluster connections
37+
// No real connection to close since GLIDE manages them internally
38+
}
39+
}

java/client/src/main/java/redis/clients/jedis/ConfigurationMapper.java

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -276,21 +276,10 @@ private static void mapAdvancedSettings(
276276

277277
boolean hasAdvancedConfig = false;
278278

279-
// Connection timeout
280-
if (jedisConfig.getConnectionTimeoutMillis() != jedisConfig.getSocketTimeoutMillis()) {
279+
// Connection timeout - always map if specified
280+
if (jedisConfig.getConnectionTimeoutMillis() > 0) {
281281
advancedBuilder.connectionTimeout(jedisConfig.getConnectionTimeoutMillis());
282282
hasAdvancedConfig = true;
283-
284-
// Log warning about different timeouts
285-
if (jedisConfig.getConnectionTimeoutMillis() > 0
286-
&& jedisConfig.getSocketTimeoutMillis() > 0) {
287-
logger.warning(
288-
String.format(
289-
"Different connection (%dms) and socket (%dms) timeouts specified. GLIDE will use"
290-
+ " connection timeout for connection establishment and socket timeout for"
291-
+ " request timeout.",
292-
jedisConfig.getConnectionTimeoutMillis(), jedisConfig.getSocketTimeoutMillis()));
293-
}
294283
}
295284

296285
// Handle blocking socket timeout - warn about architectural difference
Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,34 @@
11
/** Copyright Valkey GLIDE Project Contributors - SPDX Identifier: Apache-2.0 */
22
package redis.clients.jedis;
33

4-
/** Connection compatibility stub for Valkey GLIDE wrapper. */
5-
public class Connection {
4+
import java.io.Closeable;
65

7-
public void close() {
8-
// Stub implementation
6+
/** Represents a connection to a server. This is part of the Jedis compatibility layer. */
7+
public class Connection implements Closeable {
8+
9+
private final HostAndPort hostAndPort;
10+
11+
public Connection(HostAndPort hostAndPort) {
12+
this.hostAndPort = hostAndPort;
913
}
1014

11-
public boolean isConnected() {
12-
return true;
15+
/** Get the host and port for this connection */
16+
public HostAndPort getHostAndPort() {
17+
return hostAndPort;
1318
}
1419

20+
/** Get the host */
1521
public String getHost() {
16-
return "localhost";
22+
return hostAndPort.getHost();
1723
}
1824

25+
/** Get the port */
1926
public int getPort() {
20-
return 6379;
27+
return hostAndPort.getPort();
28+
}
29+
30+
@Override
31+
public void close() {
32+
// Implementation for closing connection
2133
}
2234
}

java/client/src/main/java/redis/clients/jedis/ConnectionPool.java

Lines changed: 18 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,31 +3,28 @@
33

44
import redis.clients.jedis.util.Pool;
55

6-
/** ConnectionPool compatibility stub for Valkey GLIDE wrapper. */
6+
/**
7+
* ConnectionPool compatibility stub for Valkey GLIDE wrapper.
8+
*
9+
* @deprecated ConnectionPool is not supported in the GLIDE compatibility layer. Use JedisPool for
10+
* connection pooling instead. See <a
11+
* href="https://github.com/valkey-io/valkey-glide/blob/main/java/MIGRATION.md">Migration
12+
* guide</a> for more details.
13+
*/
14+
@Deprecated
715
public class ConnectionPool extends Pool<Connection> {
816

9-
@Override
10-
public Connection getResource() {
11-
return new Connection();
12-
}
13-
14-
@Override
15-
public void returnResource(Connection resource) {
16-
// Stub implementation
17-
}
18-
19-
@Override
20-
public void returnBrokenResource(Connection resource) {
21-
// Stub implementation
22-
}
23-
24-
@Override
25-
public void destroy() {
26-
// Stub implementation
17+
public ConnectionPool() {
18+
throw new UnsupportedOperationException(
19+
"ConnectionPool is not supported in GLIDE compatibility layer. GLIDE uses a different"
20+
+ " connection management architecture. Please use JedisPool for connection pooling"
21+
+ " instead. See migration guide:"
22+
+ " https://github.com/valkey-io/valkey-glide/blob/main/java/MIGRATION.md");
2723
}
2824

2925
@Override
30-
public boolean isClosed() {
31-
return false;
26+
public Connection getResource() {
27+
throw new UnsupportedOperationException(
28+
"ConnectionPool is not supported in GLIDE compatibility layer. Use JedisPool instead.");
3229
}
3330
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/** Copyright Valkey GLIDE Project Contributors - SPDX Identifier: Apache-2.0 */
2+
package redis.clients.jedis;
3+
4+
import java.io.Closeable;
5+
6+
/**
7+
* Interface for providing connections to Redis instances. This is part of the Jedis compatibility
8+
* layer.
9+
*/
10+
public interface ConnectionProvider extends Closeable {
11+
12+
/** Get a connection from the provider */
13+
Connection getConnection();
14+
15+
/** Get the client configuration */
16+
JedisClientConfig getClientConfig();
17+
18+
/** Close the provider and all its connections */
19+
@Override
20+
void close();
21+
}
Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
/** Copyright Valkey GLIDE Project Contributors - SPDX Identifier: Apache-2.0 */
2+
package redis.clients.jedis;
3+
4+
import glide.api.GlideClient;
5+
import glide.api.logging.Logger;
6+
import glide.api.models.configuration.GlideClientConfiguration;
7+
import java.util.concurrent.ExecutionException;
8+
import org.apache.commons.pool2.PooledObject;
9+
import org.apache.commons.pool2.PooledObjectFactory;
10+
import org.apache.commons.pool2.impl.DefaultPooledObject;
11+
import redis.clients.jedis.exceptions.JedisException;
12+
13+
/**
14+
* Factory for creating and managing Jedis instances backed by GLIDE clients in a connection pool.
15+
* This factory implements the Apache Commons Pool PooledObjectFactory interface to provide proper
16+
* connection lifecycle management.
17+
*/
18+
public class GlideJedisFactory implements PooledObjectFactory<Jedis> {
19+
20+
private final String host;
21+
private final int port;
22+
private final JedisClientConfig clientConfig;
23+
private JedisPool pool; // Pool reference set after factory creation
24+
25+
/**
26+
* Create a new factory for Jedis connections.
27+
*
28+
* @param host the Redis/Valkey server host
29+
* @param port the Redis/Valkey server port
30+
* @param clientConfig the client configuration
31+
*/
32+
public GlideJedisFactory(String host, int port, JedisClientConfig clientConfig) {
33+
this.host = host;
34+
this.port = port;
35+
this.clientConfig = clientConfig;
36+
this.pool = null; // Will be set later by JedisPool
37+
}
38+
39+
/**
40+
* Set the pool reference after factory creation. This is called by JedisPool after the factory is
41+
* created but before it's used.
42+
*
43+
* @param pool the JedisPool that owns this factory
44+
*/
45+
public void setPool(JedisPool pool) {
46+
this.pool = pool;
47+
}
48+
49+
@Override
50+
public PooledObject<Jedis> makeObject() throws Exception {
51+
try {
52+
// Map Jedis configuration to GLIDE configuration
53+
GlideClientConfiguration glideConfig =
54+
ConfigurationMapper.mapToGlideConfig(host, port, clientConfig);
55+
56+
// Create GLIDE client
57+
GlideClient glideClient = GlideClient.createClient(glideConfig).get();
58+
59+
// Use the direct constructor following original Jedis pattern
60+
// This constructor:
61+
// - Takes GlideClient directly (no lazy initialization needed)
62+
// - Sets isPooled = true
63+
// - Sets lazyInitialized = true
64+
// - Registers the resource immediately
65+
Jedis jedis = new Jedis(glideClient, clientConfig);
66+
67+
// Set the pool reference following original Jedis pattern
68+
if (pool != null) {
69+
jedis.setDataSource(pool);
70+
}
71+
72+
return new DefaultPooledObject<>(jedis);
73+
} catch (InterruptedException | ExecutionException e) {
74+
throw new JedisException("Failed to create Jedis connection", e);
75+
}
76+
}
77+
78+
@Override
79+
public void destroyObject(PooledObject<Jedis> pooledObject) throws Exception {
80+
Jedis jedis = pooledObject.getObject();
81+
if (jedis != null && !jedis.isClosed()) {
82+
try {
83+
jedis.close();
84+
} catch (Exception e) {
85+
// Log error but don't throw - we're in cleanup mode
86+
Logger.log(
87+
Logger.Level.WARN,
88+
"GlideJedisFactory",
89+
"Error closing Jedis connection during destroy",
90+
e);
91+
e.printStackTrace();
92+
}
93+
}
94+
}
95+
96+
@Override
97+
public boolean validateObject(PooledObject<Jedis> pooledObject) {
98+
Jedis jedis = pooledObject.getObject();
99+
if (jedis == null || jedis.isClosed()) {
100+
return false;
101+
}
102+
103+
try {
104+
// Use ping to validate connection
105+
String response = jedis.ping();
106+
return "PONG".equals(response);
107+
} catch (Exception e) {
108+
// Connection is not valid
109+
return false;
110+
}
111+
}
112+
113+
@Override
114+
public void activateObject(PooledObject<Jedis> pooledObject) throws Exception {
115+
// Reset any state when borrowing from pool
116+
Jedis jedis = pooledObject.getObject();
117+
if (jedis != null) {
118+
jedis.resetForReuse();
119+
}
120+
}
121+
122+
@Override
123+
public void passivateObject(PooledObject<Jedis> pooledObject) throws Exception {
124+
// Clean up state when returning to pool
125+
Jedis jedis = pooledObject.getObject();
126+
if (jedis != null) {
127+
// Reset any transaction or pipeline state
128+
jedis.resetForReuse();
129+
}
130+
}
131+
132+
/**
133+
* Get the host this factory connects to.
134+
*
135+
* @return the host
136+
*/
137+
public String getHost() {
138+
return host;
139+
}
140+
141+
/**
142+
* Get the port this factory connects to.
143+
*
144+
* @return the port
145+
*/
146+
public int getPort() {
147+
return port;
148+
}
149+
150+
/**
151+
* Get the client configuration used by this factory.
152+
*
153+
* @return the client configuration
154+
*/
155+
public JedisClientConfig getClientConfig() {
156+
return clientConfig;
157+
}
158+
159+
/**
160+
* Get the pool reference.
161+
*
162+
* @return the pool reference, or null if not set
163+
*/
164+
public JedisPool getPool() {
165+
return pool;
166+
}
167+
}

0 commit comments

Comments
 (0)