summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/acl.c2
-rw-r--r--src/config.c2
-rw-r--r--src/db.c4
-rw-r--r--src/debug.c2
-rw-r--r--src/defrag.c2
-rw-r--r--src/eval.c171
-rw-r--r--src/evict.c2
-rw-r--r--src/module.c8
-rw-r--r--src/networking.c2
-rw-r--r--src/object.c6
-rw-r--r--src/rdb.c6
-rw-r--r--src/script_lua.c82
-rw-r--r--src/script_lua.h65
-rw-r--r--src/server.c30
-rw-r--r--src/server.h39
15 files changed, 253 insertions, 170 deletions
diff --git a/src/acl.c b/src/acl.c
index 5d1598b39..9c23cffa8 100644
--- a/src/acl.c
+++ b/src/acl.c
@@ -1897,7 +1897,7 @@ void addACLLogEntry(client *c, int reason, int context, int argpos, sds username
}
client *realclient = c;
- if (realclient->flags & CLIENT_LUA) realclient = server.lua_caller;
+ if (realclient->flags & CLIENT_LUA) realclient = server.script_caller;
le->cinfo = catClientInfoString(sdsempty(),realclient);
le->context = context;
diff --git a/src/config.c b/src/config.c
index 2b2ff737d..939a5342c 100644
--- a/src/config.c
+++ b/src/config.c
@@ -2650,7 +2650,7 @@ standardConfig configs[] = {
createULongConfig("acllog-max-len", NULL, MODIFIABLE_CONFIG, 0, LONG_MAX, server.acllog_max_len, 128, INTEGER_CONFIG, NULL, NULL),
/* Long Long configs */
- createLongLongConfig("lua-time-limit", NULL, MODIFIABLE_CONFIG, 0, LONG_MAX, server.lua_time_limit, 5000, INTEGER_CONFIG, NULL, NULL),/* milliseconds */
+ createLongLongConfig("script-time-limit", "lua-time-limit", MODIFIABLE_CONFIG, 0, LONG_MAX, server.script_time_limit, 5000, INTEGER_CONFIG, NULL, NULL),/* milliseconds */
createLongLongConfig("cluster-node-timeout", NULL, MODIFIABLE_CONFIG, 0, LLONG_MAX, server.cluster_node_timeout, 15000, INTEGER_CONFIG, NULL, NULL),
createLongLongConfig("slowlog-log-slower-than", NULL, MODIFIABLE_CONFIG, -1, LLONG_MAX, server.slowlog_log_slower_than, 10000, INTEGER_CONFIG, NULL, NULL),
createLongLongConfig("latency-monitor-threshold", NULL, MODIFIABLE_CONFIG, 0, LLONG_MAX, server.latency_monitor_threshold, 0, INTEGER_CONFIG, NULL, NULL),
diff --git a/src/db.c b/src/db.c
index b98310cf3..749f5535b 100644
--- a/src/db.c
+++ b/src/db.c
@@ -1501,8 +1501,8 @@ int keyIsExpired(redisDb *db, robj *key) {
* only the first time it is accessed and not in the middle of the
* script execution, making propagation to slaves / AOF consistent.
* See issue #1525 on Github for more information. */
- if (server.lua_caller) {
- now = server.lua_time_snapshot;
+ if (server.script_caller) {
+ now = evalTimeSnapshot();
}
/* If we are in the middle of a command execution, we still want to use
* a reference time that does not change: in that case we just use the
diff --git a/src/debug.c b/src/debug.c
index 8776de38f..d4f3f5dd2 100644
--- a/src/debug.c
+++ b/src/debug.c
@@ -919,7 +919,7 @@ NULL
addReplyStatus(c,"Apparently Redis did not crash: test passed");
} else if (!strcasecmp(c->argv[1]->ptr,"set-disable-deny-scripts") && c->argc == 3)
{
- server.lua_disable_deny_script = atoi(c->argv[2]->ptr);;
+ server.script_disable_deny_script = atoi(c->argv[2]->ptr);;
addReply(c,shared.ok);
} else if (!strcasecmp(c->argv[1]->ptr,"config-rewrite-force-all") && c->argc == 2)
{
diff --git a/src/defrag.c b/src/defrag.c
index 734174c3a..ffd6eaba6 100644
--- a/src/defrag.c
+++ b/src/defrag.c
@@ -939,7 +939,7 @@ long defragOtherGlobals() {
/* there are many more pointers to defrag (e.g. client argv, output / aof buffers, etc.
* but we assume most of these are short lived, we only need to defrag allocations
* that remain static for a long time */
- defragged += activeDefragSdsDict(server.lua_scripts, DEFRAG_SDS_DICT_VAL_IS_STROB);
+ defragged += activeDefragSdsDict(evalScriptsDict(), DEFRAG_SDS_DICT_VAL_IS_STROB);
defragged += activeDefragSdsListAndDict(server.repl_scriptcache_fifo, server.repl_scriptcache_dict, DEFRAG_SDS_DICT_NO_VAL);
defragged += moduleDefragGlobals();
return defragged;
diff --git a/src/eval.c b/src/eval.c
index 6e6aeac7c..5c4c419b5 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -50,6 +50,9 @@ void ldbLog(sds entry);
void ldbLogRedisReply(char *reply);
sds ldbCatStackValue(sds s, lua_State *lua, int idx);
+/* Lua context */
+luaCtx lctx;
+
/* Debugger shared state is stored inside this global structure. */
#define LDB_BREAKPOINTS_MAX 64 /* Max number of breakpoints. */
#define LDB_MAX_LEN_DEFAULT 256 /* Default len limit for replies / var dumps. */
@@ -138,10 +141,10 @@ int luaRedisDebugCommand(lua_State *lua) {
* already started to write, returns false and stick to whole scripts
* replication, which is our default. */
int luaRedisReplicateCommandsCommand(lua_State *lua) {
- if (server.lua_write_dirty) {
+ if (lctx.lua_write_dirty) {
lua_pushboolean(lua,0);
} else {
- server.lua_replicate_commands = 1;
+ lctx.lua_replicate_commands = 1;
/* When we switch to single commands replication, we can provide
* different math.random() sequences at every call, which is what
* the user normally expects. */
@@ -165,19 +168,19 @@ void scriptingInit(int setup) {
lua_State *lua = lua_open();
if (setup) {
- server.lua_client = NULL;
- server.lua_caller = NULL;
- server.lua_cur_script = NULL;
- server.lua_timedout = 0;
- server.lua_disable_deny_script = 0;
+ lctx.lua_client = NULL;
+ server.script_caller = NULL;
+ lctx.lua_cur_script = NULL;
+ server.script_timedout = 0;
+ server.script_disable_deny_script = 0;
ldbInit();
}
/* Initialize a dictionary we use to map SHAs to scripts.
* This is useful for replication, as we need to replicate EVALSHA
* as EVAL, so we need to remember the associated script. */
- server.lua_scripts = dictCreate(&shaScriptObjectDictType);
- server.lua_scripts_mem = 0;
+ lctx.lua_scripts = dictCreate(&shaScriptObjectDictType);
+ lctx.lua_scripts_mem = 0;
luaEngineRegisterRedisAPI(lua);
@@ -238,12 +241,12 @@ void scriptingInit(int setup) {
* inside the Lua interpreter.
* Note: there is no need to create it again when this function is called
* by scriptingReset(). */
- if (server.lua_client == NULL) {
- server.lua_client = createClient(NULL);
- server.lua_client->flags |= CLIENT_LUA;
+ if (lctx.lua_client == NULL) {
+ lctx.lua_client = createClient(NULL);
+ lctx.lua_client->flags |= CLIENT_LUA;
/* We do not want to allow blocking commands inside Lua */
- server.lua_client->flags |= CLIENT_DENY_BLOCKING;
+ lctx.lua_client->flags |= CLIENT_DENY_BLOCKING;
}
/* Lua beginners often don't use "local", this is likely to introduce
@@ -251,18 +254,18 @@ void scriptingInit(int setup) {
* to global variables. */
scriptingEnableGlobalsProtection(lua);
- server.lua = lua;
+ lctx.lua = lua;
}
/* Release resources related to Lua scripting.
* This function is used in order to reset the scripting environment. */
void scriptingRelease(int async) {
if (async)
- freeLuaScriptsAsync(server.lua_scripts);
+ freeLuaScriptsAsync(lctx.lua_scripts);
else
- dictRelease(server.lua_scripts);
- server.lua_scripts_mem = 0;
- lua_close(server.lua);
+ dictRelease(lctx.lua_scripts);
+ lctx.lua_scripts_mem = 0;
+ lua_close(lctx.lua);
}
void scriptingReset(int async) {
@@ -291,7 +294,7 @@ void scriptingReset(int async) {
*
* If 'c' is not NULL, on error the client is informed with an appropriate
* error describing the nature of the problem and the Lua interpreter error. */
-sds luaCreateFunction(client *c, lua_State *lua, robj *body) {
+sds luaCreateFunction(client *c, robj *body) {
char funcname[43];
dictEntry *de;
@@ -300,7 +303,7 @@ sds luaCreateFunction(client *c, lua_State *lua, robj *body) {
sha1hex(funcname+2,body->ptr,sdslen(body->ptr));
sds sha = sdsnewlen(funcname+2,40);
- if ((de = dictFind(server.lua_scripts,sha)) != NULL) {
+ if ((de = dictFind(lctx.lua_scripts,sha)) != NULL) {
sdsfree(sha);
return dictGetKey(de);
}
@@ -312,25 +315,25 @@ sds luaCreateFunction(client *c, lua_State *lua, robj *body) {
funcdef = sdscatlen(funcdef,body->ptr,sdslen(body->ptr));
funcdef = sdscatlen(funcdef,"\nend",4);
- if (luaL_loadbuffer(lua,funcdef,sdslen(funcdef),"@user_script")) {
+ if (luaL_loadbuffer(lctx.lua,funcdef,sdslen(funcdef),"@user_script")) {
if (c != NULL) {
addReplyErrorFormat(c,
"Error compiling script (new function): %s\n",
- lua_tostring(lua,-1));
+ lua_tostring(lctx.lua,-1));
}
- lua_pop(lua,1);
+ lua_pop(lctx.lua,1);
sdsfree(sha);
sdsfree(funcdef);
return NULL;
}
sdsfree(funcdef);
- if (lua_pcall(lua,0,0,0)) {
+ if (lua_pcall(lctx.lua,0,0,0)) {
if (c != NULL) {
addReplyErrorFormat(c,"Error running script (new function): %s\n",
- lua_tostring(lua,-1));
+ lua_tostring(lctx.lua,-1));
}
- lua_pop(lua,1);
+ lua_pop(lctx.lua,1);
sdsfree(sha);
return NULL;
}
@@ -338,31 +341,31 @@ sds luaCreateFunction(client *c, lua_State *lua, robj *body) {
/* We also save a SHA1 -> Original script map in a dictionary
* so that we can replicate / write in the AOF all the
* EVALSHA commands as EVAL using the original script. */
- int retval = dictAdd(server.lua_scripts,sha,body);
- serverAssertWithInfo(c ? c : server.lua_client,NULL,retval == DICT_OK);
- server.lua_scripts_mem += sdsZmallocSize(sha) + getStringObjectSdsUsedMemory(body);
+ int retval = dictAdd(lctx.lua_scripts,sha,body);
+ serverAssertWithInfo(c ? c : lctx.lua_client,NULL,retval == DICT_OK);
+ lctx.lua_scripts_mem += sdsZmallocSize(sha) + getStringObjectSdsUsedMemory(body);
incrRefCount(body);
return sha;
}
void prepareLuaClient(void) {
/* Select the right DB in the context of the Lua client */
- selectDb(server.lua_client,server.lua_caller->db->id);
- server.lua_client->resp = 2; /* Default is RESP2, scripts can change it. */
+ selectDb(lctx.lua_client,server.script_caller->db->id);
+ lctx.lua_client->resp = 2; /* Default is RESP2, scripts can change it. */
/* If we are in MULTI context, flag Lua client as CLIENT_MULTI. */
- if (server.lua_caller->flags & CLIENT_MULTI) {
- server.lua_client->flags |= CLIENT_MULTI;
+ if (server.script_caller->flags & CLIENT_MULTI) {
+ lctx.lua_client->flags |= CLIENT_MULTI;
}
}
void resetLuaClient(void) {
/* After the script done, remove the MULTI state. */
- server.lua_client->flags &= ~CLIENT_MULTI;
+ lctx.lua_client->flags &= ~CLIENT_MULTI;
}
void evalGenericCommand(client *c, int evalsha) {
- lua_State *lua = server.lua;
+ lua_State *lua = lctx.lua;
char funcname[43];
long long numkeys;
long long initial_server_dirty = server.dirty;
@@ -380,11 +383,11 @@ void evalGenericCommand(client *c, int evalsha) {
*
* Thanks to this flag we'll raise an error every time a write command
* is called after a random command was used. */
- server.lua_random_dirty = 0;
- server.lua_write_dirty = 0;
- server.lua_replicate_commands = server.lua_always_replicate_commands;
- server.lua_multi_emitted = 0;
- server.lua_repl = PROPAGATE_AOF|PROPAGATE_REPL;
+ lctx.lua_random_dirty = 0;
+ lctx.lua_write_dirty = 0;
+ lctx.lua_replicate_commands = server.lua_always_replicate_commands;
+ lctx.lua_multi_emitted = 0;
+ lctx.lua_repl = PROPAGATE_AOF|PROPAGATE_REPL;
/* Get the number of arguments that are keys */
if (getLongLongFromObjectOrReply(c,c->argv[2],&numkeys,NULL) != C_OK)
@@ -433,7 +436,7 @@ void evalGenericCommand(client *c, int evalsha) {
addReplyErrorObject(c, shared.noscripterr);
return;
}
- if (luaCreateFunction(c,lua,c->argv[1]) == NULL) {
+ if (luaCreateFunction(c,c->argv[1]) == NULL) {
lua_pop(lua,1); /* remove the error handler from the stack. */
/* The error is sent to the client by luaCreateFunction()
* itself when it returns NULL. */
@@ -456,17 +459,17 @@ void evalGenericCommand(client *c, int evalsha) {
*
* If we are debugging, we set instead a "line" hook so that the
* debugger is call-back at every line executed by the script. */
- server.in_eval = 1;
- server.lua_caller = c;
- server.lua_cur_script = funcname + 2;
- server.lua_time_start = getMonotonicUs();
- server.lua_time_snapshot = mstime();
- server.lua_kill = 0;
- if (server.lua_time_limit > 0 && ldb.active == 0) {
+ server.in_script = 1;
+ server.script_caller = c;
+ lctx.lua_cur_script = funcname + 2;
+ lctx.lua_time_start = getMonotonicUs();
+ lctx.lua_time_snapshot = mstime();
+ lctx.lua_kill = 0;
+ if (server.script_time_limit > 0 && ldb.active == 0) {
lua_sethook(lua,luaMaskCountHook,LUA_MASKCOUNT,100000);
delhook = 1;
} else if (ldb.active) {
- lua_sethook(server.lua,luaLdbLineHook,LUA_MASKLINE|LUA_MASKCOUNT,100000);
+ lua_sethook(lctx.lua,luaLdbLineHook,LUA_MASKLINE|LUA_MASKCOUNT,100000);
delhook = 1;
}
@@ -481,8 +484,8 @@ void evalGenericCommand(client *c, int evalsha) {
/* Perform some cleanup that we need to do both on error and success. */
if (delhook) lua_sethook(lua,NULL,0,0); /* Disable hook */
- if (server.lua_timedout) {
- server.lua_timedout = 0;
+ if (server.script_timedout) {
+ server.script_timedout = 0;
blockingOperationEnds();
/* Restore the client that was protected when the script timeout
* was detected. */
@@ -490,9 +493,9 @@ void evalGenericCommand(client *c, int evalsha) {
if (server.masterhost && server.master)
queueClientForReprocessing(server.master);
}
- server.in_eval = 0;
- server.lua_caller = NULL;
- server.lua_cur_script = NULL;
+ server.in_script = 0;
+ server.script_caller = NULL;
+ lctx.lua_cur_script = NULL;
/* Call the Lua garbage collector from time to time to avoid a
* full cycle performed by Lua, which adds too latency.
@@ -524,9 +527,9 @@ void evalGenericCommand(client *c, int evalsha) {
/* If we are using single commands replication, emit EXEC if there
* was at least a write. */
- if (server.lua_replicate_commands) {
+ if (lctx.lua_replicate_commands) {
preventCommandPropagation(c);
- if (server.lua_multi_emitted) {
+ if (lctx.lua_multi_emitted) {
execCommandPropagateExec(c->db->id);
}
}
@@ -541,12 +544,12 @@ void evalGenericCommand(client *c, int evalsha) {
* For replication, every time a new slave attaches to the master, we need to
* flush our cache of scripts that can be replicated as EVALSHA, while
* for AOF we need to do so every time we rewrite the AOF file. */
- if (evalsha && !server.lua_replicate_commands) {
+ if (evalsha && !lctx.lua_replicate_commands) {
if (!replicationScriptCacheExists(c->argv[1]->ptr)) {
/* This script is not in our script cache, replicate it as
* EVAL, then add it into the script cache, as from now on
* slaves and AOF know about it. */
- robj *script = dictFetchValue(server.lua_scripts,c->argv[1]->ptr);
+ robj *script = dictFetchValue(lctx.lua_scripts,c->argv[1]->ptr);
replicationScriptCacheAdd(c->argv[1]->ptr);
serverAssertWithInfo(c,NULL,script != NULL);
@@ -648,25 +651,25 @@ NULL
addReplyArrayLen(c, c->argc-2);
for (j = 2; j < c->argc; j++) {
- if (dictFind(server.lua_scripts,c->argv[j]->ptr))
+ if (dictFind(lctx.lua_scripts,c->argv[j]->ptr))
addReply(c,shared.cone);
else
addReply(c,shared.czero);
}
} else if (c->argc == 3 && !strcasecmp(c->argv[1]->ptr,"load")) {
- sds sha = luaCreateFunction(c,server.lua,c->argv[2]);
+ sds sha = luaCreateFunction(c,c->argv[2]);
if (sha == NULL) return; /* The error was sent by luaCreateFunction(). */
addReplyBulkCBuffer(c,sha,40);
forceCommandPropagation(c,PROPAGATE_REPL|PROPAGATE_AOF);
} else if (c->argc == 2 && !strcasecmp(c->argv[1]->ptr,"kill")) {
- if (server.lua_caller == NULL) {
+ if (server.script_caller == NULL) {
addReplyError(c,"-NOTBUSY No scripts in execution right now.");
- } else if (server.lua_caller->flags & CLIENT_MASTER) {
+ } else if (server.script_caller->flags & CLIENT_MASTER) {
addReplyError(c,"-UNKILLABLE The busy script was sent by a master instance in the context of replication and cannot be killed.");
- } else if (server.lua_write_dirty) {
+ } else if (lctx.lua_write_dirty) {
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 {
- server.lua_kill = 1;
+ lctx.lua_kill = 1;
addReply(c,shared.ok);
}
} else if (c->argc == 3 && !strcasecmp(c->argv[1]->ptr,"debug")) {
@@ -693,6 +696,26 @@ NULL
}
}
+unsigned long evalMemory() {
+ return lua_gc(lctx.lua, LUA_GCCOUNT, 0) * 1024LL;
+}
+
+dict* evalScriptsDict() {
+ return lctx.lua_scripts;
+}
+
+unsigned long evalScriptsMemory() {
+ return lctx.lua_scripts_mem +
+ dictSize(lctx.lua_scripts) * sizeof(dictEntry) +
+ dictSlots(lctx.lua_scripts) * sizeof(dictEntry*);
+}
+
+/* Returns the time when the script invocation started */
+mstime_t evalTimeSnapshot() {
+ return lctx.lua_time_snapshot;
+}
+
+
/* ---------------------------------------------------------------------------
* LDB: Redis Lua debugging facilities
* ------------------------------------------------------------------------- */
@@ -717,6 +740,10 @@ void ldbFlushLog(list *log) {
listDelNode(log,ln);
}
+int ldbIsEnabled(){
+ return ldb.active && ldb.step;
+}
+
/* Enable debug mode of Lua scripts for this client. */
void ldbEnable(client *c) {
c->flags |= CLIENT_LUA_DEBUG;
@@ -1447,7 +1474,7 @@ void ldbEval(lua_State *lua, sds *argv, int argc) {
* implementation, with ldb.step enabled, so as a side effect the Redis command
* and its reply are logged. */
void ldbRedis(lua_State *lua, sds *argv, int argc) {
- int j, saved_rc = server.lua_replicate_commands;
+ int j, saved_rc = lctx.lua_replicate_commands;
if (!lua_checkstack(lua, argc + 1)) {
/* Increase the Lua stack if needed to make sure there is enough room
@@ -1466,10 +1493,10 @@ void ldbRedis(lua_State *lua, sds *argv, int argc) {
for (j = 1; j < argc; j++)
lua_pushlstring(lua,argv[j],sdslen(argv[j]));
ldb.step = 1; /* Force redis.call() to log. */
- server.lua_replicate_commands = 1;
+ lctx.lua_replicate_commands = 1;
lua_pcall(lua,argc-1,1,0); /* Stack: redis, result */
ldb.step = 0; /* Disable logging. */
- server.lua_replicate_commands = saved_rc;
+ lctx.lua_replicate_commands = saved_rc;
lua_pop(lua,2); /* Discard the result and clean the stack. */
}
@@ -1657,9 +1684,9 @@ void luaLdbLineHook(lua_State *lua, lua_Debug *ar) {
/* Check if a timeout occurred. */
if (ar->event == LUA_HOOKCOUNT && ldb.step == 0 && bp == 0) {
- mstime_t elapsed = elapsedMs(server.lua_time_start);
- mstime_t timelimit = server.lua_time_limit ?
- server.lua_time_limit : 5000;
+ mstime_t elapsed = elapsedMs(server.script_time_limit);
+ mstime_t timelimit = server.script_time_limit ?
+ server.script_time_limit : 5000;
if (elapsed >= timelimit) {
timeout = 1;
ldb.step = 1;
@@ -1687,7 +1714,7 @@ void luaLdbLineHook(lua_State *lua, lua_Debug *ar) {
lua_pushstring(lua, "timeout during Lua debugging with client closing connection");
lua_error(lua);
}
- server.lua_time_start = getMonotonicUs();
- server.lua_time_snapshot = mstime();
+ lctx.lua_time_start = getMonotonicUs();
+ lctx.lua_time_snapshot = mstime();
}
}
diff --git a/src/evict.c b/src/evict.c
index 4186378a2..2d87546cb 100644
--- a/src/evict.c
+++ b/src/evict.c
@@ -472,7 +472,7 @@ static int evictionTimeProc(
static int isSafeToPerformEvictions(void) {
/* - There must be no script in timeout condition.
* - Nor we are loading data right now. */
- if (server.lua_timedout || server.loading) return 0;
+ if (server.script_timedout || server.loading) return 0;
/* By default replicas should ignore maxmemory
* and just be masters exact copies. */
diff --git a/src/module.c b/src/module.c
index 7c1cc054b..bc7599b75 100644
--- a/src/module.c
+++ b/src/module.c
@@ -629,7 +629,7 @@ void moduleHandlePropagationAfterCommandCallback(RedisModuleCtx *ctx) {
/* If this command is executed from with Lua or MULTI/EXEC we do not
* need to propagate EXEC */
- if (server.in_eval || server.in_exec) return;
+ if (server.in_script || server.in_exec) return;
/* Handle the replication of the final EXEC, since whatever a command
* emits is always wrapped around MULTI/EXEC. */
@@ -2333,7 +2333,7 @@ int RM_ReplyWithLongDouble(RedisModuleCtx *ctx, long double ld) {
void moduleReplicateMultiIfNeeded(RedisModuleCtx *ctx) {
/* Skip this if client explicitly wrap the command with MULTI, or if
* the module command was called by a script. */
- if (server.in_eval || server.in_exec) return;
+ if (server.in_script || server.in_exec) return;
/* If we already emitted MULTI return ASAP. */
if (server.propagate_in_transaction) return;
/* If this is a thread safe context, we do not want to wrap commands
@@ -2709,7 +2709,7 @@ int RM_GetContextFlags(RedisModuleCtx *ctx) {
}
}
- if (server.in_eval)
+ if (server.in_script)
flags |= REDISMODULE_CTX_FLAGS_LUA;
if (server.in_exec)
@@ -6215,7 +6215,7 @@ void unblockClientFromModule(client *c) {
*/
RedisModuleBlockedClient *moduleBlockClient(RedisModuleCtx *ctx, RedisModuleCmdFunc reply_callback, RedisModuleCmdFunc timeout_callback, void (*free_privdata)(RedisModuleCtx*,void*), long long timeout_ms, RedisModuleString **keys, int numkeys, void *privdata) {
client *c = ctx->client;
- int islua = server.in_eval;
+ int islua = server.in_script;
int ismulti = server.in_exec;
c->bpop.module_blocked_handle = zmalloc(sizeof(RedisModuleBlockedClient));
diff --git a/src/networking.c b/src/networking.c
index 1f1a2e169..fb4a487a3 100644
--- a/src/networking.c
+++ b/src/networking.c
@@ -2199,7 +2199,7 @@ int processInputBuffer(client *c) {
* condition on the slave. We want just to accumulate the replication
* stream (instead of replying -BUSY like we do with other clients) and
* later resume the processing. */
- if (server.lua_timedout && c->flags & CLIENT_MASTER) break;
+ if (server.script_timedout && c->flags & CLIENT_MASTER) break;
/* CLIENT_CLOSE_AFTER_REPLY closes the connection once the reply is
* written to the client. Make sure to not let the reply grow after
diff --git a/src/object.c b/src/object.c
index 5831f196d..dab0648a8 100644
--- a/src/object.c
+++ b/src/object.c
@@ -1203,9 +1203,7 @@ struct redisMemOverhead *getMemoryOverheadData(void) {
mh->aof_buffer = mem;
mem_total+=mem;
- mem = server.lua_scripts_mem;
- mem += dictSize(server.lua_scripts) * sizeof(dictEntry) +
- dictSlots(server.lua_scripts) * sizeof(dictEntry*);
+ mem = evalScriptsMemory();
mem += dictSize(server.repl_scriptcache_dict) * sizeof(dictEntry) +
dictSlots(server.repl_scriptcache_dict) * sizeof(dictEntry*);
if (listLength(server.repl_scriptcache_fifo) > 0) {
@@ -1325,7 +1323,7 @@ sds getMemoryDoctorReport(void) {
}
/* Too many scripts are cached? */
- if (dictSize(server.lua_scripts) > 1000) {
+ if (dictSize(evalScriptsDict()) > 1000) {
many_scripts = 1;
num_reports++;
}
diff --git a/src/rdb.c b/src/rdb.c
index 4a65f2cc9..dcbc83785 100644
--- a/src/rdb.c
+++ b/src/rdb.c
@@ -1303,8 +1303,8 @@ int rdbSaveRio(rio *rdb, int *error, int rdbflags, rdbSaveInfo *rsi) {
* the script cache as well: on successful PSYNC after a restart, we need
* to be able to process any EVALSHA inside the replication backlog the
* master will send us. */
- if (rsi && dictSize(server.lua_scripts)) {
- di = dictGetIterator(server.lua_scripts);
+ if (rsi && dictSize(evalScriptsDict())) {
+ di = dictGetIterator(evalScriptsDict());
while((de = dictNext(di)) != NULL) {
robj *body = dictGetVal(de);
if (rdbSaveAuxField(rdb,"lua",3,body->ptr,sdslen(body->ptr)) == -1)
@@ -2808,7 +2808,7 @@ int rdbLoadRio(rio *rdb, int rdbflags, rdbSaveInfo *rsi, redisDb *dbarray) {
if (rsi) rsi->repl_offset = strtoll(auxval->ptr,NULL,10);
} else if (!strcasecmp(auxkey->ptr,"lua")) {
/* Load the script back in memory. */
- if (luaCreateFunction(NULL,server.lua,auxval) == NULL) {
+ if (luaCreateFunction(NULL, auxval) == NULL) {
rdbReportCorruptRDB(
"Can't load Lua script from RDB file! "
"BODY: %s", (char*)auxval->ptr);
diff --git a/src/script_lua.c b/src/script_lua.c
index 0685a4bb3..bee5d6c93 100644
--- a/src/script_lua.c
+++ b/src/script_lua.c
@@ -399,7 +399,7 @@ void luaPushError(lua_State *lua, char *error) {
/* If debugging is active and in step mode, log errors resulting from
* Redis commands. */
- if (ldb.active && ldb.step) {
+ if (ldbIsEnabled()) {
ldbLog(sdscatprintf(sdsempty(),"<error> %s",error));
}
@@ -483,7 +483,7 @@ void luaReplyToRedisReply(client *c, lua_State *lua) {
addReplyBulkCBuffer(c,(char*)lua_tostring(lua,-1),lua_strlen(lua,-1));
break;
case LUA_TBOOLEAN:
- if (server.lua_client->resp == 2)
+ if (lctx.lua_client->resp == 2)
addReply(c,lua_toboolean(lua,-1) ? shared.cone :
shared.null[c->resp]);
else
@@ -653,7 +653,7 @@ void luaReplyToRedisReply(client *c, lua_State *lua) {
int luaRedisGenericCommand(lua_State *lua, int raise_error) {
int j, argc = lua_gettop(lua);
struct redisCommand *cmd;
- client *c = server.lua_client;
+ client *c = lctx.lua_client;
sds reply;
/* Cached across calls. */
@@ -744,7 +744,7 @@ int luaRedisGenericCommand(lua_State *lua, int raise_error) {
/* Setup our fake client for command execution */
c->argv = argv;
c->argc = argc;
- c->user = server.lua_caller->user;
+ c->user = server.script_caller->user;
/* Process module hooks */
moduleCallCommandFilters(c);
@@ -752,7 +752,7 @@ int luaRedisGenericCommand(lua_State *lua, int raise_error) {
argc = c->argc;
/* Log the command if debugging is active. */
- if (ldb.active && ldb.step) {
+ if (ldbIsEnabled()) {
sds cmdlog = sdsnew("<redis>");
for (j = 0; j < c->argc; j++) {
if (j == 10) {
@@ -782,14 +782,14 @@ int luaRedisGenericCommand(lua_State *lua, int raise_error) {
c->cmd = c->lastcmd = cmd;
/* There are commands that are not allowed inside scripts. */
- if (!server.lua_disable_deny_script && (cmd->flags & CMD_NOSCRIPT)) {
+ if (!server.script_disable_deny_script && (cmd->flags & CMD_NOSCRIPT)) {
luaPushError(lua, "This Redis command is not allowed from scripts");
goto cleanup;
}
/* This check is for EVAL_RO, EVALSHA_RO. We want to allow only read only commands */
- if ((server.lua_caller->cmd->proc == evalRoCommand ||
- server.lua_caller->cmd->proc == evalShaRoCommand) &&
+ if ((server.script_caller->cmd->proc == evalRoCommand ||
+ server.script_caller->cmd->proc == evalShaRoCommand) &&
(cmd->flags & CMD_WRITE))
{
luaPushError(lua, "Write commands are not allowed from read-only scripts");
@@ -828,13 +828,13 @@ int luaRedisGenericCommand(lua_State *lua, int raise_error) {
* of this script. */
if (cmd->flags & CMD_WRITE) {
int deny_write_type = writeCommandsDeniedByDiskError();
- if (server.lua_random_dirty && !server.lua_replicate_commands) {
+ if (lctx.lua_random_dirty && !lctx.lua_replicate_commands) {
luaPushError(lua,
"Write commands not allowed after non deterministic commands. Call redis.replicate_commands() at the start of your script in order to switch to single commands replication mode.");
goto cleanup;
} else if (server.masterhost && server.repl_slave_ro &&
- server.lua_caller->id != CLIENT_ID_AOF &&
- !(server.lua_caller->flags & CLIENT_MASTER))
+ server.script_caller->id != CLIENT_ID_AOF &&
+ !(server.script_caller->flags & CLIENT_MASTER))
{
luaPushError(lua, shared.roslaveerr->ptr);
goto cleanup;
@@ -857,29 +857,29 @@ int luaRedisGenericCommand(lua_State *lua, int raise_error) {
* first write in the context of this script, otherwise we can't stop
* in the middle. */
if (server.maxmemory && /* Maxmemory is actually enabled. */
- server.lua_caller->id != CLIENT_ID_AOF && /* Don't care about mem if loading from AOF. */
+ server.script_caller->id != CLIENT_ID_AOF && /* Don't care about mem if loading from AOF. */
!server.masterhost && /* Slave must execute the script. */
- server.lua_write_dirty == 0 && /* Script had no side effects so far. */
- server.lua_oom && /* Detected OOM when script start. */
+ lctx.lua_write_dirty == 0 && /* Script had no side effects so far. */
+ server.script_oom && /* Detected OOM when script start. */
(cmd->flags & CMD_DENYOOM))
{
luaPushError(lua, shared.oomerr->ptr);
goto cleanup;
}
- if (cmd->flags & CMD_RANDOM) server.lua_random_dirty = 1;
- if (cmd->flags & CMD_WRITE) server.lua_write_dirty = 1;
+ if (cmd->flags & CMD_RANDOM) lctx.lua_random_dirty = 1;
+ if (cmd->flags & CMD_WRITE) lctx.lua_write_dirty = 1;
/* If this is a Redis Cluster node, we need to make sure Lua is not
* trying to access non-local keys, with the exception of commands
* received from our master or when loading the AOF back in memory. */
- if (server.cluster_enabled && server.lua_caller->id != CLIENT_ID_AOF &&
- !(server.lua_caller->flags & CLIENT_MASTER))
+ if (server.cluster_enabled && server.script_caller->id != CLIENT_ID_AOF &&
+ !(server.script_caller->flags & CLIENT_MASTER))
{
int error_code;
/* Duplicate relevant flags in the lua client. */
c->flags &= ~(CLIENT_READONLY|CLIENT_ASKING);
- c->flags |= server.lua_caller->flags & (CLIENT_READONLY|CLIENT_ASKING);
+ c->flags |= server.script_caller->flags & (CLIENT_READONLY|CLIENT_ASKING);
if (getNodeByQuery(c,c->cmd,c->argv,c->argc,NULL,&error_code) !=
server.cluster->myself)
{
@@ -904,14 +904,14 @@ int luaRedisGenericCommand(lua_State *lua, int raise_error) {
/* If we are using single commands replication, we need to wrap what
* we propagate into a MULTI/EXEC block, so that it will be atomic like
* a Lua script in the context of AOF and slaves. */
- if (server.lua_replicate_commands &&
- !server.lua_multi_emitted &&
- !(server.lua_caller->flags & CLIENT_MULTI) &&
- server.lua_write_dirty &&
- server.lua_repl != PROPAGATE_NONE)
+ if (lctx.lua_replicate_commands &&
+ !lctx.lua_multi_emitted &&
+ !(server.script_caller->flags & CLIENT_MULTI) &&
+ lctx.lua_write_dirty &&
+ lctx.lua_repl != PROPAGATE_NONE)
{
- execCommandPropagateMulti(server.lua_caller->db->id);
- server.lua_multi_emitted = 1;
+ execCommandPropagateMulti(server.script_caller->db->id);
+ lctx.lua_multi_emitted = 1;
/* Now we are in the MULTI context, the lua_client should be
* flag as CLIENT_MULTI. */
c->flags |= CLIENT_MULTI;
@@ -919,11 +919,11 @@ int luaRedisGenericCommand(lua_State *lua, int raise_error) {
/* Run the command */
int call_flags = CMD_CALL_SLOWLOG | CMD_CALL_STATS;
- if (server.lua_replicate_commands) {
+ if (lctx.lua_replicate_commands) {
/* Set flags according to redis.set_repl() settings. */
- if (server.lua_repl & PROPAGATE_AOF)
+ if (lctx.lua_repl & PROPAGATE_AOF)
call_flags |= CMD_CALL_PROPAGATE_AOF;
- if (server.lua_repl & PROPAGATE_REPL)
+ if (lctx.lua_repl & PROPAGATE_REPL)
call_flags |= CMD_CALL_PROPAGATE_REPL;
}
call(c,call_flags);
@@ -953,13 +953,13 @@ int luaRedisGenericCommand(lua_State *lua, int raise_error) {
redisProtocolToLuaType(lua,reply);
/* If the debugger is active, log the reply from Redis. */
- if (ldb.active && ldb.step)
+ if (ldbIsEnabled())
ldbLogRedisReply(reply);
/* Sort the output array if needed, assuming it is a non-null multi bulk
* reply as expected. */
if ((cmd->flags & CMD_SORT_FOR_SCRIPT) &&
- (server.lua_replicate_commands == 0) &&
+ (lctx.lua_replicate_commands == 0) &&
(reply[0] == '*' && reply[1] != '-')) {
luaSortArray(lua);
}
@@ -1076,7 +1076,7 @@ int luaRedisSetReplCommand(lua_State *lua) {
int argc = lua_gettop(lua);
int flags;
- if (server.lua_replicate_commands == 0) {
+ if (lctx.lua_replicate_commands == 0) {
lua_pushstring(lua, "You can set the replication behavior only after turning on single commands replication with redis.replicate_commands().");
return lua_error(lua);
} else if (argc != 1) {
@@ -1089,7 +1089,7 @@ int luaRedisSetReplCommand(lua_State *lua) {
lua_pushstring(lua, "Invalid replication flags. Use REPL_AOF, REPL_REPLICA, REPL_ALL or REPL_NONE.");
return lua_error(lua);
}
- server.lua_repl = flags;
+ lctx.lua_repl = flags;
return 0;
}
@@ -1145,7 +1145,7 @@ int luaSetResp(lua_State *lua) {
return lua_error(lua);
}
- server.lua_client->resp = resp;
+ lctx.lua_client->resp = resp;
return 0;
}
@@ -1385,29 +1385,29 @@ 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) {
- long long elapsed = elapsedMs(server.lua_time_start);
+ long long elapsed = elapsedMs(lctx.lua_time_start);
UNUSED(ar);
UNUSED(lua);
/* Set the timeout condition if not already set and the maximum
* execution time was reached. */
- if (elapsed >= server.lua_time_limit && server.lua_timedout == 0) {
+ if (elapsed >= server.script_time_limit && server.script_timedout == 0) {
serverLog(LL_WARNING,
"Lua slow script detected: still in execution after %lld milliseconds. "
"You can try killing the script using the SCRIPT KILL command. "
"Script SHA1 is: %s",
- elapsed, server.lua_cur_script);
- server.lua_timedout = 1;
+ elapsed, lctx.lua_cur_script);
+ server.script_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.
* If we don't do that the client may disconnect and could no longer be
* here when the EVAL command will return. */
- protectClient(server.lua_caller);
+ protectClient(server.script_caller);
}
- if (server.lua_timedout) processEventsWhileBlocked();
- if (server.lua_kill) {
+ if (server.script_timedout) processEventsWhileBlocked();
+ if (lctx.lua_kill) {
serverLog(LL_WARNING,"Lua script killed by user with SCRIPT KILL.");
/*
diff --git a/src/script_lua.h b/src/script_lua.h
new file mode 100644
index 000000000..f9cf6f18a
--- /dev/null
+++ b/src/script_lua.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2009-2021, Redis Labs Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Redis nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __SCRIPT_LUA_H_
+#define __SCRIPT_LUA_H_
+
+#include "server.h"
+#include "script.h"
+#include <lua.h>
+#include <lauxlib.h>
+#include <lualib.h>
+
+typedef struct luaCtx {
+ lua_State *lua; /* The Lua interpreter. We use just one for all clients */
+ client *lua_client; /* The "fake client" to query Redis from Lua */
+ char *lua_cur_script; /* SHA1 of the script currently running, or NULL */
+ dict *lua_scripts; /* A dictionary of SHA1 -> Lua scripts */
+ unsigned long long lua_scripts_mem; /* Cached scripts' memory + oh */
+ int lua_replicate_commands; /* True if we are doing single commands repl. */
+ int lua_write_dirty;
+ int lua_random_dirty;
+ int lua_multi_emitted;
+ int lua_repl;
+ int lua_kill;
+ monotime lua_time_start; /* monotonic timer to detect timed-out script */
+ mstime_t lua_time_snapshot; /* Snapshot of mstime when script is started */
+} luaCtx;
+
+extern luaCtx lctx;
+
+void luaEngineRegisterRedisAPI(lua_State* lua);
+void scriptingEnableGlobalsProtection(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, lua_State *lua);
+
+
+
+#endif /* __SCRIPT_LUA_H_ */
diff --git a/src/server.c b/src/server.c
index 05ab6b93a..8d682c207 100644
--- a/src/server.c
+++ b/src/server.c
@@ -2994,7 +2994,7 @@ void cronUpdateMemoryStats() {
/* LUA memory isn't part of zmalloc_used, but it is part of the process RSS,
* so we must deduct it in order to be able to calculate correct
* "allocator fragmentation" ratio */
- size_t lua_memory = lua_gc(server.lua,LUA_GCCOUNT,0)*1024LL;
+ size_t lua_memory = evalMemory();
server.cron_malloc_stats.allocator_resident = server.cron_malloc_stats.process_rss - lua_memory;
}
if (!server.cron_malloc_stats.allocator_active)
@@ -4247,7 +4247,7 @@ void initServer(void) {
server.pubsub_channels = dictCreate(&keylistDictType);
server.pubsub_patterns = dictCreate(&keylistDictType);
server.cronloops = 0;
- server.in_eval = 0;
+ server.in_script = 0;
server.in_exec = 0;
server.propagate_in_transaction = 0;
server.client_pause_in_transaction = 0;
@@ -4937,11 +4937,11 @@ void call(client *c, int flags) {
/* If the caller is Lua, we want to force the EVAL caller to propagate
* the script if the command flag or client flag are forcing the
* propagation. */
- if (c->flags & CLIENT_LUA && server.lua_caller) {
+ if (c->flags & CLIENT_LUA && server.script_caller) {
if (c->flags & CLIENT_FORCE_REPL)
- server.lua_caller->flags |= CLIENT_FORCE_REPL;
+ server.script_caller->flags |= CLIENT_FORCE_REPL;
if (c->flags & CLIENT_FORCE_AOF)
- server.lua_caller->flags |= CLIENT_FORCE_AOF;
+ server.script_caller->flags |= CLIENT_FORCE_AOF;
}
/* Note: the code below uses the real command that was executed
@@ -5070,8 +5070,8 @@ void call(client *c, int flags) {
/* If the client has keys tracking enabled for client side caching,
* make sure to remember the keys it fetched via this command. */
if (c->cmd->flags & CMD_READONLY) {
- client *caller = (c->flags & CLIENT_LUA && server.lua_caller) ?
- server.lua_caller : c;
+ client *caller = (c->flags & CLIENT_LUA && server.script_caller) ?
+ server.script_caller : c;
if (caller->flags & CLIENT_TRACKING &&
!(caller->flags & CLIENT_TRACKING_BCAST))
{
@@ -5172,14 +5172,14 @@ void populateCommandMovableKeys(struct redisCommand *cmd) {
* other operations can be performed by the caller. Otherwise
* if C_ERR is returned the client was destroyed (i.e. after QUIT). */
int processCommand(client *c) {
- if (!server.lua_timedout) {
+ if (!server.script_timedout) {
/* Both EXEC and EVAL call call() directly so there should be
* no way in_exec or in_eval or propagate_in_transaction is 1.
* That is unless lua_timedout, in which case client may run
* some commands. */
serverAssert(!server.propagate_in_transaction);
serverAssert(!server.in_exec);
- serverAssert(!server.in_eval);
+ serverAssert(!server.in_script);
}
moduleCallCommandFilters(c);
@@ -5274,7 +5274,7 @@ int processCommand(client *c) {
if (server.cluster_enabled &&
!(c->flags & CLIENT_MASTER) &&
!(c->flags & CLIENT_LUA &&
- server.lua_caller->flags & CLIENT_MASTER) &&
+ server.script_caller->flags & CLIENT_MASTER) &&
!(!c->cmd->movablekeys && c->cmd->key_specs_num == 0 &&
c->cmd->proc != execCommand))
{
@@ -5309,7 +5309,7 @@ int processCommand(client *c) {
* the event loop since there is a busy Lua script running in timeout
* condition, to avoid mixing the propagation of scripts with the
* propagation of DELs due to eviction. */
- if (server.maxmemory && !server.lua_timedout) {
+ if (server.maxmemory && !server.script_timedout) {
int out_of_memory = (performEvictions() == EVICT_FAIL);
/* performEvictions may evict keys, so we need flush pending tracking
@@ -5345,7 +5345,7 @@ int processCommand(client *c) {
* until first write within script, memory used by lua stack and
* arguments might interfere. */
if (c->cmd->proc == evalCommand || c->cmd->proc == evalShaCommand) {
- server.lua_oom = out_of_memory;
+ server.script_oom = out_of_memory;
}
}
@@ -5432,7 +5432,7 @@ int processCommand(client *c) {
* the MULTI plus a few initial commands refused, then the timeout
* condition resolves, and the bottom-half of the transaction gets
* executed, see Github PR #7022. */
- if (server.lua_timedout &&
+ if (server.script_timedout &&
c->cmd->proc != authCommand &&
c->cmd->proc != helloCommand &&
c->cmd->proc != replconfCommand &&
@@ -6286,7 +6286,7 @@ sds genRedisInfoString(const char *section) {
size_t zmalloc_used = zmalloc_used_memory();
size_t total_system_mem = server.system_memory_size;
const char *evict_policy = evictPolicyToString();
- long long memory_lua = server.lua ? (long long)lua_gc(server.lua,LUA_GCCOUNT,0)*1024 : 0;
+ long long memory_lua = evalMemory();
struct redisMemOverhead *mh = getMemoryOverheadData();
/* Peak memory is updated from time to time by serverCron() so it
@@ -6369,7 +6369,7 @@ sds genRedisInfoString(const char *section) {
used_memory_lua_hmem,
(long long) mh->lua_caches,
used_memory_scripts_hmem,
- dictSize(server.lua_scripts),
+ dictSize(evalScriptsDict()),
server.maxmemory,
maxmemory_hmem,
evict_policy,
diff --git a/src/server.h b/src/server.h
index c06b23631..959b0e2d1 100644
--- a/src/server.h
+++ b/src/server.h
@@ -1334,7 +1334,7 @@ struct redisServer {
int sentinel_mode; /* True if this instance is a Sentinel. */
size_t initial_memory_usage; /* Bytes used after initialization. */
int always_show_logo; /* Show logo even for non-stdout logging. */
- int in_eval; /* Are we inside EVAL? */
+ int in_script; /* Are we inside EVAL? */
int in_exec; /* Are we inside EXEC? */
int propagate_in_transaction; /* Make sure we don't propagate nested MULTI/EXEC */
char *ignore_warnings; /* Config: warnings that should be ignored. */
@@ -1719,28 +1719,13 @@ struct redisServer {
is down? */
int cluster_config_file_lock_fd; /* cluster config fd, will be flock */
/* Scripting */
- lua_State *lua; /* The Lua interpreter. We use just one for all clients */
- client *lua_client; /* The "fake client" to query Redis from Lua */
- client *lua_caller; /* The client running EVAL right now, or NULL */
- char* lua_cur_script; /* SHA1 of the script currently running, or NULL */
- dict *lua_scripts; /* A dictionary of SHA1 -> Lua scripts */
- unsigned long long lua_scripts_mem; /* Cached scripts' memory + oh */
- mstime_t lua_time_limit; /* Script timeout in milliseconds */
- monotime lua_time_start; /* monotonic timer to detect timed-out script */
- mstime_t lua_time_snapshot; /* Snapshot of mstime when script is started */
- int lua_write_dirty; /* True if a write command was called during the
- execution of the current script. */
- int lua_random_dirty; /* True if a random command was called during the
- execution of the current script. */
- int lua_replicate_commands; /* True if we are doing single commands repl. */
- int lua_multi_emitted;/* True if we already propagated MULTI. */
- int lua_repl; /* Script replication flags for redis.set_repl(). */
- int lua_timedout; /* True if we reached the time limit for script
- execution. */
- int lua_kill; /* Kill the script if true. */
+ client *script_caller; /* The client running script right now, or NULL */
+ mstime_t script_time_limit; /* Script timeout in milliseconds */
+ int script_timedout; /* True if we reached the time limit for script
+ execution. */
int lua_always_replicate_commands; /* Default replication type. */
- int lua_oom; /* OOM detected when script start? */
- int lua_disable_deny_script; /* Allow running commands marked "no-script" inside a script. */
+ int script_oom; /* OOM detected when script start */
+ int script_disable_deny_script; /* Allow running commands marked "no-script" inside a script. */
/* Lazy free */
int lazyfree_lazy_eviction;
int lazyfree_lazy_expire;
@@ -2722,8 +2707,16 @@ void scriptingInit(int setup);
int ldbRemoveChild(pid_t pid);
void ldbKillForkedSessions(void);
int ldbPendingChildren(void);
-sds luaCreateFunction(client *c, lua_State *lua, robj *body);
+sds luaCreateFunction(client *c, robj *body);
void freeLuaScriptsAsync(dict *lua_scripts);
+int ldbIsEnabled();
+void ldbLog(sds entry);
+void ldbLogRedisReply(char *reply);
+void sha1hex(char *digest, char *script, size_t len);
+unsigned long evalMemory();
+dict* evalScriptsDict();
+unsigned long evalScriptsMemory();
+mstime_t evalTimeSnapshot();
/* Blocked clients */
void processUnblockedClients(void);