mirror of
https://github.com/fluencelabs/redis
synced 2025-03-30 22:31:03 +00:00
Lua scripts max execution time
This commit is contained in:
parent
8c3402dffa
commit
eeffcf380f
@ -292,6 +292,13 @@ appendfsync everysec
|
|||||||
# "no" that is the safest pick from the point of view of durability.
|
# "no" that is the safest pick from the point of view of durability.
|
||||||
no-appendfsync-on-rewrite no
|
no-appendfsync-on-rewrite no
|
||||||
|
|
||||||
|
################################ LUA SCRIPTING ###############################
|
||||||
|
|
||||||
|
# Max execution time of a Lua script in milliseconds.
|
||||||
|
# This prevents that a programming error generating an infinite loop will block
|
||||||
|
# your server forever. Set it to 0 or a negative value for unlimited execution.
|
||||||
|
lua-time-limit 60000
|
||||||
|
|
||||||
#################################### DISK STORE ###############################
|
#################################### DISK STORE ###############################
|
||||||
|
|
||||||
# When disk store is active Redis works as an on-disk database, where memory
|
# When disk store is active Redis works as an on-disk database, where memory
|
||||||
|
10
src/config.c
10
src/config.c
@ -296,6 +296,8 @@ void loadServerConfig(char *filename) {
|
|||||||
} else if (!strcasecmp(argv[0],"cluster-config-file") && argc == 2) {
|
} else if (!strcasecmp(argv[0],"cluster-config-file") && argc == 2) {
|
||||||
zfree(server.cluster.configfile);
|
zfree(server.cluster.configfile);
|
||||||
server.cluster.configfile = zstrdup(argv[1]);
|
server.cluster.configfile = zstrdup(argv[1]);
|
||||||
|
} else if (!strcasecmp(argv[0],"lua-time-limit") && argc == 2) {
|
||||||
|
server.lua_time_limit = strtoll(argv[1],NULL,10);
|
||||||
} else {
|
} else {
|
||||||
err = "Bad directive or wrong number of arguments"; goto loaderr;
|
err = "Bad directive or wrong number of arguments"; goto loaderr;
|
||||||
}
|
}
|
||||||
@ -460,6 +462,9 @@ void configSetCommand(redisClient *c) {
|
|||||||
} else if (!strcasecmp(c->argv[2]->ptr,"zset-max-ziplist-value")) {
|
} else if (!strcasecmp(c->argv[2]->ptr,"zset-max-ziplist-value")) {
|
||||||
if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll < 0) goto badfmt;
|
if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll < 0) goto badfmt;
|
||||||
server.zset_max_ziplist_value = ll;
|
server.zset_max_ziplist_value = ll;
|
||||||
|
} else if (!strcasecmp(c->argv[2]->ptr,"lua-time-limit")) {
|
||||||
|
if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll < 0) goto badfmt;
|
||||||
|
server.lua_time_limit = ll;
|
||||||
} else {
|
} else {
|
||||||
addReplyErrorFormat(c,"Unsupported CONFIG parameter: %s",
|
addReplyErrorFormat(c,"Unsupported CONFIG parameter: %s",
|
||||||
(char*)c->argv[2]->ptr);
|
(char*)c->argv[2]->ptr);
|
||||||
@ -621,6 +626,11 @@ void configGetCommand(redisClient *c) {
|
|||||||
addReplyBulkLongLong(c,server.zset_max_ziplist_value);
|
addReplyBulkLongLong(c,server.zset_max_ziplist_value);
|
||||||
matches++;
|
matches++;
|
||||||
}
|
}
|
||||||
|
if (stringmatch(pattern,"lua-time-limit",0)) {
|
||||||
|
addReplyBulkCString(c,"lua-time-limit");
|
||||||
|
addReplyBulkLongLong(c,server.lua_time_limit);
|
||||||
|
matches++;
|
||||||
|
}
|
||||||
setDeferredMultiBulkLength(c,replylen,matches*2);
|
setDeferredMultiBulkLength(c,replylen,matches*2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -858,6 +858,7 @@ void initServerConfig() {
|
|||||||
server.cache_flush_delay = 0;
|
server.cache_flush_delay = 0;
|
||||||
server.cluster_enabled = 0;
|
server.cluster_enabled = 0;
|
||||||
server.cluster.configfile = zstrdup("nodes.conf");
|
server.cluster.configfile = zstrdup("nodes.conf");
|
||||||
|
server.lua_time_limit = REDIS_LUA_TIME_LIMIT;
|
||||||
|
|
||||||
updateLRUClock();
|
updateLRUClock();
|
||||||
resetServerSaveParams();
|
resetServerSaveParams();
|
||||||
|
@ -225,6 +225,9 @@
|
|||||||
#define REDIS_BGSAVE_THREAD_DONE_OK 2
|
#define REDIS_BGSAVE_THREAD_DONE_OK 2
|
||||||
#define REDIS_BGSAVE_THREAD_DONE_ERR 3
|
#define REDIS_BGSAVE_THREAD_DONE_ERR 3
|
||||||
|
|
||||||
|
/* Scripting */
|
||||||
|
#define REDIS_LUA_TIME_LIMIT 60000 /* milliseconds */
|
||||||
|
|
||||||
/* We can print the stacktrace, so our assert is defined this way: */
|
/* We can print the stacktrace, so our assert is defined this way: */
|
||||||
#define redisAssert(_e) ((_e)?(void)0 : (_redisAssert(#_e,__FILE__,__LINE__),_exit(1)))
|
#define redisAssert(_e) ((_e)?(void)0 : (_redisAssert(#_e,__FILE__,__LINE__),_exit(1)))
|
||||||
#define redisPanic(_e) _redisPanic(#_e,__FILE__,__LINE__),_exit(1)
|
#define redisPanic(_e) _redisPanic(#_e,__FILE__,__LINE__),_exit(1)
|
||||||
@ -659,6 +662,8 @@ struct redisServer {
|
|||||||
/* Scripting */
|
/* Scripting */
|
||||||
lua_State *lua;
|
lua_State *lua;
|
||||||
redisClient *lua_client;
|
redisClient *lua_client;
|
||||||
|
long long lua_time_limit;
|
||||||
|
long long lua_time_start;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct pubsubPattern {
|
typedef struct pubsubPattern {
|
||||||
|
@ -199,6 +199,19 @@ int luaRedisCommand(lua_State *lua) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void luaMaskCountHook(lua_State *lua, lua_Debug *ar) {
|
||||||
|
long long elapsed;
|
||||||
|
REDIS_NOTUSED(ar);
|
||||||
|
|
||||||
|
if (server.lua_time_limit <= 0) return;
|
||||||
|
elapsed = (ustime()/1000) - server.lua_time_start;
|
||||||
|
if (elapsed >= server.lua_time_limit) {
|
||||||
|
lua_pushstring(lua,"Script aborted for max execution time...");
|
||||||
|
lua_error(lua);
|
||||||
|
redisLog(REDIS_NOTICE,"Lua script aborted for max execution time after %lld milliseconds of running time",elapsed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void scriptingInit(void) {
|
void scriptingInit(void) {
|
||||||
lua_State *lua = lua_open();
|
lua_State *lua = lua_open();
|
||||||
luaL_openlibs(lua);
|
luaL_openlibs(lua);
|
||||||
@ -212,6 +225,10 @@ void scriptingInit(void) {
|
|||||||
server.lua_client = createClient(-1);
|
server.lua_client = createClient(-1);
|
||||||
server.lua_client->flags |= REDIS_LUA_CLIENT;
|
server.lua_client->flags |= REDIS_LUA_CLIENT;
|
||||||
|
|
||||||
|
/* Set an hook in order to be able to stop the script execution if it
|
||||||
|
* is running for too much time. */
|
||||||
|
lua_sethook(lua,luaMaskCountHook,LUA_MASKCOUNT,10000);
|
||||||
|
|
||||||
server.lua = lua;
|
server.lua = lua;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -375,6 +392,7 @@ void evalCommand(redisClient *c) {
|
|||||||
/* At this point whatever this script was never seen before or if it was
|
/* At this point whatever this script was never seen before or if it was
|
||||||
* already defined, we can call it. We have zero arguments and expect
|
* already defined, we can call it. We have zero arguments and expect
|
||||||
* a single return value. */
|
* a single return value. */
|
||||||
|
server.lua_time_start = ustime()/1000;
|
||||||
if (lua_pcall(lua,0,1,0)) {
|
if (lua_pcall(lua,0,1,0)) {
|
||||||
selectDb(c,server.lua_client->db->id); /* set DB ID from Lua client */
|
selectDb(c,server.lua_client->db->id); /* set DB ID from Lua client */
|
||||||
addReplyErrorFormat(c,"Error running script (call to %s): %s\n",
|
addReplyErrorFormat(c,"Error running script (call to %s): %s\n",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user