Skip to content

Commit 1ea0060

Browse files
Address PR feedback.
Signed-off-by: Yury-Fridlyand <[email protected]>
1 parent f296c00 commit 1ea0060

16 files changed

+377
-397
lines changed

java/client/src/main/java/glide/api/BaseClient.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
package glide.api;
22

3+
import static glide.ffi.resolvers.SocketListenerResolver.getSocket;
4+
5+
import glide.connectors.handlers.CallbackDispatcher;
6+
import glide.connectors.handlers.ChannelHandler;
37
import glide.ffi.resolvers.RedisValueResolver;
48
import glide.managers.BaseCommandResponseResolver;
59
import glide.managers.CommandManager;
@@ -43,4 +47,17 @@ public void close() throws ExecutionException {
4347
throw new RuntimeException(e);
4448
}
4549
}
50+
51+
protected static ChannelHandler buildChannelHandler() throws InterruptedException {
52+
CallbackDispatcher callbackDispatcher = new CallbackDispatcher();
53+
return new ChannelHandler(callbackDispatcher, getSocket());
54+
}
55+
56+
protected static ConnectionManager buildConnectionManager(ChannelHandler channelHandler) {
57+
return new ConnectionManager(channelHandler);
58+
}
59+
60+
protected static CommandManager buildCommandManager(ChannelHandler channelHandler) {
61+
return new CommandManager(channelHandler);
62+
}
4663
}

java/client/src/main/java/glide/api/RedisClient.java

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,11 @@
11
package glide.api;
22

3-
import static glide.ffi.resolvers.SocketListenerResolver.getSocket;
4-
53
import glide.api.commands.BaseCommands;
64
import glide.api.models.configuration.RedisClientConfiguration;
7-
import glide.connectors.handlers.CallbackDispatcher;
85
import glide.connectors.handlers.ChannelHandler;
96
import glide.managers.CommandManager;
107
import glide.managers.ConnectionManager;
118
import glide.managers.models.Command;
12-
import java.util.Optional;
139
import java.util.concurrent.CompletableFuture;
1410

