Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Periodic Lua Gc after loading Lua script #325

Open
wants to merge 9 commits into
base: unstable
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion deps/lua/src/lapi.c
Original file line number Diff line number Diff line change
Expand Up @@ -960,7 +960,22 @@ LUA_API int lua_gc (lua_State *L, int what, int data) {
return res;
}


LUA_API int lua_gc_step (lua_State *L, int steps) {
int res = 0;
global_State *g;
lua_lock(L);
g = G(L);
g->GCthreshold = 0;
while (steps--) {
luaC_step(L);
if (g->gcstate == GCSpause) { /* end of cycle? */
res = 1; /* signal it */
break;
}
}
lua_unlock(L);
return res;
}

/*
** miscellaneous functions
Expand Down
1 change: 1 addition & 0 deletions deps/lua/src/lua.h
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@ LUA_API int (lua_status) (lua_State *L);
#define LUA_GCSETSTEPMUL 7

LUA_API int (lua_gc) (lua_State *L, int what, int data);
LUA_API int (lua_gc_step) (lua_State *L, int steps);


/*
Expand Down
4 changes: 2 additions & 2 deletions src/debug.c
Original file line number Diff line number Diff line change
Expand Up @@ -1016,7 +1016,7 @@ NULL
addReply(c, shared.ok);
} else if (!strcasecmp(c->argv[1]->ptr,"script") && c->argc == 3) {
if (!strcasecmp(c->argv[2]->ptr,"list")) {
dictIterator *di = dictGetIterator(getLuaScripts());
dictIterator *di = dictGetIterator(evalScriptsDict());
dictEntry *de;
while ((de = dictNext(di)) != NULL) {
luaScript *script = dictGetVal(de);
Expand All @@ -1026,7 +1026,7 @@ NULL
dictReleaseIterator(di);
} else if (sdslen(c->argv[2]->ptr) == 40) {
dictEntry *de;
if ((de = dictFind(getLuaScripts(), c->argv[2]->ptr)) == NULL) {
if ((de = dictFind(evalScriptsDict(), c->argv[2]->ptr)) == NULL) {
addReplyErrorObject(c, shared.noscripterr);
return;
}
Expand Down
8 changes: 4 additions & 4 deletions src/eval.c
Original file line number Diff line number Diff line change
Expand Up @@ -736,6 +736,10 @@ unsigned long evalScriptsMemory(void) {
listLength(lctx.lua_scripts_lru_list) * sizeof(listNode);
}

void evalScriptsGC(void) {
lua_gc_step(lctx.lua, 1);
}

/* ---------------------------------------------------------------------------
* LDB: Redis Lua debugging facilities
* ------------------------------------------------------------------------- */
Expand Down Expand Up @@ -1737,7 +1741,3 @@ void luaLdbLineHook(lua_State *lua, lua_Debug *ar) {
rctx->start_time = getMonotonicUs();
}
}

dict *getLuaScripts(void) {
return lctx.lua_scripts;
}
7 changes: 7 additions & 0 deletions src/function_lua.c
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,12 @@ static void luaEngineFreeFunction(void *engine_ctx, void *compiled_function) {
zfree(f_ctx);
}

static void luaEnglineGCStep(void *engine_ctx, int steps) {
luaEngineCtx *lua_engine_ctx = engine_ctx;
lua_State *lua = lua_engine_ctx->lua;
lua_gc_step(lua, steps);
}

static void luaRegisterFunctionArgsInitialize(registerFunctionArgs *register_f_args,
sds name,
sds desc,
Expand Down Expand Up @@ -480,6 +486,7 @@ int luaEngineInitEngine(void) {
.get_function_memory_overhead = luaEngineFunctionMemoryOverhead,
.get_engine_memory_overhead = luaEngineMemoryOverhead,
.free_function = luaEngineFreeFunction,
.gc_step = luaEnglineGCStep,
};
return functionsRegisterEngine(LUA_ENGINE_NAME, lua_engine);
}
11 changes: 11 additions & 0 deletions src/functions.c
Original file line number Diff line number Diff line change
Expand Up @@ -1106,3 +1106,14 @@ int functionsInit(void) {

return C_OK;
}

