Skip to content

Commit 7043c0f

Browse files
authored
Scripting Engine Debugger Support (#1701)
This PR introduces the support for implementing remote debuggers in scripting engines modules. The module API is extended with scripting engines callbacks and new functions that can be used by scripting engine modules to implement a remote debugger. Most of the code that was used to implement the Lua debugger, was refactored and moved to the `scripting_engine.c` file, and only the code specific to the Lua engine, remained in the `debug_lua.c` file. The `SCRIPT DEBUG (YES|NO|SYNC)` command was extend with an optional parameter that can be used to specify the engine name, where we want to enable the debugger. If no engine name is specified, the Lua engine is used to keep backwards compatibility. In [src/valkeymodule.h](https://github.com/valkey-io/valkey/pull/1701/files#diff-b91520205c29a3a5a940786e509b2f13a5e73a1ac2016be773e62ea64c7efb28) we see the module API changes. And in the `helloscripting.c` file we can see how to implement a simple debugger for the dummy HELLO scripting engine. --------- Signed-off-by: Ricardo Dias <[email protected]>
1 parent f1270a8 commit 7043c0f

File tree

15 files changed

+1800
-618
lines changed

15 files changed

+1800
-618
lines changed

src/commands.def

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5969,6 +5969,7 @@ struct COMMAND_ARG SCRIPT_DEBUG_mode_Subargs[] = {
59695969
/* SCRIPT DEBUG argument table */
59705970
struct COMMAND_ARG SCRIPT_DEBUG_Args[] = {
59715971
{MAKE_ARG("mode",ARG_TYPE_ONEOF,-1,NULL,NULL,NULL,CMD_ARG_NONE,3,NULL),.subargs=SCRIPT_DEBUG_mode_Subargs},
5972+
{MAKE_ARG("engine",ARG_TYPE_STRING,-1,NULL,NULL,"9.1.0",CMD_ARG_OPTIONAL,0,NULL)},
59725973
};
59735974

59745975
/********** SCRIPT EXISTS ********************/
@@ -6115,7 +6116,7 @@ struct COMMAND_ARG SCRIPT_SHOW_Args[] = {
61156116

61166117
/* SCRIPT command table */
61176118
struct COMMAND_STRUCT SCRIPT_Subcommands[] = {
6118-
{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},
6119+
{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,2),.args=SCRIPT_DEBUG_Args},
61196120
{MAKE_CMD("exists","Determines whether server-side Lua scripts exist in the script cache.","O(N) with N being the number of scripts to check (so checking a single script is an O(1) operation).","2.6.0",CMD_DOC_NONE,NULL,NULL,"scripting",COMMAND_GROUP_SCRIPTING,SCRIPT_EXISTS_History,0,SCRIPT_EXISTS_Tips,2,scriptCommand,-3,CMD_NOSCRIPT|CMD_STALE,ACL_CATEGORY_SCRIPTING,SCRIPT_EXISTS_Keyspecs,0,NULL,1),.args=SCRIPT_EXISTS_Args},
61206121
{MAKE_CMD("flush","Removes all server-side Lua scripts from the script cache.","O(N) with N being the number of scripts in cache","2.6.0",CMD_DOC_NONE,NULL,NULL,"scripting",COMMAND_GROUP_SCRIPTING,SCRIPT_FLUSH_History,1,SCRIPT_FLUSH_Tips,2,scriptCommand,-2,CMD_NOSCRIPT|CMD_STALE,ACL_CATEGORY_SCRIPTING,SCRIPT_FLUSH_Keyspecs,0,NULL,1),.args=SCRIPT_FLUSH_Args},
61216122
{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)},

src/commands/script-debug.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"complexity": "O(1)",
55
"group": "scripting",
66
"since": "3.2.0",
7-
"arity": 3,
7+
"arity": -3,
88
"container": "SCRIPT",
99
"function": "scriptCommand",
1010
"command_flags": [
@@ -34,6 +34,12 @@
3434
"token": "NO"
3535
}
3636
]
37+
},
38+
{
39+
"name": "engine",
40+
"type": "string",
41+
"optional": true,
42+
"since": "9.1.0"
3743
}
3844
],
3945
"reply_schema": {

src/eval.c

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@
4949
#include "monotonic.h"
5050
#include "resp_parser.h"
5151
#include "script.h"
52-
#include "lua/debug_lua.h"
5352
#include "scripting_engine.h"
5453
#include "sds.h"
5554

@@ -561,8 +560,9 @@ void evalShaRoCommand(client *c) {
561560
void scriptCommand(client *c) {
562561
if (c->argc == 2 && !strcasecmp(c->argv[1]->ptr, "help")) {
563562
const char *help[] = {
564-
"DEBUG (YES|SYNC|NO)",
565-
" Set the debug mode for subsequent scripts executed.",
563+
"DEBUG (YES|SYNC|NO) [<engine_name>]",
564+
" Set the debug mode for subsequent scripts executed of the specified engine.",
565+
" Default engine name: 'lua'",
566566
"EXISTS <sha1> [<sha1> ...]",
567567
" Return information about the existence of the scripts in the script cache.",
568568
"FLUSH [ASYNC|SYNC]",
@@ -614,19 +614,35 @@ void scriptCommand(client *c) {
614614
zfree(sha);
615615
} else if (c->argc == 2 && !strcasecmp(c->argv[1]->ptr, "kill")) {
616616
scriptKill(c, 1);
617-
} else if (c->argc == 3 && !strcasecmp(c->argv[1]->ptr, "debug")) {
617+
} else if ((c->argc == 3 || c->argc == 4) && !strcasecmp(c->argv[1]->ptr, "debug")) {
618618
if (clientHasPendingReplies(c)) {
619619
addReplyError(c, "SCRIPT DEBUG must be called outside a pipeline");
620620
return;
621621
}
622+
623+
const char *engine_name = c->argc == 4 ? c->argv[3]->ptr : "lua";
624+
scriptingEngine *en = scriptingEngineManagerFind(engine_name);
625+
if (en == NULL) {
626+
addReplyErrorFormat(c, "No scripting engine found with name '%s' to enable debug", engine_name);
627+
return;
628+
}
629+
serverAssert(en != NULL);
630+
631+
sds err;
622632
if (!strcasecmp(c->argv[2]->ptr, "no")) {
623-
ldbDisable(c);
633+
scriptingEngineDebuggerDisable(c);
624634
addReply(c, shared.ok);
625635
} else if (!strcasecmp(c->argv[2]->ptr, "yes")) {
626-
ldbEnable(c);
636+
if (scriptingEngineDebuggerEnable(c, en, &err) != C_OK) {
637+
addReplyErrorSds(c, err);
638+
return;
639+
}
627640
addReply(c, shared.ok);
628641
} else if (!strcasecmp(c->argv[2]->ptr, "sync")) {
629-
ldbEnable(c);
642+
if (scriptingEngineDebuggerEnable(c, en, &err) != C_OK) {
643+
addReplyErrorSds(c, err);
644+
return;
645+
}
630646
addReply(c, shared.ok);
631647
c->flag.lua_debug_sync = 1;
632648
} else {
@@ -674,11 +690,11 @@ unsigned long evalScriptsMemory(void) {
674690
/* Wrapper for EVAL / EVALSHA that enables debugging, and makes sure
675691
* that when EVAL returns, whatever happened, the session is ended. */
676692
void evalGenericCommandWithDebugging(client *c, int evalsha) {
677-
if (ldbStartSession(c)) {
693+
if (scriptingEngineDebuggerStartSession(c)) {
678694
evalGenericCommand(c, evalsha);
679-
ldbEndSession(c);
695+
scriptingEngineDebuggerEndSession(c);
680696
} else {
681-
ldbDisable(c);
697+
scriptingEngineDebuggerDisable(c);
682698
}
683699
}
684700

0 commit comments

Comments
 (0)