summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/eval.c62
-rw-r--r--src/script_lua.c69
-rw-r--r--src/script_lua.h5
-rw-r--r--src/server.h1
4 files changed, 70 insertions, 67 deletions
diff --git a/src/eval.c b/src/eval.c
index 7d5c40a53..f8fe8bf37 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -45,9 +45,6 @@ void ldbInit(void);
void ldbDisable(client *c);
void ldbEnable(client *c);
void evalGenericCommandWithDebugging(client *c, int evalsha);
-void luaLdbLineHook(lua_State *lua, lua_Debug *ar);
-void ldbLog(sds entry);
-void ldbLogRedisReply(char *reply);
sds ldbCatStackValue(sds s, lua_State *lua, int idx);
/* Lua context */
@@ -377,7 +374,6 @@ void evalGenericCommand(client *c, int evalsha) {
char funcname[43];
long long numkeys;
long long initial_server_dirty = server.dirty;
- int delhook = 0, err;
/* When we replicate whole scripts, we want the same PRNG sequence at
* every call so that our PRNG is not affected by external state. */
@@ -443,22 +439,10 @@ void evalGenericCommand(client *c, int evalsha) {
serverAssert(!lua_isnil(lua,-1));
}
- /* Populate the argv and keys table accordingly to the arguments that
- * EVAL received. */
- luaSetGlobalArray(lua,"KEYS",c->argv+3,numkeys);
- luaSetGlobalArray(lua,"ARGV",c->argv+3+numkeys,c->argc-3-numkeys);
-
lctx.lua_cur_script = funcname + 2;
scriptRunCtx rctx;
scriptPrepareForRun(&rctx, lctx.lua_client, c, lctx.lua_cur_script);
-
- /* We must set it before we set the Lua hook, theoretically the
- * Lua hook might be called wheneven we run any Lua instruction
- * such as 'luaSetGlobalArray' and we want the rctx to be available
- * each time the Lua hook is invoked. */
- luaSaveOnRegistry(lua, REGISTRY_RUN_CTX_NAME, &rctx);
-
if (!lctx.lua_replicate_commands) rctx.flags |= SCRIPT_EVAL_REPLICATION;
/* This check is for EVAL_RO, EVALSHA_RO. We want to allow only read only commands */
if ((server.script_caller->cmd->proc == evalRoCommand ||
@@ -466,53 +450,11 @@ void evalGenericCommand(client *c, int evalsha) {
rctx.flags |= SCRIPT_READ_ONLY;
}
- if (server.script_time_limit > 0 && ldb.active == 0) {
- lua_sethook(lua,luaMaskCountHook,LUA_MASKCOUNT,100000);
- delhook = 1;
- } else if (ldb.active) {
- lua_sethook(lctx.lua,luaLdbLineHook,LUA_MASKLINE|LUA_MASKCOUNT,100000);
- delhook = 1;
- }
-
- /* At this point whether this script was never seen before or if it was
- * already defined, we can call it. We have zero arguments and expect
- * a single return value. */
- err = lua_pcall(lua,0,1,-2);
-
+ luaCallFunction(&rctx, lua, c->argv+3, numkeys, c->argv+3+numkeys, c->argc-3-numkeys, ldb.active);
+ lua_pop(lua,1); /* Remove the error handler. */
scriptResetRun(&rctx);
- /* Perform some cleanup that we need to do both on error and success. */
- if (delhook) lua_sethook(lua,NULL,0,0); /* Disable hook */
lctx.lua_cur_script = NULL;
- luaSaveOnRegistry(lua, REGISTRY_RUN_CTX_NAME, NULL);
-
- /* Call the Lua garbage collector from time to time to avoid a
- * full cycle performed by Lua, which adds too latency.
- *
- * The call is performed every LUA_GC_CYCLE_PERIOD executed commands
- * (and for LUA_GC_CYCLE_PERIOD collection steps) because calling it
- * for every command uses too much CPU. */
- #define LUA_GC_CYCLE_PERIOD 50
- {
- static long gc_count = 0;
-
- gc_count++;
- if (gc_count == LUA_GC_CYCLE_PERIOD) {
- lua_gc(lua,LUA_GCSTEP,LUA_GC_CYCLE_PERIOD);
- gc_count = 0;
- }
- }
-
- if (err) {
- addReplyErrorFormat(c,"Error running script (call to %s): %s\n",
- funcname, lua_tostring(lua,-1));
- lua_pop(lua,2); /* Consume the Lua reply and remove error handler. */
- } else {
- /* On success convert the Lua return value into Redis protocol, and
- * send it to * the client. */
- luaReplyToRedisReply(c,rctx.c,lua); /* Convert and consume the reply. */
- lua_pop(lua,1); /* Remove the error handler. */
- }
/* EVALSHA should be propagated to Slave and AOF file as full EVAL, unless
* we are sure that the script was already in the context of all the
diff --git a/src/script_lua.c b/src/script_lua.c
index c7206095c..fb3fa397b 100644
--- a/src/script_lua.c
+++ b/src/script_lua.c
@@ -57,6 +57,7 @@ static void redisProtocolToLuaType_Double(void *ctx, double d, const char *proto
static void redisProtocolToLuaType_BigNumber(void *ctx, const char *str, size_t len, const char *proto, size_t proto_len);
static void redisProtocolToLuaType_VerbatimString(void *ctx, const char *format, const char *str, size_t len, const char *proto, size_t proto_len);
static void redisProtocolToLuaType_Attribute(struct ReplyParser *parser, void *ctx, size_t len, const char *proto);
+static void luaReplyToRedisReply(client *c, client* script_client, lua_State *lua);
/*
* Save the give pointer on Lua registry, used to save the Lua context and
@@ -497,7 +498,7 @@ static void luaSortArray(lua_State *lua) {
/* Reply to client 'c' converting the top element in the Lua stack to a
* Redis reply. As a side effect the element is consumed from the stack. */
-void luaReplyToRedisReply(client *c, client* script_client, lua_State *lua) {
+static void luaReplyToRedisReply(client *c, client* script_client, lua_State *lua) {
int t = lua_type(lua,-1);
if (!lua_checkstack(lua, 4)) {
@@ -1201,7 +1202,7 @@ void luaRegisterRedisAPI(lua_State* lua) {
/* Set an array of Redis String Objects as a Lua array (table) stored into a
* global variable. */
-void luaSetGlobalArray(lua_State *lua, char *var, robj **elev, int elec) {
+static void luaSetGlobalArray(lua_State *lua, char *var, robj **elev, int elec) {
int j;
lua_newtable(lua);
@@ -1256,7 +1257,7 @@ static int redis_math_randomseed (lua_State *L) {
}
/* This is the Lua script "count" hook that we use to detect scripts timeout. */
-void luaMaskCountHook(lua_State *lua, lua_Debug *ar) {
+static void luaMaskCountHook(lua_State *lua, lua_Debug *ar) {
UNUSED(ar);
scriptRunCtx* rctx = luaGetFromRegistry(lua, REGISTRY_RUN_CTX_NAME);
if (scriptInterrupt(rctx) == SCRIPT_KILL) {
@@ -1273,3 +1274,65 @@ void luaMaskCountHook(lua_State *lua, lua_Debug *ar) {
lua_error(lua);
}
}
+
+void luaCallFunction(scriptRunCtx* run_ctx, lua_State *lua, robj** keys, size_t nkeys, robj** args, size_t nargs, int debug_enabled) {
+ client* c = run_ctx->original_client;
+ int delhook = 0;
+
+ /* We must set it before we set the Lua hook, theoretically the
+ * Lua hook might be called wheneven we run any Lua instruction
+ * such as 'luaSetGlobalArray' and we want the run_ctx to be available
+ * each time the Lua hook is invoked. */
+ luaSaveOnRegistry(lua, REGISTRY_RUN_CTX_NAME, run_ctx);
+
+ if (server.script_time_limit > 0 && !debug_enabled) {
+ lua_sethook(lua,luaMaskCountHook,LUA_MASKCOUNT,100000);
+ delhook = 1;
+ } else if (debug_enabled) {
+ lua_sethook(lua,luaLdbLineHook,LUA_MASKLINE|LUA_MASKCOUNT,100000);
+ delhook = 1;
+ }
+
+ /* Populate the argv and keys table accordingly to the arguments that
+ * EVAL received. */
+ luaSetGlobalArray(lua,"KEYS",keys,nkeys);
+ luaSetGlobalArray(lua,"ARGV",args,nargs);
+
+ /* At this point whether this script was never seen before or if it was
+ * already defined, we can call it. We have zero arguments and expect
+ * a single return value. */
+ int err = lua_pcall(lua,0,1,-2);
+
+ /* Call the Lua garbage collector from time to time to avoid a
+ * full cycle performed by Lua, which adds too latency.
+ *
+ * The call is performed every LUA_GC_CYCLE_PERIOD executed commands
+ * (and for LUA_GC_CYCLE_PERIOD collection steps) because calling it
+ * for every command uses too much CPU. */
+ #define LUA_GC_CYCLE_PERIOD 50
+ {
+ static long gc_count = 0;
+
+ gc_count++;
+ if (gc_count == LUA_GC_CYCLE_PERIOD) {
+ lua_gc(lua,LUA_GCSTEP,LUA_GC_CYCLE_PERIOD);
+ gc_count = 0;
+ }
+ }
+
+ if (err) {
+ addReplyErrorFormat(c,"Error running script (call to %s): %s\n",
+ run_ctx->funcname, lua_tostring(lua,-1));
+ lua_pop(lua,1); /* Consume the Lua reply and remove error handler. */
+ } else {
+ /* On success convert the Lua return value into Redis protocol, and
+ * send it to * the client. */
+ luaReplyToRedisReply(c, run_ctx->c, lua); /* Convert and consume the reply. */
+ }
+
+ /* Perform some cleanup that we need to do both on error and success. */
+ if (delhook) lua_sethook(lua,NULL,0,0); /* Disable hook */
+
+ /* remove run_ctx from registry, its only applicable for the current script. */
+ luaSaveOnRegistry(lua, REGISTRY_RUN_CTX_NAME, NULL);
+}
diff --git a/src/script_lua.h b/src/script_lua.h
index 5ae9225bc..c18ad40bd 100644
--- a/src/script_lua.h
+++ b/src/script_lua.h
@@ -58,12 +58,9 @@
void luaRegisterRedisAPI(lua_State* lua);
void luaEnableGlobalsProtection(lua_State *lua);
-void luaSetGlobalArray(lua_State *lua, char *var, robj **elev, int elec);
-void luaMaskCountHook(lua_State *lua, lua_Debug *ar);
-void luaReplyToRedisReply(client *c, client* script_client, lua_State *lua);
void luaSaveOnRegistry(lua_State* lua, const char* name, void* ptr);
void* luaGetFromRegistry(lua_State* lua, const char* name);
-
+void luaCallFunction(scriptRunCtx* r_ctx, lua_State *lua, robj** keys, size_t nkeys, robj** args, size_t nargs, int debug_enabled);
#endif /* __SCRIPT_LUA_H_ */
diff --git a/src/server.h b/src/server.h
index 2b1ef1ce7..3511ff04b 100644
--- a/src/server.h
+++ b/src/server.h
@@ -2706,6 +2706,7 @@ int ldbRemoveChild(pid_t pid);
void ldbKillForkedSessions(void);
int ldbPendingChildren(void);
sds luaCreateFunction(client *c, robj *body);
+void luaLdbLineHook(lua_State *lua, lua_Debug *ar);
void freeLuaScriptsAsync(dict *lua_scripts);
int ldbIsEnabled();
void ldbLog(sds entry);