Merge tag '6.2.1' into unstable

Former-commit-id: bfed57e3e0
This commit is contained in:
John Sully committed 2021-05-19 02:59:48 +00:00
commit fe8efa916b
298 files changed
+30298 -10182

No files matched your search

+79 -38
View File
@@ -369,10 +369,7 @@ void luaReplyToRedisReply(client *c, lua_State *lua) {
lua_gettable(lua,-2);
t = lua_type(lua,-1);
if (t == LUA_TSTRING) {
sds err = sdsnew(lua_tostring(lua,-1));
sdsmapchars(err,"\r\n"," ",2);
addReplySds(c,sdscatprintf(sdsempty(),"-%s\r\n",err));
sdsfree(err);
addReplyErrorFormat(c,"-%s",lua_tostring(lua,-1));
lua_pop(lua,2);
return;
}
@@ -479,7 +476,6 @@ void luaReplyToRedisReply(client *c, lua_State *lua) {
#define LUA_CMD_OBJCACHE_MAX_LEN 64
int luaRedisGenericCommand(lua_State *lua, int raise_error) {
int j, argc = lua_gettop(lua);
int acl_retval = 0;
int call_flags = CMD_CALL_SLOWLOG | CMD_CALL_STATS;
struct redisCommand *cmd;
client *c = serverTL->lua_client;
@@ -513,6 +509,7 @@ int luaRedisGenericCommand(lua_State *lua, int raise_error) {
inuse++;
std::unique_lock<decltype(c->lock)> ulock(c->lock);
{ // Begin GOTO protected variables
/* Require at least one argument */
if (argc == 0) {
luaPushError(lua,
@@ -576,7 +573,7 @@ int luaRedisGenericCommand(lua_State *lua, int raise_error) {
/* Setup our fake client for command execution */
c->argv = argv;
c->argc = argc;
c->puser = g_pserver->lua_caller->puser;
c->user = g_pserver->lua_caller->user;
/* Process module hooks */
moduleCallCommandFilters(c);
@@ -620,17 +617,31 @@ int luaRedisGenericCommand(lua_State *lua, int raise_error) {
}
/* Check the ACLs. */
int acl_keypos;
acl_retval = ACLCheckCommandPerm(c,&acl_keypos);
int acl_errpos;
int acl_retval = ACLCheckCommandPerm(c,&acl_errpos);
if (acl_retval == ACL_OK && c->cmd->proc == publishCommand)
acl_retval = ACLCheckPubsubPerm(c,1,1,0,&acl_errpos);
if (acl_retval != ACL_OK) {
addACLLogEntry(c,acl_retval,acl_keypos,NULL);
if (acl_retval == ACL_DENIED_CMD)
addACLLogEntry(c,acl_retval,acl_errpos,NULL);
switch (acl_retval) {
case ACL_DENIED_CMD:
luaPushError(lua, "The user executing the script can't run this "
"command or subcommand");
else
break;
case ACL_DENIED_KEY:
luaPushError(lua, "The user executing the script can't access "
"at least one of the keys mentioned in the "
"command arguments");
break;
case ACL_DENIED_CHANNEL:
luaPushError(lua, "The user executing the script can't publish "
"to the channel mentioned in the command");
break;
default:
luaPushError(lua, "The user executing the script is lacking the "
"permissions for the command");
break;
}
goto cleanup;
}
@@ -694,11 +705,11 @@ int luaRedisGenericCommand(lua_State *lua, int raise_error) {
if (getNodeByQuery(c,c->cmd,c->argv,c->argc,NULL,&error_code) !=
g_pserver->cluster->myself)
{
if (error_code == CLUSTER_REDIR_DOWN_RO_STATE) {
if (error_code == CLUSTER_REDIR_DOWN_RO_STATE) {
luaPushError(lua,
"Lua script attempted to execute a write command while the "
"cluster is down and readonly");
} else if (error_code == CLUSTER_REDIR_DOWN_STATE) {
} else if (error_code == CLUSTER_REDIR_DOWN_STATE) {
luaPushError(lua,
"Lua script attempted to execute a command while the "
"cluster is down");
@@ -721,7 +732,7 @@ int luaRedisGenericCommand(lua_State *lua, int raise_error) {
g_pserver->lua_write_dirty &&
g_pserver->lua_repl != PROPAGATE_NONE)
{
execCommandPropagateMulti(g_pserver->lua_caller);
execCommandPropagateMulti(g_pserver->lua_caller->db->id);
g_pserver->lua_multi_emitted = 1;
/* Now we are in the MULTI context, the lua_client should be
* flag as CLIENT_MULTI. */
@@ -737,6 +748,7 @@ int luaRedisGenericCommand(lua_State *lua, int raise_error) {
call_flags |= CMD_CALL_PROPAGATE_REPL;
}
call(c,call_flags);
serverAssert((c->flags & CLIENT_BLOCKED) == 0);
/* Convert the result of the Redis command into a suitable Lua type.
* The first thing we need is to create a single string from the client
@@ -774,6 +786,7 @@ int luaRedisGenericCommand(lua_State *lua, int raise_error) {
}
if (reply != c->buf) sdsfree(reply);
c->reply_bytes = 0;
} // END Goto Protected Variables
cleanup:
/* Clean up. Command code may have changed argv/argc so we use the
@@ -805,7 +818,7 @@ cleanup:
argv_size = 0;
}
c->puser = NULL;
c->user = NULL;
if (raise_error) {
/* If we are here we should have an error in the stack, in the
@@ -1110,6 +1123,8 @@ void scriptingInit(int setup) {
{
g_pserver->rgthreadvar[iel].lua_client = createClient(nullptr, iel);
g_pserver->rgthreadvar[iel].lua_client->flags |= CLIENT_LUA;
/* We do not want to allow blocking commands inside Lua */
g_pserver->rgthreadvar[iel].lua_client->flags |= CLIENT_DENY_BLOCKING;
}
g_pserver->lua_timedout = 0;
g_pserver->lua_caller = NULL;
@@ -1277,14 +1292,17 @@ void scriptingInit(int setup) {
/* Release resources related to Lua scripting.
* This function is used in order to reset the scripting environment. */
void scriptingRelease(void) {
dictRelease(g_pserver->lua_scripts);
void scriptingRelease(int async) {
if (async)
freeLuaScriptsAsync(g_pserver->lua_scripts);
else
dictRelease(g_pserver->lua_scripts);
g_pserver->lua_scripts_mem = 0;
lua_close(g_pserver->lua);
}
void scriptingReset(void) {
scriptingRelease();
void scriptingReset(int async) {
scriptingRelease(async);
scriptingInit(0);
}
@@ -1434,6 +1452,7 @@ void luaMaskCountHook(lua_State *lua, lua_Debug *ar) {
"Script SHA1 is: %s",
elapsed, g_pserver->lua_cur_script);
g_pserver->lua_timedout = 1;
blockingOperationStarts();
/* Once the script timeouts we reenter the event loop to permit others
* to call SCRIPT KILL or SHUTDOWN NOSAVE if needed. For this reason
* we need to mask the client executing the script from the event loop.
@@ -1489,6 +1508,7 @@ void evalGenericCommand(client *c, int evalsha) {
g_pserver->lua_replicate_commands = g_pserver->lua_always_replicate_commands;
g_pserver->lua_multi_emitted = 0;
g_pserver->lua_repl = PROPAGATE_AOF|PROPAGATE_REPL;
serverTL->in_eval = 1;
/* Get the number of arguments that are keys */
if (getLongLongFromObjectOrReply(c,c->argv[2],&numkeys,NULL) != C_OK)
@@ -1534,7 +1554,7 @@ void evalGenericCommand(client *c, int evalsha) {
* return an error. */
if (evalsha) {
lua_pop(lua,1); /* remove the error handler from the stack. */
addReply(c, shared.noscripterr);
addReplyErrorObject(c, shared.noscripterr);
return;
}
if (luaCreateFunction(c,lua,c->argv[1]) == NULL) {
@@ -1585,6 +1605,7 @@ void evalGenericCommand(client *c, int evalsha) {
if (delhook) lua_sethook(lua,NULL,0,0); /* Disable hook */
if (g_pserver->lua_timedout) {
g_pserver->lua_timedout = 0;
blockingOperationEnds();
/* Restore the client that was protected when the script timeout
* was detected. */
unprotectClient(c);
@@ -1634,7 +1655,7 @@ void evalGenericCommand(client *c, int evalsha) {
if (g_pserver->lua_replicate_commands) {
preventCommandPropagation(c);
if (g_pserver->lua_multi_emitted) {
execCommandPropagateExec(c);
execCommandPropagateExec(c->db->id);
}
}
@@ -1664,17 +1685,18 @@ void evalGenericCommand(client *c, int evalsha) {
* or just running a CPU costly read-only script on the slaves. */
if (g_pserver->dirty == initial_server_dirty) {
rewriteClientCommandVector(c,3,
resetRefCount(createStringObject("SCRIPT",6)),
resetRefCount(createStringObject("LOAD",4)),
shared.script,
shared.load,
script);
} else {
rewriteClientCommandArgument(c,0,
resetRefCount(createStringObject("EVAL",4)));
rewriteClientCommandArgument(c,0,shared.eval);
rewriteClientCommandArgument(c,1,script);
}
forceCommandPropagation(c,PROPAGATE_REPL|PROPAGATE_AOF);
}
}
serverTL->in_eval = 0;
}
void evalCommand(client *c) {
@@ -1690,7 +1712,7 @@ void evalShaCommand(client *c) {
* not the right length. So we return an error ASAP, this way
* evalGenericCommand() can be implemented without string length
* sanity check */
addReply(c, shared.noscripterr);
addReplyErrorObject(c, shared.noscripterr);
return;
}
if (!(c->flags & CLIENT_LUA_DEBUG))
@@ -1704,16 +1726,36 @@ void evalShaCommand(client *c) {
void scriptCommand(client *c) {
if (c->argc == 2 && !strcasecmp((const char*)ptrFromObj(c->argv[1]),"help")) {
const char *help[] = {
"DEBUG (yes|sync|no) -- Set the debug mode for subsequent scripts executed.",
"EXISTS <sha1> [<sha1> ...] -- Return information about the existence of the scripts in the script cache.",
"FLUSH -- Flush the Lua scripts cache. Very dangerous on replicas.",
"KILL -- Kill the currently executing Lua script.",
"LOAD <script> -- Load a script into the scripts cache, without executing it.",
"DEBUG (YES|SYNC|NO)",
" Set the debug mode for subsequent scripts executed.",
"EXISTS <sha1> [<sha1> ...]",
" Return information about the existence of the scripts in the script cache.",
"FLUSH [ASYNC|SYNC]",
" Flush the Lua scripts cache. Very dangerous on replicas.",
" When called without the optional mode argument, the behavior is determined by the",
" lazyfree-lazy-user-flush configuration directive. Valid modes are:",
" * ASYNC: Asynchronously flush the scripts cache.",
" * SYNC: Synchronously flush the scripts cache.",
"KILL",
" Kill the currently executing Lua script.",
"LOAD <script>",
" Load a script into the scripts cache without executing it.",
NULL
};
addReplyHelp(c, help);
} else if (c->argc == 2 && !strcasecmp((const char*)ptrFromObj(c->argv[1]),"flush")) {
scriptingReset();
} else if (c->argc >= 2 && !strcasecmp(szFromObj(c->argv[1]),"flush")) {
int async = 0;
if (c->argc == 3 && !strcasecmp(szFromObj(c->argv[2]),"sync")) {
async = 0;
} else if (c->argc == 3 && !strcasecmp(szFromObj(c->argv[2]),"async")) {
async = 1;
} else if (c->argc == 2) {
async = g_pserver->lazyfree_lazy_user_flush ? 1 : 0;
} else {
addReplyError(c,"SCRIPT FLUSH only support SYNC|ASYNC option");
return;
}
scriptingReset(async);
addReply(c,shared.ok);
replicationScriptCacheFlush();
g_pserver->dirty++; /* Propagating this command is a good idea. */
@@ -1734,11 +1776,11 @@ NULL
forceCommandPropagation(c,PROPAGATE_REPL|PROPAGATE_AOF);
} else if (c->argc == 2 && !strcasecmp((const char*)ptrFromObj(c->argv[1]),"kill")) {
if (g_pserver->lua_caller == NULL) {
addReplySds(c,sdsnew("-NOTBUSY No scripts in execution right now.\r\n"));
addReplyError(c,"-NOTBUSY No scripts in execution right now.");
} else if (g_pserver->lua_caller->flags & CLIENT_MASTER) {
addReplySds(c,sdsnew("-UNKILLABLE The busy script was sent by a master instance in the context of replication and cannot be killed.\r\n"));
addReplyError(c,"-UNKILLABLE The busy script was sent by a master instance in the context of replication and cannot be killed.");
} else if (g_pserver->lua_write_dirty) {
addReplySds(c,sdsnew("-UNKILLABLE Sorry the script already executed write commands against the dataset. You can either wait the script termination or kill the server in a hard way using the SHUTDOWN NOSAVE command.\r\n"));
addReplyError(c,"-UNKILLABLE Sorry the script already executed write commands against the dataset. You can either wait the script termination or kill the server in a hard way using the SHUTDOWN NOSAVE command.");
} else {
g_pserver->lua_kill = 1;
addReply(c,shared.ok);
@@ -1759,7 +1801,7 @@ NULL
addReply(c,shared.ok);
c->flags |= CLIENT_LUA_DEBUG_SYNC;
} else {
addReplyError(c,"Use SCRIPT DEBUG yes/sync/no");
addReplyError(c,"Use SCRIPT DEBUG YES/SYNC/NO");
return;
}
} else {
@@ -2733,4 +2775,3 @@ void luaLdbLineHook(lua_State *lua, lua_Debug *ar) {
g_pserver->lua_time_start = mstime();
}
}