void functionsGC(void) {
dictIterator *iter = dictGetIterator(engines);
dictEntry *entry = NULL;
while ((entry = dictNext(iter))) {
engineInfo *ei = dictGetVal(entry);
engine *engine = ei->engine;
engine->gc_step(engine->engine_ctx, 1);
}
dictReleaseIterator(iter);
}
4 changes: 4 additions & 0 deletions src/functions.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ typedef struct engine {

/* free the given function */
void (*free_function)(void *engine_ctx, void *compiled_function);

/* Perform the garbage collector */
void (*gc_step)(void *engine_ctx, int steps);
} engine;

/* Hold information about an engine.
Expand Down Expand Up @@ -116,5 +119,6 @@ int functionLibCreateFunction(sds name, void *function, functionLibInfo *li, sds

int luaEngineInitEngine(void);
int functionsInit(void);
void functionsGC(void);

#endif /* __FUNCTIONS_H_ */
1 change: 0 additions & 1 deletion src/script.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,6 @@ extern scriptFlag scripts_flags_def[];

void luaEnvInit(void);
lua_State *createLuaState(void);
dict *getLuaScripts(void);
uint64_t scriptFlagsToCmdFlags(uint64_t cmd_flags, uint64_t script_flags);
int scriptPrepareForRun(scriptRunCtx *r_ctx, client *engine_client, client *caller, const char *funcname, uint64_t script_flags, int ro);
void scriptResetRun(scriptRunCtx *r_ctx);
Expand Down
17 changes: 0 additions & 17 deletions src/script_lua.c
Original file line number Diff line number Diff line change
Expand Up @@ -1650,23 +1650,6 @@ void luaCallFunction(scriptRunCtx* run_ctx, lua_State *lua, robj** keys, size_t
err = lua_pcall(lua,2,1,-4);
}

/* 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) {
/* Error object is a table of the following format:
* {err='<error msg>', source='<source file>', line=<line>}
Expand Down
5 changes: 5 additions & 0 deletions src/server.c
Original file line number Diff line number Diff line change
Expand Up @@ -1389,6 +1389,11 @@ int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) {
/* Handle background operations on Redis databases. */
databasesCron();

run_with_period(100) {
evalScriptsGC();
functionsGC();
}

/* Start a scheduled AOF rewrite if this was requested by the user while
* a BGSAVE was in progress. */
if (!hasActiveChildProcess() &&
Expand Down
1 change: 1 addition & 0 deletions src/server.h
Original file line number Diff line number Diff line change
Expand Up @@ -3475,6 +3475,7 @@ void sha1hex(char *digest, char *script, size_t len);
unsigned long evalMemory(void);
dict* evalScriptsDict(void);
unsigned long evalScriptsMemory(void);
void evalScriptsGC(void);
uint64_t evalGetCommandFlags(client *c, uint64_t orig_flags);
uint64_t fcallGetCommandFlags(client *c, uint64_t orig_flags);
int isInsideYieldingLongCommand(void);
Expand Down
18 changes: 18 additions & 0 deletions tests/unit/scripting.tcl
Original file line number Diff line number Diff line change
Expand Up @@ -2383,3 +2383,21 @@ start_server {tags {"scripting"}} {
}
}
}

start_server {tags {"scripting"}} {
test "LUA gc in cron" {
set dummy_script "--[string repeat x 40]\nreturn "
set n 150000
for {set i 0} {$i < $n} {incr i} {
set val "$dummy_script[format "%06d" $i]"
r script load $val
}

# we expect the gabages in the LUA VM to be collected in the cron.
wait_for_condition 500 10 {
[s used_memory_lua] < 60000000
} else {
fail "LUA gc in cron doesn't work"
}
}
}
Loading