Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Java: Add FCALL_RO command. #365

Merged
merged 4 commits into from
Jun 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions glide-core/src/protobuf/redis_request.proto
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ enum RequestType {
BLMPop = 158;
XLen = 159;
Sort = 160;
FCallReadOnly = 163;
LSet = 165;
XDel = 166;
XRange = 167;
Expand Down
3 changes: 3 additions & 0 deletions glide-core/src/request_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ pub enum RequestType {
BLMPop = 158,
XLen = 159,
Sort = 160,
FCallReadOnly = 163,
LSet = 165,
XDel = 166,
XRange = 167,
Expand Down Expand Up @@ -356,6 +357,7 @@ impl From<::protobuf::EnumOrUnknown<ProtobufRequestType>> for RequestType {
ProtobufRequestType::ExpireTime => RequestType::ExpireTime,
ProtobufRequestType::PExpireTime => RequestType::PExpireTime,
ProtobufRequestType::XLen => RequestType::XLen,
ProtobufRequestType::FCallReadOnly => RequestType::FCallReadOnly,
ProtobufRequestType::LSet => RequestType::LSet,
ProtobufRequestType::XDel => RequestType::XDel,
ProtobufRequestType::XRange => RequestType::XRange,
Expand Down Expand Up @@ -539,6 +541,7 @@ impl RequestType {
RequestType::ExpireTime => Some(cmd("EXPIRETIME")),
RequestType::PExpireTime => Some(cmd("PEXPIRETIME")),
RequestType::XLen => Some(cmd("XLEN")),
RequestType::FCallReadOnly => Some(cmd("FCALL_RO")),
RequestType::LSet => Some(cmd("LSET")),
RequestType::XDel => Some(cmd("XDEL")),
RequestType::XRange => Some(cmd("XRANGE")),
Expand Down
9 changes: 9 additions & 0 deletions java/client/src/main/java/glide/api/BaseClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import static redis_request.RedisRequestOuterClass.RequestType.ExpireAt;
import static redis_request.RedisRequestOuterClass.RequestType.ExpireTime;
import static redis_request.RedisRequestOuterClass.RequestType.FCall;
import static redis_request.RedisRequestOuterClass.RequestType.FCallReadOnly;
import static redis_request.RedisRequestOuterClass.RequestType.GeoAdd;
import static redis_request.RedisRequestOuterClass.RequestType.GeoDist;
import static redis_request.RedisRequestOuterClass.RequestType.GeoHash;
Expand Down Expand Up @@ -1783,6 +1784,14 @@ public CompletableFuture<Object> fcall(
return commandManager.submitNewCommand(FCall, args, this::handleObjectOrNullResponse);
}

@Override
public CompletableFuture<Object> fcallReadOnly(
@NonNull String function, @NonNull String[] keys, @NonNull String[] arguments) {
String[] args =
concatenateArrays(new String[] {function, Long.toString(keys.length)}, keys, arguments);
return commandManager.submitNewCommand(FCallReadOnly, args, this::handleObjectOrNullResponse);
}

@Override
public CompletableFuture<Boolean> copy(
@NonNull String source, @NonNull String destination, boolean replace) {
Expand Down
5 changes: 5 additions & 0 deletions java/client/src/main/java/glide/api/RedisClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,11 @@ public CompletableFuture<Object> fcall(@NonNull String function) {
return fcall(function, new String[0], new String[0]);
}

@Override
public CompletableFuture<Object> fcallReadOnly(@NonNull String function) {
return fcallReadOnly(function, new String[0], new String[0]);
}

@Override
public CompletableFuture<Boolean> copy(
@NonNull String source, @NonNull String destination, long destinationDB) {
Expand Down
33 changes: 33 additions & 0 deletions java/client/src/main/java/glide/api/RedisClusterClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import static redis_request.RedisRequestOuterClass.RequestType.DBSize;
import static redis_request.RedisRequestOuterClass.RequestType.Echo;
import static redis_request.RedisRequestOuterClass.RequestType.FCall;
import static redis_request.RedisRequestOuterClass.RequestType.FCallReadOnly;
import static redis_request.RedisRequestOuterClass.RequestType.FlushAll;
import static redis_request.RedisRequestOuterClass.RequestType.FunctionDelete;
import static redis_request.RedisRequestOuterClass.RequestType.FunctionFlush;
Expand Down Expand Up @@ -575,4 +576,36 @@ public CompletableFuture<ClusterValue<Object>> fcall(
? ClusterValue.ofSingleValue(handleObjectOrNullResponse(response))
: ClusterValue.ofMultiValue(handleMapResponse(response)));
}

@Override
public CompletableFuture<Object> fcallReadOnly(@NonNull String function) {
return fcallReadOnly(function, new String[0]);
}

@Override
public CompletableFuture<ClusterValue<Object>> fcallReadOnly(
@NonNull String function, @NonNull Route route) {
return fcallReadOnly(function, new String[0], route);
}

@Override
public CompletableFuture<Object> fcallReadOnly(
@NonNull String function, @NonNull String[] arguments) {
String[] args = concatenateArrays(new String[] {function, "0"}, arguments); // 0 - key count
return commandManager.submitNewCommand(FCallReadOnly, args, this::handleObjectOrNullResponse);
}

@Override
public CompletableFuture<ClusterValue<Object>> fcallReadOnly(
@NonNull String function, @NonNull String[] arguments, @NonNull Route route) {
String[] args = concatenateArrays(new String[] {function, "0"}, arguments); // 0 - key count
return commandManager.submitNewCommand(
FCallReadOnly,
args,
route,
response ->
route instanceof SingleNodeRoute
? ClusterValue.ofSingleValue(handleObjectOrNullResponse(response))
: ClusterValue.ofMultiValue(handleMapResponse(response)));
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/** Copyright GLIDE-for-Redis Project Contributors - SPDX Identifier: Apache-2.0 */
package glide.api.commands;

import glide.api.models.configuration.ReadFrom;
import java.util.concurrent.CompletableFuture;

/**
Expand All @@ -13,12 +14,14 @@
public interface ScriptingAndFunctionsBaseCommands {

/**
* Invokes a previously loaded function.
* Invokes a previously loaded function.<br>
* This command is routed to primary nodes only.<br>
* To route to a replica please refer to {@link #fcallReadOnly}.
*
* @apiNote When in cluster mode
* <ul>
* <li>all <code>keys</code> must map to the same hash slot.
* <li>if no <code>keys</code> are given, command will be routed to a random node.
* <li>if no <code>keys</code> are given, command will be routed to a random primary node.
* </ul>
*
* @since Redis 7.0 and above.
Expand All @@ -27,7 +30,7 @@ public interface ScriptingAndFunctionsBaseCommands {
* @param keys An <code>array</code> of keys accessed by the function. To ensure the correct
* execution of functions, both in standalone and clustered deployments, all names of keys
* that a function accesses must be explicitly provided as <code>keys</code>.
* @param arguments An <code>array</code> of <code>function</code> arguments. <code>Arguments
* @param arguments An <code>array</code> of <code>function</code> arguments. <code>arguments
* </code> should not represent names of keys.
* @return The invoked function's return value.
* @example
Expand All @@ -38,4 +41,32 @@ public interface ScriptingAndFunctionsBaseCommands {
* }</pre>
*/
CompletableFuture<Object> fcall(String function, String[] keys, String[] arguments);

/**
* Invokes a previously loaded read-only function.<br>
* This command is routed depending on the client's {@link ReadFrom} strategy.
*
* @apiNote When in cluster mode
* <ul>
* <li>all <code>keys</code> must map to the same hash slot.
* <li>if no <code>keys</code> are given, command will be routed to a random node.
* </ul>
*
* @since Redis 7.0 and above.
* @see <a href="https://redis.io/docs/latest/commands/fcall_ro/">redis.io</a> for details.
* @param function The function name.
* @param keys An <code>array</code> of keys accessed by the function. To ensure the correct
* execution of functions, both in standalone and clustered deployments, all names of keys
* that a function accesses must be explicitly provided as <code>keys</code>.
* @param arguments An <code>array</code> of <code>function</code> arguments. <code>arguments
* </code> should not represent names of keys.
* @return The invoked function's return value.
* @example
* <pre>{@code
* String[] args = new String[] { "Answer", "to", "the", "Ultimate", "Question", "of", "Life,", "the", "Universe,", "and", "Everything"};
* Object response = client.fcallReadOnly("Deep_Thought", new String[0], args).get();
* assert response == 42L;
* }</pre>
*/
CompletableFuture<Object> fcallReadOnly(String function, String[] keys, String[] arguments);
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import glide.api.models.ClusterValue;
import glide.api.models.commands.FlushMode;
import glide.api.models.configuration.ReadFrom;
import glide.api.models.configuration.RequestRoutingConfiguration.Route;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
Expand Down Expand Up @@ -268,7 +269,8 @@ CompletableFuture<ClusterValue<Map<String, Object>[]>> functionList(

/**
* Invokes a previously loaded function.<br>
* The command will be routed to a random node.
* The command will be routed to a primary random node.<br>
* To route to a replica please refer to {@link #fcallReadOnly(String)}.
*
* @since Redis 7.0 and above.
* @see <a href="https://redis.io/docs/latest/commands/fcall/">redis.io</a> for details.
Expand Down Expand Up @@ -303,12 +305,13 @@ CompletableFuture<ClusterValue<Map<String, Object>[]>> functionList(

/**
* Invokes a previously loaded function.<br>
* The command will be routed to a random node.
* The command will be routed to a random primary node.<br>
* To route to a replica please refer to {@link #fcallReadOnly(String, String[])}.
*
* @since Redis 7.0 and above.
* @see <a href="https://redis.io/docs/latest/commands/fcall/">redis.io</a> for details.
* @param function The function name.
* @param arguments An <code>array</code> of <code>function</code> arguments. <code>Arguments
* @param arguments An <code>array</code> of <code>function</code> arguments. <code>arguments
* </code> should not represent names of keys.
* @return The invoked function's return value.
* @example
Expand All @@ -326,7 +329,7 @@ CompletableFuture<ClusterValue<Map<String, Object>[]>> functionList(
* @since Redis 7.0 and above.
* @see <a href="https://redis.io/docs/latest/commands/fcall/">redis.io</a> for details.
* @param function The function name.
* @param arguments An <code>array</code> of <code>function</code> arguments. <code>Arguments
* @param arguments An <code>array</code> of <code>function</code> arguments. <code>arguments
* </code> should not represent names of keys.
* @param route Specifies the routing configuration for the command. The client will route the
* command to the nodes defined by <code>route</code>.
Expand All @@ -339,4 +342,79 @@ CompletableFuture<ClusterValue<Map<String, Object>[]>> functionList(
* }</pre>
*/
CompletableFuture<ClusterValue<Object>> fcall(String function, String[] arguments, Route route);

/**
* Invokes a previously loaded read-only function.<br>
* The command is routed to a random node depending on the client's {@link ReadFrom} strategy.
*
* @since Redis 7.0 and above.
* @see <a href="https://redis.io/docs/latest/commands/fcall_ro/">redis.io</a> for details.
* @param function The function name.
* @return The invoked function's return value.
* @example
* <pre>{@code
* Object response = client.fcallReadOnly("Deep_Thought").get();
* assert response == 42L;
* }</pre>
*/
CompletableFuture<Object> fcallReadOnly(String function);

/**
* Invokes a previously loaded read-only function.
*
* @since Redis 7.0 and above.
* @see <a href="https://redis.io/docs/latest/commands/fcall_ro/">redis.io</a> for details.
* @param function The function name.
* @param route Specifies the routing configuration for the command. The client will route the
* command to the nodes defined by <code>route</code>.
* @return The invoked function's return value wrapped by a {@link ClusterValue}.
* @example
* <pre>{@code
* ClusterValue<Object> response = client.fcallReadOnly("Deep_Thought", ALL_NODES).get();
* for (Object nodeResponse : response.getMultiValue().values()) {
* assert nodeResponse == 42L;
* }
* }</pre>
*/
CompletableFuture<ClusterValue<Object>> fcallReadOnly(String function, Route route);

/**
* Invokes a previously loaded function.<br>
* The command is routed to a random node depending on the client's {@link ReadFrom} strategy.
*
* @since Redis 7.0 and above.
* @see <a href="https://redis.io/docs/latest/commands/fcall_ro/">redis.io</a> for details.
* @param function The function name.
* @param arguments An <code>array</code> of <code>function</code> arguments. <code>arguments
* </code> should not represent names of keys.
* @return The invoked function's return value.
* @example
* <pre>{@code
* String[] args = new String[] { "Answer", "to", "the", "Ultimate", "Question", "of", "Life,", "the", "Universe,", "and", "Everything" };
* Object response = client.fcallReadOnly("Deep_Thought", args).get();
* assert response == 42L;
* }</pre>
*/
CompletableFuture<Object> fcallReadOnly(String function, String[] arguments);

/**
* Invokes a previously loaded read-only function.
*
* @since Redis 7.0 and above.
* @see <a href="https://redis.io/docs/latest/commands/fcall_ro/">redis.io</a> for details.
* @param function The function name.
* @param arguments An <code>array</code> of <code>function</code> arguments. <code>arguments
* </code> should not represent names of keys.
* @param route Specifies the routing configuration for the command. The client will route the
* command to the nodes defined by <code>route</code>.
* @return The invoked function's return value wrapped by a {@link ClusterValue}.
* @example
* <pre>{@code
* String[] args = new String[] { "Answer", "to", "the", "Ultimate", "Question", "of", "Life,", "the", "Universe,", "and", "Everything" };
* ClusterValue<Object> response = client.fcallReadOnly("Deep_Thought", args, RANDOM).get();
* assert response.getSingleValue() == 42L;
* }</pre>
*/
CompletableFuture<ClusterValue<Object>> fcallReadOnly(
String function, String[] arguments, Route route);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
package glide.api.commands;

import glide.api.models.commands.FlushMode;
import glide.api.models.configuration.ReadFrom;
import java.util.Map;
import java.util.concurrent.CompletableFuture;

Expand Down Expand Up @@ -129,7 +130,9 @@ public interface ScriptingAndFunctionsCommands {
CompletableFuture<String> functionDelete(String libName);

/**
* Invokes a previously loaded function.
* Invokes a previously loaded function.<br>
* This command is routed to primary nodes only.<br>
* To route to a replica please refer to {@link #fcallReadOnly}.
*
* @since Redis 7.0 and above.
* @see <a href="https://redis.io/docs/latest/commands/fcall/">redis.io</a> for details.
Expand All @@ -142,4 +145,20 @@ public interface ScriptingAndFunctionsCommands {
* }</pre>
*/
CompletableFuture<Object> fcall(String function);

/**
* Invokes a previously loaded read-only function.<br>
* This command is routed depending on the client's {@link ReadFrom} strategy.
*
* @since Redis 7.0 and above.
* @see <a href="https://redis.io/docs/latest/commands/fcall_ro/">redis.io</a> for details.
* @param function The function name.
* @return The invoked function's return value.
* @example
* <pre>{@code
* Object response = client.fcallReadOnly("Deep_Thought").get();
* assert response == 42L;
* }</pre>
*/
CompletableFuture<Object> fcallReadOnly(String function);
}
Loading
Loading