From 905c047e60f3e809b9c4a5dffdcad3e5383a2336 Mon Sep 17 00:00:00 2001 From: Nikita Koksharov Date: Fri, 4 Feb 2022 09:21:43 +0300 Subject: [PATCH] Improvement - RScript read-only cached scripts should be executed on slaves (supported only by Redis 7.0+) --- .../main/java/org/redisson/RedissonScript.java | 16 ++++++++++++++-- .../redisson/command/CommandAsyncExecutor.java | 4 ++++ .../redisson/command/CommandAsyncService.java | 12 ++++++++++-- 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/redisson/src/main/java/org/redisson/RedissonScript.java b/redisson/src/main/java/org/redisson/RedissonScript.java index c9e10d74c..2691a4f5b 100644 --- a/redisson/src/main/java/org/redisson/RedissonScript.java +++ b/redisson/src/main/java/org/redisson/RedissonScript.java @@ -200,8 +200,20 @@ public class RedissonScript implements RScript { public RFuture evalShaAsync(String key, Mode mode, String shaDigest, ReturnType returnType, List keys, Object... values) { RedisCommand command = new RedisCommand(returnType.getCommand(), "EVALSHA"); - if (mode == Mode.READ_ONLY) { - return commandExecutor.evalReadAsync(key, codec, command, shaDigest, keys, encode(Arrays.asList(values), codec).toArray()); + if (mode == Mode.READ_ONLY && commandExecutor.isEvalShaROSupported()) { + RedisCommand cmd = new RedisCommand(returnType.getCommand(), "EVALSHA_RO"); + RFuture f = commandExecutor.evalReadAsync(key, codec, cmd, shaDigest, keys, encode(Arrays.asList(values), codec).toArray()); + CompletableFuture result = new CompletableFuture<>(); + f.whenComplete((r, e) -> { + if (e != null) { + if (e.getMessage().startsWith("ERR unknown command")) { + commandExecutor.setEvalShaROSupported(false); + RFuture s = evalShaAsync(key, mode, shaDigest, returnType, keys, values); + commandExecutor.transfer(s.toCompletableFuture(), result); + } + } + }); + return new CompletableFutureWrapper<>(result); } return commandExecutor.evalWriteAsync(key, codec, command, shaDigest, keys, encode(Arrays.asList(values), codec).toArray()); } diff --git a/redisson/src/main/java/org/redisson/command/CommandAsyncExecutor.java b/redisson/src/main/java/org/redisson/command/CommandAsyncExecutor.java index aadf1d0a3..10436f69e 100644 --- a/redisson/src/main/java/org/redisson/command/CommandAsyncExecutor.java +++ b/redisson/src/main/java/org/redisson/command/CommandAsyncExecutor.java @@ -132,4 +132,8 @@ public interface CommandAsyncExecutor { RFuture writeBatchedAsync(Codec codec, RedisCommand command, SlotCallback callback, String... keys); + boolean isEvalShaROSupported(); + + void setEvalShaROSupported(boolean value); + } diff --git a/redisson/src/main/java/org/redisson/command/CommandAsyncService.java b/redisson/src/main/java/org/redisson/command/CommandAsyncService.java index c3d2259e5..0e0c943a4 100644 --- a/redisson/src/main/java/org/redisson/command/CommandAsyncService.java +++ b/redisson/src/main/java/org/redisson/command/CommandAsyncService.java @@ -498,8 +498,16 @@ public class CommandAsyncService implements CommandAsyncExecutor { return result.toArray(); } - private AtomicBoolean evalShaROSupported = new AtomicBoolean(true); - + private final AtomicBoolean evalShaROSupported = new AtomicBoolean(true); + + public boolean isEvalShaROSupported() { + return evalShaROSupported.get(); + } + + public void setEvalShaROSupported(boolean value) { + this.evalShaROSupported.set(value); + } + private RFuture evalAsync(NodeSource nodeSource, boolean readOnlyMode, Codec codec, RedisCommand evalCommandType, String script, List keys, boolean noRetry, Object... params) { if (isEvalCacheActive() && evalCommandType.getName().equals("EVAL")) {