Skip to content

Commit 91890d0

Browse files
authored
Java: Multi-Database Support for Cluster Mode Valkey 9.0 (#4658)
* - Implement database selection for cluster clients when database_id != 0 - Send SELECT command to all cluster nodes using MultiNode routing - Add comprehensive error handling with clear error messages - Include test for database selection error handling in cluster mode - Support backward compatibility with servers that don't support multi-db cluster mode - Enable cluster-databases=16 for Valkey 9.0+ in cluster manager This enables cluster clients to work with non-default databases on Valkey 9.0+ servers configured with cluster-databases support, while gracefully handling older servers that don't support this feature. Signed-off-by: affonsov <67347924+affonsov@users.noreply.github.com> * update valkey9 multi db tests Signed-off-by: affonsov <67347924+affonsov@users.noreply.github.com> * fix lint Signed-off-by: affonsov <67347924+affonsov@users.noreply.github.com> * fixing valkey 9 cluster tests Signed-off-by: affonsov <67347924+affonsov@users.noreply.github.com> * add to route to all nodes in the core Signed-off-by: affonsov <67347924+affonsov@users.noreply.github.com> * rust lint fix Signed-off-by: affonsov <67347924+affonsov@users.noreply.github.com> * implement database selection in cluster mode via connection parameters - Add database_id field to ClusterParams and BuilderParams structs - Add database() method to ClusterClientBuilder for setting database ID - Pass database_id through connection info instead of post-connection SELECT - Remove SELECT command from cluster routing - Remove post-connection SELECT command logic from create_cluster_client - Add comprehensive tests for database isolation and reconnection behavior - Verify database ID persistence across node reconnections - Test multi-database cluster support with proper isolation verification This change moves database selection from a post-connection SELECT command to a connection parameter, which is more reliable for cluster mode and handles reconnections automatically. The approach works with servers that support multi-database cluster configurations (like Valkey 9.0+). Signed-off-by: affonsov <67347924+affonsov@users.noreply.github.com> * add valkey9 constraint in the core tests Signed-off-by: affonsov <67347924+affonsov@users.noreply.github.com> * fix core test not skipping test when version was lower than valkey 9 Signed-off-by: affonsov <67347924+affonsov@users.noreply.github.com> * Fix version check Signed-off-by: affonsov <67347924+affonsov@users.noreply.github.com> * refactored test test_set_database_id_after_reconnection to be similar from standalone removed is_valkey_9_or_higher Signed-off-by: affonsov <67347924+affonsov@users.noreply.github.com> * removed tests and cleanup Signed-off-by: affonsov <67347924+affonsov@users.noreply.github.com> * renamed builder.database to builder.database_id Signed-off-by: affonsov <67347924+affonsov@users.noreply.github.com> * Java: implement multi-database support for cluster mode - Move databaseId from GlideClientConfiguration to BaseClientConfiguration - Add databaseId validation and protobuf integration - Update SELECT command with AllNodes routing and reconnection warnings - Add connection management for database selection after auth - Add comprehensive tests with Valkey 9+ version guards Completes Java client implementation for Valkey 9 cluster multi-database support. Signed-off-by: affonsov <67347924+affonsov@users.noreply.github.com> * fixing database id restriction Signed-off-by: affonsov <67347924+affonsov@users.noreply.github.com> * fixed java test error select_command_invalid_database_standalone Signed-off-by: affonsov <67347924+affonsov@users.noreply.github.com> * fixed lint errors Signed-off-by: affonsov <67347924+affonsov@users.noreply.github.com> * Refactored select command to route to all nodes per default Removed the option to provide a route Signed-off-by: affonsov <67347924+affonsov@users.noreply.github.com> * java lint fix Signed-off-by: affonsov <67347924+affonsov@users.noreply.github.com> * java: Remove SELECT command from cluster client - Remove select() method from GlideClusterClient and ConnectionManagementClusterCommands interface - Delete MultiDatabaseTests.java which tested SELECT command functionality - Remove SELECT command tests from SharedCommandTests.java - Add focused test for cluster database_id configuration in ClusterClientTests - Remove SELECT import from GlideClusterClient The SELECT command is being removed from the cluster client API as database selection should be handled through client configuration (databaseId parameter) rather than runtime commands, which provides better consistency and avoids reconnection issues. Signed-off-by: affonsov <67347924+affonsov@users.noreply.github.com> * remove database_id validatation and simplified tests Signed-off-by: affonsov <67347924+affonsov@users.noreply.github.com> * added changelog Signed-off-by: affonsov <67347924+affonsov@users.noreply.github.com> * fix documentation Signed-off-by: affonsov <67347924+affonsov@users.noreply.github.com> * fix databaseId documentation Signed-off-by: affonsov <67347924+affonsov@users.noreply.github.com> --------- Signed-off-by: affonsov <67347924+affonsov@users.noreply.github.com>
1 parent b9c031d commit 91890d0

File tree

7 files changed

+105
-7
lines changed

7 files changed

+105
-7
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
* JAVA: Valkey 9 new commands HASH items expiration ([#4556](https://github.com/valkey-io/valkey-glide/pull/4556))
77
* NODE: Valkey 9 support - Add Hash Field Expiration Commands Support ([#4598](https://github.com/valkey-io/valkey-glide/pull/4598))
88
* Python: Valkey 9 new hash field expiration commands ([#4610](https://github.com/valkey-io/valkey-glide/pull/4610))
9+
* Java: Multi-Database Support for Cluster Mode Valkey 9.0 ([#4658](https://github.com/valkey-io/valkey-glide/pull/4658))
910
* Go: Add Multi-Database Support for Cluster Mode Valkey 9.0 ([#4660](https://github.com/valkey-io/valkey-glide/pull/4660))
1011
* Python: Add Multi-Database Support for Cluster Mode Valkey 9.0 ([#4659](https://github.com/valkey-io/valkey-glide/pull/4659))
1112

java/client/src/main/java/glide/api/commands/ConnectionManagementCommands.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,23 @@ public interface ConnectionManagementCommands {
110110
/**
111111
* Changes the currently selected database.
112112
*
113+
* <p><b>WARNING:</b> This command is <b>NOT RECOMMENDED</b> for production use. Upon
114+
* reconnection, the client will revert to the database_id specified in the client configuration
115+
* (default: 0), NOT the database selected via this command.
116+
*
117+
* <p><b>RECOMMENDED APPROACH:</b> Use the database_id parameter in client configuration instead:
118+
*
119+
* <p><b>RECOMMENDED EXAMPLE:</b>
120+
*
121+
* <pre>{@code
122+
* GlideClient client = GlideClient.createClient(
123+
* GlideClientConfiguration.builder()
124+
* .address(NodeAddress.builder().host("localhost").port(6379).build())
125+
* .databaseId(5) // Recommended: persists across reconnections
126+
* .build()
127+
* ).get();
128+
* }</pre>
129+
*
113130
* @see <a href="https://valkey.io/commands/select/">valkey.io</a> for details.
114131
* @param index The index of the database to select.
115132
* @return A simple <code>OK</code> response.

java/client/src/main/java/glide/api/models/configuration/BaseClientConfiguration.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,12 @@ public abstract class BaseClientConfiguration {
8585
/** Strategy used to determine how and when to reconnect, in case of connection failures. */
8686
private final BackoffStrategy reconnectStrategy;
8787

88+
/**
89+
* Index of the logical database to connect to. Must be non-negative and within the range
90+
* supported by the server configuration. If not specified, defaults to database 0.
91+
*/
92+
private final Integer databaseId;
93+
8894
/**
8995
* Enables lazy connection mode, where physical connections to the server(s) are deferred until
9096
* the first command is sent. This can reduce startup latency and allow for client creation in

java/client/src/main/java/glide/api/models/configuration/GlideClientConfiguration.java

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,6 @@
3434
@ToString
3535
public class GlideClientConfiguration extends BaseClientConfiguration {
3636

37-
/** Index of the logical database to connect to. */
38-
private final Integer databaseId;
39-
4037
/** Subscription configuration for the current client. */
4138
private final StandaloneSubscriptionConfiguration subscriptionConfiguration;
4239

java/client/src/main/java/glide/managers/ConnectionManager.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,10 @@ private ConnectionRequest.Builder setupConnectionRequestBuilderBaseConfiguration
162162
connectionRequestBuilder.setLazyConnect(configuration.isLazyConnect());
163163
}
164164

165+
if (configuration.getDatabaseId() != null) {
166+
connectionRequestBuilder.setDatabaseId(configuration.getDatabaseId());
167+
}
168+
165169
return connectionRequestBuilder;
166170
}
167171

@@ -176,10 +180,6 @@ private ConnectionRequest.Builder setupConnectionRequestBuilderGlideClient(
176180
setupConnectionRequestBuilderBaseConfiguration(configuration);
177181
connectionRequestBuilder.setClusterModeEnabled(false);
178182

179-
if (configuration.getDatabaseId() != null) {
180-
connectionRequestBuilder.setDatabaseId(configuration.getDatabaseId());
181-
}
182-
183183
if (configuration.getSubscriptionConfiguration() != null) {
184184
if (configuration.getProtocol() == ProtocolVersion.RESP2) {
185185
throw new ConfigurationError(
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/** Copyright Valkey GLIDE Project Contributors - SPDX Identifier: Apache-2.0 */
2+
package glide.api.models.configuration;
3+
4+
import static org.junit.jupiter.api.Assertions.assertEquals;
5+
import static org.junit.jupiter.api.Assertions.assertNull;
6+
7+
import org.junit.jupiter.api.Test;
8+
import org.junit.jupiter.params.ParameterizedTest;
9+
import org.junit.jupiter.params.provider.ValueSource;
10+
11+
public class BaseClientConfigurationTest {
12+
13+
/** Test implementation of BaseClientConfiguration for testing purposes */
14+
private static class TestClientConfiguration extends BaseClientConfiguration {
15+
private TestClientConfiguration(TestClientConfigurationBuilder builder) {
16+
super(builder);
17+
}
18+
19+
public static TestClientConfigurationBuilder builder() {
20+
return new TestClientConfigurationBuilder();
21+
}
22+
23+
@Override
24+
public BaseSubscriptionConfiguration getSubscriptionConfiguration() {
25+
return null;
26+
}
27+
28+
public static class TestClientConfigurationBuilder
29+
extends BaseClientConfigurationBuilder<
30+
TestClientConfiguration, TestClientConfigurationBuilder> {
31+
@Override
32+
protected TestClientConfigurationBuilder self() {
33+
return this;
34+
}
35+
36+
@Override
37+
public TestClientConfiguration build() {
38+
return new TestClientConfiguration(this);
39+
}
40+
}
41+
}
42+
43+
@Test
44+
public void testDatabaseIdDefault() {
45+
// Test that databaseId defaults to null when not specified
46+
TestClientConfiguration config = TestClientConfiguration.builder().build();
47+
assertNull(config.getDatabaseId());
48+
}
49+
50+
@ParameterizedTest
51+
@ValueSource(ints = {0, 1, 5, 10, 15, 50, 100, 1000})
52+
public void testDatabaseIdValidRange(int databaseId) {
53+
// Test that non-negative database IDs are accepted (server-side validation will handle range
54+
// checks)
55+
TestClientConfiguration config =
56+
TestClientConfiguration.builder().databaseId(databaseId).build();
57+
assertEquals(databaseId, config.getDatabaseId());
58+
}
59+
}

java/integTest/src/test/java/glide/cluster/ClusterClientTests.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,24 @@ public void client_name() {
154154
client.close();
155155
}
156156

157+
@SneakyThrows
158+
@Test
159+
public void select_cluster_database_id() {
160+
String minVersion = "9.0.0";
161+
assumeTrue(
162+
SERVER_VERSION.isGreaterThanOrEqualTo(minVersion),
163+
"Valkey version required >= " + minVersion);
164+
165+
GlideClusterClient client =
166+
GlideClusterClient.createClient(commonClusterClientConfig().databaseId(4).build()).get();
167+
168+
String clientInfo =
169+
(String) client.customCommand(new String[] {"CLIENT", "INFO"}).get().getSingleValue();
170+
assertTrue(clientInfo.contains("db=4"));
171+
172+
client.close();
173+
}
174+
157175
@Test
158176
@SneakyThrows
159177
public void closed_client_throws_ExecutionException_with_ClosingException_as_cause() {

0 commit comments

Comments
 (0)