This is an automated email from the ASF dual-hosted git repository.
twice pushed a commit to branch unstable
in repository https://gitbox.apache.org/repos/asf/kvrocks.git
The following commit(s) were added to refs/heads/unstable by this push:
new 81691c20 feat(script): allow blocking commands in scripting (#2740)
81691c20 is described below
commit 81691c20dcfbdc887cc52c54f97f93cd4e5aea7c
Author: Twice <[email protected]>
AuthorDate: Tue Jan 28 14:56:30 2025 +0800
feat(script): allow blocking commands in scripting (#2740)
---
src/commands/blocking_commander.h | 2 +-
src/server/redis_connection.cc | 6 ++++++
src/server/redis_connection.h | 2 ++
src/storage/scripting.cc | 8 +-------
tests/gocase/unit/scripting/scripting_test.go | 8 +++++++-
5 files changed, 17 insertions(+), 9 deletions(-)
diff --git a/src/commands/blocking_commander.h
b/src/commands/blocking_commander.h
index 27496819..2571e456 100644
--- a/src/commands/blocking_commander.h
+++ b/src/commands/blocking_commander.h
@@ -52,7 +52,7 @@ class BlockingCommander : public Commander,
// to start the blocking process
// usually put to the end of the Execute method
Status StartBlocking(int64_t timeout, std::string *output) {
- if (conn_->IsInExec()) {
+ if (conn_->IsInExec() || conn_->IsInScript()) {
*output = NoopReply(conn_);
return Status::OK(); // no blocking in multi-exec
}
diff --git a/src/server/redis_connection.cc b/src/server/redis_connection.cc
index 3f8e0dd2..a4926dfb 100644
--- a/src/server/redis_connection.cc
+++ b/src/server/redis_connection.cc
@@ -496,6 +496,12 @@ void Connection::ExecuteCommands(std::deque<CommandTokens>
*to_process_cmds) {
continue;
}
+ ScopeExit in_script_exit{[this] { in_script_ = false; }, false};
+ if (attributes->category == CommandCategory::Script ||
attributes->category == CommandCategory::Function) {
+ in_script_ = true;
+ in_script_exit.Enable();
+ }
+
SetLastCmd(cmd_name);
{
std::optional<MultiLockGuard> guard;
diff --git a/src/server/redis_connection.h b/src/server/redis_connection.h
index e7d277f6..e8b44d94 100644
--- a/src/server/redis_connection.h
+++ b/src/server/redis_connection.h
@@ -171,6 +171,7 @@ class Connection : public EvbufCallbackBase<Connection> {
// Multi exec
void SetInExec() { in_exec_ = true; }
bool IsInExec() const { return in_exec_; }
+ bool IsInScript() const { return in_script_; }
bool IsMultiError() const { return multi_error_; }
void ResetMultiExec();
std::deque<redis::CommandTokens> *GetMultiExecCommands() { return
&multi_cmds_; }
@@ -210,6 +211,7 @@ class Connection : public EvbufCallbackBase<Connection> {
bool multi_error_ = false;
std::atomic<bool> is_running_ = false;
std::deque<redis::CommandTokens> multi_cmds_;
+ bool in_script_ = false;
bool importing_ = false;
RESP protocol_version_ = RESP::v2;
diff --git a/src/storage/scripting.cc b/src/storage/scripting.cc
index b2c0eebc..6a93ad9f 100644
--- a/src/storage/scripting.cc
+++ b/src/storage/scripting.cc
@@ -756,7 +756,7 @@ int RedisGenericCommand(lua_State *lua, int raise_error) {
auto attributes = cmd->GetAttributes();
if (!attributes->CheckArity(argc)) {
- PushError(lua, "Wrong number of args calling Redis command From Lua
script");
+ PushError(lua, "Wrong number of args while calling Redis command from Lua
script");
return raise_error ? RaiseError(lua) : 1;
}
@@ -772,12 +772,6 @@ int RedisGenericCommand(lua_State *lua, int raise_error) {
return raise_error ? RaiseError(lua) : 1;
}
- // TODO: fix blocking commands to make them work in scripting
- if (cmd_flags & redis::kCmdBlocking) {
- PushError(lua, "This Redis command is not allowed from scripts");
- return raise_error ? RaiseError(lua) : 1;
- }
-
std::string cmd_name = attributes->name;
auto *conn = script_run_ctx->conn;
diff --git a/tests/gocase/unit/scripting/scripting_test.go
b/tests/gocase/unit/scripting/scripting_test.go
index cd04351a..c3753ecc 100644
--- a/tests/gocase/unit/scripting/scripting_test.go
+++ b/tests/gocase/unit/scripting/scripting_test.go
@@ -198,10 +198,16 @@ return {type(foo),foo == false}
})
t.Run("EVAL - Scripts can't run certain commands", func(t *testing.T) {
- r := rdb.Eval(ctx, `return redis.pcall('blpop','x',0)`,
[]string{})
+ r := rdb.Eval(ctx, `return redis.pcall('shutdown')`, []string{})
require.ErrorContains(t, r.Err(), "not allowed")
})
+ t.Run("EVAL - Scripts can run blocking commands and get immediate
result", func(t *testing.T) {
+ r := rdb.Eval(ctx, `return redis.pcall('blpop', KEYS[1], 0)`,
[]string{"key_for_blpop_script"})
+ require.Equal(t, r.Val(), nil)
+ require.ErrorContains(t, r.Err(), "nil")
+ })
+
t.Run("EVAL - Scripts can run certain commands", func(t *testing.T) {
r := rdb.Eval(ctx, `redis.pcall('randomkey'); return
redis.pcall('set','x','ciao')`, []string{})
require.NoError(t, r.Err())