Skip to content

Commit

Permalink
Add new SCRIPT SHOW subcommand to dump script via sha1 (#617)
Browse files Browse the repository at this point in the history
In some scenarios, the business may not be able to find the
previously used Lua script and only have a SHA signature.
Or there are multiple identical evalsha's args in monitor/slowlog,
and admin is not able to distinguish the script body.

Add a new script subcommmand to show the contents of script
given the scripts sha1. Returns a NOSCRIPT error if the script
is not present in the cache.

Usage: `SCRIPT SHOW sha1`
Complexity: `O(1)`

Closes #604.
Doc PR: valkey-io/valkey-doc#143

---------

Signed-off-by: wei.kukey <wei.kukey@gmail.com>
Signed-off-by: Madelyn Olson <madelyneolson@gmail.com>
Co-authored-by: Madelyn Olson <madelyneolson@gmail.com>
Co-authored-by: Binbin <binloveplay1314@qq.com>
Co-authored-by: Viktor Söderqvist <viktor.soderqvist@est.tech>
  • Loading branch information
4 people authored Jun 19, 2024
1 parent be2c321 commit ae2d421
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 1 deletion.
23 changes: 23 additions & 0 deletions src/commands.def
Original file line number Diff line number Diff line change
Expand Up @@ -5333,6 +5333,28 @@ struct COMMAND_ARG SCRIPT_LOAD_Args[] = {
{MAKE_ARG("script",ARG_TYPE_STRING,-1,NULL,NULL,NULL,CMD_ARG_NONE,0,NULL)},
};

/********** SCRIPT SHOW ********************/

#ifndef SKIP_CMD_HISTORY_TABLE
/* SCRIPT SHOW history */
#define SCRIPT_SHOW_History NULL
#endif

#ifndef SKIP_CMD_TIPS_TABLE
/* SCRIPT SHOW tips */
#define SCRIPT_SHOW_Tips NULL
#endif

#ifndef SKIP_CMD_KEY_SPECS_TABLE
/* SCRIPT SHOW key specs */
#define SCRIPT_SHOW_Keyspecs NULL
#endif

/* SCRIPT SHOW argument table */
struct COMMAND_ARG SCRIPT_SHOW_Args[] = {
{MAKE_ARG("sha1",ARG_TYPE_STRING,-1,NULL,NULL,NULL,CMD_ARG_NONE,0,NULL)},
};

/* SCRIPT command table */
struct COMMAND_STRUCT SCRIPT_Subcommands[] = {
{MAKE_CMD("debug","Sets the debug mode of server-side Lua scripts.","O(1)","3.2.0",CMD_DOC_NONE,NULL,NULL,"scripting",COMMAND_GROUP_SCRIPTING,SCRIPT_DEBUG_History,0,SCRIPT_DEBUG_Tips,0,scriptCommand,3,CMD_NOSCRIPT,ACL_CATEGORY_SCRIPTING,SCRIPT_DEBUG_Keyspecs,0,NULL,1),.args=SCRIPT_DEBUG_Args},
Expand All @@ -5341,6 +5363,7 @@ struct COMMAND_STRUCT SCRIPT_Subcommands[] = {
{MAKE_CMD("help","Returns helpful text about the different subcommands.","O(1)","5.0.0",CMD_DOC_NONE,NULL,NULL,"scripting",COMMAND_GROUP_SCRIPTING,SCRIPT_HELP_History,0,SCRIPT_HELP_Tips,0,scriptCommand,2,CMD_LOADING|CMD_STALE,ACL_CATEGORY_SCRIPTING,SCRIPT_HELP_Keyspecs,0,NULL,0)},
{MAKE_CMD("kill","Terminates a server-side Lua script during execution.","O(1)","2.6.0",CMD_DOC_NONE,NULL,NULL,"scripting",COMMAND_GROUP_SCRIPTING,SCRIPT_KILL_History,0,SCRIPT_KILL_Tips,2,scriptCommand,2,CMD_NOSCRIPT|CMD_ALLOW_BUSY,ACL_CATEGORY_SCRIPTING,SCRIPT_KILL_Keyspecs,0,NULL,0)},
{MAKE_CMD("load","Loads a server-side Lua script to the script cache.","O(N) with N being the length in bytes of the script body.","2.6.0",CMD_DOC_NONE,NULL,NULL,"scripting",COMMAND_GROUP_SCRIPTING,SCRIPT_LOAD_History,0,SCRIPT_LOAD_Tips,2,scriptCommand,3,CMD_NOSCRIPT|CMD_STALE,ACL_CATEGORY_SCRIPTING,SCRIPT_LOAD_Keyspecs,0,NULL,1),.args=SCRIPT_LOAD_Args},
{MAKE_CMD("show","Show server-side Lua script in the script cache.","O(1).","8.0.0",CMD_DOC_NONE,NULL,NULL,"scripting",COMMAND_GROUP_SCRIPTING,SCRIPT_SHOW_History,0,SCRIPT_SHOW_Tips,0,scriptCommand,3,CMD_NOSCRIPT,ACL_CATEGORY_SCRIPTING,SCRIPT_SHOW_Keyspecs,0,NULL,1),.args=SCRIPT_SHOW_Args},
{0}
};

Expand Down
27 changes: 27 additions & 0 deletions src/commands/script-show.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"SHOW": {
"summary": "Show server-side Lua script in the script cache.",
"complexity": "O(1).",
"group": "scripting",
"since": "8.0.0",
"arity": 3,
"container": "SCRIPT",
"function": "scriptCommand",
"command_flags": [
"NOSCRIPT"
],
"acl_categories": [
"SCRIPTING"
],
"arguments": [
{
"name": "sha1",
"type": "string"
}
],
"reply_schema": {
"description": "Lua script if sha1 hash exists in script cache.",
"type": "string"
}
}
}
12 changes: 12 additions & 0 deletions src/eval.c
Original file line number Diff line number Diff line change
Expand Up @@ -682,6 +682,8 @@ void scriptCommand(client *c) {
" Kill the currently executing Lua script.",
"LOAD <script>",
" Load a script into the scripts cache without executing it.",
"SHOW <sha1>",
" Show a script from the scripts cache.",
NULL
};
/* clang-format on */
Expand Down Expand Up @@ -735,6 +737,16 @@ NULL
addReplyError(c, "Use SCRIPT DEBUG YES/SYNC/NO");
return;
}
} else if (c->argc == 3 && !strcasecmp(c->argv[1]->ptr, "show")) {
dictEntry *de;
luaScript *ls;

if (sdslen(c->argv[2]->ptr) == 40 && (de = dictFind(lctx.lua_scripts, c->argv[2]->ptr))) {
ls = dictGetVal(de);
addReplyBulk(c, ls->body);
} else {
addReplyErrorObject(c, shared.noscripterr);
}
} else {
addReplySubcommandSyntaxError(c);
}
Expand Down
2 changes: 1 addition & 1 deletion src/server.c
Original file line number Diff line number Diff line change
Expand Up @@ -1814,7 +1814,7 @@ void createSharedObjects(void) {
shared.syntaxerr = createObject(OBJ_STRING, sdsnew("-ERR syntax error\r\n"));
shared.sameobjecterr = createObject(OBJ_STRING, sdsnew("-ERR source and destination objects are the same\r\n"));
shared.outofrangeerr = createObject(OBJ_STRING, sdsnew("-ERR index out of range\r\n"));
shared.noscripterr = createObject(OBJ_STRING, sdsnew("-NOSCRIPT No matching script. Please use EVAL.\r\n"));
shared.noscripterr = createObject(OBJ_STRING, sdsnew("-NOSCRIPT No matching script.\r\n"));
createSharedObjectsWithCompat();
shared.primarydownerr = createObject(
OBJ_STRING, sdsnew("-MASTERDOWN Link with MASTER is down and replica-serve-stale-data is set to 'no'.\r\n"));
Expand Down
15 changes: 15 additions & 0 deletions tests/unit/scripting.tcl
Original file line number Diff line number Diff line change
Expand Up @@ -638,6 +638,21 @@ start_server {tags {"scripting"}} {
[r evalsha b534286061d4b9e4026607613b95c06c06015ae8 0]
} {b534286061d4b9e4026607613b95c06c06015ae8 loaded}

test {SCRIPT SHOW - is able to dump scripts from the scripting cache} {
r script load "return 'dump'"
r script show 4f5a49d7b18244a3b100d159b78b51474e23e081
} {return 'dump'}

test {SCRIPT SHOW - wrong sha1 length or invalid sha1 char return noscript error} {
assert_error {NOSCRIPT*} {r script show b534286061d4b06c06015ae8}
assert_error {NOSCRIPT*} {r script show AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA}
}

test {SCRIPT SHOW - script not exist return noscript error} {
r script flush
assert_error {NOSCRIPT*} {r script show 4f5a49d7b18244a3b100d159b78b51474e23e081}
}

test "SORT is normally not alpha re-ordered for the scripting engine" {
r del myset
r sadd myset 1 2 3 4 10
Expand Down

0 comments on commit ae2d421

Please sign in to comment.