Redis Functions - Moved invoke Lua code functionality to script_lua.c
The functionality was moved to script_lua.c under callFunction function. Its purpose is to call the Lua function already located on the top of the Lua stack. Used the new function on eval.c to invoke Lua code. The function will also be used to invoke Lua code on the Lua engine.
This commit is contained in:
parent
fc731bc67f
commit
f21dc38a6e
62
src/eval.c
62
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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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_ */
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user