Fixed - CommandMapper isn't applied to Lua scripts. #5797

pull/5898/head
Nikita Koksharov 9 months ago
parent db6e98e4bd
commit fd94acbf70

@ -31,6 +31,7 @@ import org.redisson.client.codec.Codec;
import org.redisson.client.codec.StringCodec;
import org.redisson.client.protocol.RedisCommand;
import org.redisson.client.protocol.RedisCommands;
import org.redisson.config.DefaultCommandMapper;
import org.redisson.connection.ConnectionManager;
import org.redisson.connection.MasterSlaveEntry;
import org.redisson.connection.NodeSource;
@ -53,6 +54,8 @@ import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
/**
@ -500,15 +503,37 @@ public class CommandAsyncService implements CommandAsyncExecutor {
this.EVAL_SHA_RO_SUPPORTED.set(value);
}
private static final Pattern COMMANDS_PATTERN = Pattern.compile("redis\\.call\\(['\"]{1}([\\w.]+)['\"]{1}");
private String map(String script) {
if (getServiceManager().getConfig().getCommandMapper() instanceof DefaultCommandMapper) {
return script;
}
Matcher matcher = COMMANDS_PATTERN.matcher(script);
while (matcher.find()) {
String command = matcher.group(1);
String mapped = getServiceManager().getConfig().getCommandMapper().map(command);
if (!command.equalsIgnoreCase(mapped)) {
script = script.replace(command, mapped);
}
}
return script;
}
public <T, R> RFuture<R> evalAsync(NodeSource nodeSource, boolean readOnlyMode, Codec codec, RedisCommand<T> evalCommandType,
String script, List<Object> keys, boolean noRetry, Object... params) {
String script, List<Object> keys, boolean noRetry, Object... params) {
String mappedScript = map(script);
if (isEvalCacheActive() && evalCommandType.getName().equals("EVAL")) {
CompletableFuture<R> mainPromise = new CompletableFuture<>();
Object[] pps = copy(params);
CompletableFuture<R> promise = new CompletableFuture<>();
String sha1 = getServiceManager().calcSHA(script);
String sha1 = getServiceManager().calcSHA(mappedScript);
RedisCommand cmd;
if (readOnlyMode && EVAL_SHA_RO_SUPPORTED.get()) {
cmd = new RedisCommand(evalCommandType, "EVALSHA_RO");
@ -522,19 +547,19 @@ public class CommandAsyncService implements CommandAsyncExecutor {
args.addAll(Arrays.asList(params));
RedisExecutor<T, R> executor = new RedisExecutor(readOnlyMode, nodeSource, codec, cmd,
args.toArray(), promise, false,
connectionManager, objectBuilder, referenceType, noRetry,
retryAttempts, retryInterval, responseTimeout, trackChanges);
args.toArray(), promise, false,
connectionManager, objectBuilder, referenceType, noRetry,
retryAttempts, retryInterval, responseTimeout, trackChanges);
executor.execute();
promise.whenComplete((res, e) -> {
if (e != null) {
if (e.getMessage().startsWith("ERR unknown command")) {
EVAL_SHA_RO_SUPPORTED.set(false);
RFuture<R> future = evalAsync(nodeSource, readOnlyMode, codec, evalCommandType, script, keys, noRetry, pps);
RFuture<R> future = evalAsync(nodeSource, readOnlyMode, codec, evalCommandType, mappedScript, keys, noRetry, pps);
transfer(future.toCompletableFuture(), mainPromise);
} else if (e.getMessage().startsWith("NOSCRIPT")) {
RFuture<String> loadFuture = loadScript(executor.getRedisClient(), script);
RFuture<String> loadFuture = loadScript(executor.getRedisClient(), mappedScript);
loadFuture.whenComplete((r, ex) -> {
if (ex != null) {
free(pps);
@ -567,9 +592,9 @@ public class CommandAsyncService implements CommandAsyncExecutor {
});
return new CompletableFutureWrapper<>(mainPromise);
}
List<Object> args = new ArrayList<Object>(2 + keys.size() + params.length);
args.add(script);
args.add(mappedScript);
args.add(keys.size());
args.addAll(keys);
args.addAll(Arrays.asList(params));

@ -1,23 +1,58 @@
package org.redisson;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ExecutionException;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.redisson.api.RFuture;
import org.redisson.api.RLexSortedSet;
import org.redisson.api.RScript;
import org.redisson.api.*;
import org.redisson.api.RScript.Mode;
import org.redisson.client.RedisException;
import org.redisson.client.codec.StringCodec;
import org.redisson.config.CommandMapper;
import org.redisson.config.Config;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
public class RedissonScriptTest extends RedisDockerTest {
@Test
public void testCommandMapping() {
String script = "local value = redis.call('cmd1', KEYS[1], ARGV[1]); "
+ "if value ~= false then "
+ "redis.call('cmd2', KEYS[1], ARGV[1], ARGV[2]); "
+ "redis.call('cmd2', KEYS[1], ARGV[1], ARGV[2]); "
+ "return value; "
+ "end; "
+ "return nil; ";
Config cfg = createConfig();
cfg.useSingleServer().setCommandMapper(new CommandMapper() {
@Override
public String map(String name) {
if (name.equalsIgnoreCase("cmd1")) {
return "hget";
}
if (name.equalsIgnoreCase("cmd2")) {
return "hset";
}
return name;
}
});
RedissonClient r = Redisson.create(cfg);
RMap<Object, Object> m = r.getMap("test");
m.fastPut("key1", "value");
String res = r.getScript().eval(Mode.READ_WRITE,
script,
RScript.ReturnType.VALUE, Arrays.asList("test"), "key1", "value3");
assertThat(res).isEqualTo("value");
assertThat(m.get("key1")).isEqualTo("value3");
}
@Test
public void testMulti() {
RLexSortedSet idx2 = redisson.getLexSortedSet("ABCD17436");

Loading…
Cancel
Save