1511
/**
@@ -45,23 +41,10 @@ public static CompletableFuture<RedisClient> CreateClient(RedisClientConfigurati
4541
}
4642
}
4743

48-
protected static ChannelHandler buildChannelHandler() throws InterruptedException {
49-
CallbackDispatcher callbackDispatcher = new CallbackDispatcher();
50-
return new ChannelHandler(callbackDispatcher, getSocket());
51-
}
52-
53-
protected static ConnectionManager buildConnectionManager(ChannelHandler channelHandler) {
54-
return new ConnectionManager(channelHandler);
55-
}
56-
57-
protected static CommandManager buildCommandManager(ChannelHandler channelHandler) {
58-
return new CommandManager(channelHandler);
59-
}
60-
6144
@Override
6245
public CompletableFuture<Object> customCommand(String[] args) {
6346
Command command =
6447
Command.builder().requestType(Command.RequestType.CUSTOM_COMMAND).arguments(args).build();
65-
return commandManager.submitNewCommand(command, Optional.empty(), this::handleObjectResponse);
48+
return commandManager.submitNewCommand(command, this::handleObjectResponse);
6649
}
6750
}

java/client/src/main/java/glide/api/RedisClusterClient.java

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,14 @@
11
package glide.api;
22

3-
import static glide.api.RedisClient.buildChannelHandler;
4-
import static glide.api.RedisClient.buildCommandManager;
5-
import static glide.api.RedisClient.buildConnectionManager;
6-
73
import glide.api.commands.ClusterBaseCommands;
84
import glide.api.models.ClusterValue;
95
import glide.api.models.configuration.RedisClusterClientConfiguration;
10-
import glide.api.models.configuration.Route;
6+
import glide.api.models.configuration.RequestRoutingConfiguration.Route;
117
import glide.connectors.handlers.ChannelHandler;
128
import glide.managers.CommandManager;
139
import glide.managers.ConnectionManager;
1410
import glide.managers.models.Command;
15-
import java.util.Optional;
11+
import java.util.Map;
1612
import java.util.concurrent.CompletableFuture;
1713

1814
/**
@@ -53,15 +49,26 @@ public static CompletableFuture<RedisClusterClient> CreateClient(
5349
public CompletableFuture<ClusterValue<Object>> customCommand(String[] args) {
5450
Command command =
5551
Command.builder().requestType(Command.RequestType.CUSTOM_COMMAND).arguments(args).build();
52+
// TODO if a command returns a map as a single value, ClusterValue misleads user
5653
return commandManager.submitNewCommand(
57-
command, Optional.empty(), response -> ClusterValue.of(handleObjectResponse(response)));
54+
command, response -> ClusterValue.of(handleObjectResponse(response)));
5855
}
5956

6057
@Override
58+
@SuppressWarnings("unchecked")
6159
public CompletableFuture<ClusterValue<Object>> customCommand(String[] args, Route route) {
6260
Command command =
63-
Command.builder().requestType(Command.RequestType.CUSTOM_COMMAND).arguments(args).build();
61+
Command.builder()
62+
.requestType(Command.RequestType.CUSTOM_COMMAND)
63+
.arguments(args)
64+
.route(route)
65+
.build();
66+
6467
return commandManager.submitNewCommand(
65-
command, Optional.of(route), response -> ClusterValue.of(handleObjectResponse(response)));
68+
command,
69+
response ->
70+
route.isSingleNodeRoute()
71+
? ClusterValue.ofSingleValue(handleObjectResponse(response))
72+
: ClusterValue.ofMultiValue((Map<String, Object>) handleObjectResponse(response)));
6673
}
6774
}

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

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,19 @@ public interface BaseCommands {
77

88
/**
99
* Executes a single command, without checking inputs. Every part of the command, including
10-
* subcommands, should be added as a separate value in {@code args}.
10+
* subcommands, should be added as a separate value in args.
1111
*
1212
* @remarks This function should only be used for single-response commands. Commands that don't
13-
* return response (such as <em>SUBSCRIBE</em>), or that return potentially more than a single
14-
* response (such as <em>XREAD</em>), or that change the client's behavior (such as entering
15-
* <em>pub</em>/<em>sub</em> mode on <em>RESP2</em> connections) shouldn't be called using
16-
* this function.
17-
* @example Returns a list of all <em>pub</em>/<em>sub</em> clients:
18-
* <p><code>
19-
* Object result = client.customCommand(new String[]{ "CLIENT", "LIST", "TYPE", "PUBSUB" }).get();
20-
* </code>
21-
* @param args Arguments for the custom command including the command name
22-
* @return A <em>CompletableFuture</em> with response result from Redis
13+
* return response (such as SUBSCRIBE), or that return potentially more than a single response
14+
* (such as XREAD), or that change the client's behavior (such as entering pub/sub mode on
15+
* RESP2 connections) shouldn't be called using this function.
16+
* @example Returns a list of all pub/sub clients:
17+
* <pre>
18+
* Object result = client.customCommand(new String[]{"CLIENT","LIST","TYPE", "PUBSUB"}).get();
19+
* </pre>
20+
*
21+
* @param args arguments for the custom command
22+
* @return a CompletableFuture with response result from Redis
2323
*/
2424
CompletableFuture<Object> customCommand(String[] args);
2525
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package glide.api.commands;
22

33
import glide.api.models.ClusterValue;
4-
import glide.api.models.configuration.Route;
4+
import glide.api.models.configuration.RequestRoutingConfiguration.Route;
55
import java.util.concurrent.CompletableFuture;
66

77
/**

java/client/src/main/java/glide/api/models/ClusterValue.java

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ private ClusterValue() {}
2121
* Check with {@link #hasMultiData()} prior to accessing the data.
2222
*/
2323
public Map<String, T> getMultiValue() {
24-
assert hasMultiData();
24+
assert hasMultiData() : "No multi value stored";
2525
return multiValue;
2626
}
2727

@@ -30,11 +30,11 @@ public Map<String, T> getMultiValue() {
3030
* Check with {@link #hasSingleData()} ()} prior to accessing the data.
3131
*/
3232
public T getSingleValue() {
33-
assert hasSingleData();
33+
assert hasSingleData() : "No single value stored";
3434
return singleValue;
3535
}
3636

37-
/** A constructor for the value. */
37+
/** A constructor for the value with type auto-detection. */
3838
@SuppressWarnings("unchecked")
3939
public static <T> ClusterValue<T> of(Object data) {
4040
var res = new ClusterValue<T>();
@@ -46,6 +46,20 @@ public static <T> ClusterValue<T> of(Object data) {
4646
return res;
4747
}
4848

49+
/** A constructor for the value. */
50+
public static <T> ClusterValue<T> ofSingleValue(T data) {
51+
var res = new ClusterValue<T>();
52+
res.singleValue = data;
53+
return res;
54+
}
55+
56+
/** A constructor for the value. */
57+
public static <T> ClusterValue<T> ofMultiValue(Map<String, T> data) {
58+
var res = new ClusterValue<T>();
59+
res.multiValue = data;
60+
return res;
61+
}
62+
4963
/** Check that multi-value is stored in this object. Use it prior to accessing the data. */
5064
public boolean hasMultiData() {
5165
return multiValue != null;
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
package glide.api.models.configuration;
2+
3+
import lombok.Getter;
4+
import lombok.RequiredArgsConstructor;
5+
import redis_request.RedisRequestOuterClass.SimpleRoutes;
6+
import redis_request.RedisRequestOuterClass.SlotTypes;
7+
8+
/** Request routing configuration. */
9+
public class RequestRoutingConfiguration {
10+
11+
/**
12+
* Basic interface. Please use one of the following implementations:
13+
*
14+
* <ul>
15+
* <li>{@link SimpleRoute}
16+
* <li>{@link SlotIdRoute}
17+
* <li>{@link SlotKeyRoute}
18+
* </ul>
19+
*/
20+
public interface Route {
21+
boolean isSingleNodeRoute();
22+
}
23+
24+
@RequiredArgsConstructor
25+
@Getter
26+
public enum SimpleRoute implements Route {
27+
/** Route request to all nodes. */
28+
ALL_NODES(SimpleRoutes.AllNodes),
29+
/** Route request to all primary nodes. */
30+
ALL_PRIMARIES(SimpleRoutes.AllPrimaries),
31+
/** Route request to a random node. */
32+
RANDOM(SimpleRoutes.Random);
33+
34+
private final SimpleRoutes protobufMapping;
35+
36+
@Override
37+
public boolean isSingleNodeRoute() {
38+
return this == RANDOM;
39+
}
40+
}
41+
42+
@RequiredArgsConstructor
43+
@Getter
44+
public enum SlotType {
45+
PRIMARY(SlotTypes.Primary),
46+
REPLICA(SlotTypes.Replica);
47+
48+
private final SlotTypes slotTypes;
49+
}
50+
51+
/**
52+
* Request routing configuration overrides the {@link ReadFrom} connection configuration.<br>
53+
* If {@link SlotType#REPLICA} is used, the request will be routed to a replica, even if the
54+
* strategy is {@link ReadFrom#PRIMARY}.
55+
*/
56+
@RequiredArgsConstructor
57+
@Getter
58+
public static class SlotIdRoute implements Route {
59+
/**
60+
* Slot number. There are 16384 slots in a redis cluster, and each shard manages a slot range.
61+
* Unless the slot is known, it's better to route using {@link SlotType#PRIMARY}.
62+
*/
63+
private final int slotId;
64+
65+
private final SlotType slotType;
66+
67+
@Override
68+
public boolean isSingleNodeRoute() {
69+
return true;
70+
}
71+
}
72+
73+
/**
74+
* Request routing configuration overrides the {@link ReadFrom} connection configuration.<br>
75+
* If {@link SlotType#REPLICA} is used, the request will be routed to a replica, even if the
76+
* strategy is {@link ReadFrom#PRIMARY}.
77+
*/
78+
@RequiredArgsConstructor
79+
@Getter
80+
public static class SlotKeyRoute implements Route {
81+
/** The request will be sent to nodes managing this key. */
82+
private final String slotKey;
83+
84+
private final SlotType slotType;
85+
86+
@Override
87+
public boolean isSingleNodeRoute() {
88+
return true;
89+
}
90+
}
91+
}

0 commit comments

Comments
 (0)