SCRIPT FLUSH run truly async, close lua interpreter in bio (#13087)
Even if we have SCRIPT FLUSH ASYNC now, when there are a lot of lua scripts, SCRIPT FLUSH ASYNC will still block the main thread. This is because lua_close is executed in the main thread, and lua heap needs to release a lot of memory. In this PR, we take the current lua instance on lctx.lua and call lua_close on it in a background thread, to close it in async way. This is MeirShpilraien's idea.
This commit is contained in:
parent
763827c981
commit
a7abc2f067
24
src/eval.c
24
src/eval.c
@ -264,15 +264,31 @@ void scriptingInit(int setup) {
|
|||||||
lctx.lua = lua;
|
lctx.lua = lua;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Free lua_scripts dict and close lua interpreter. */
|
||||||
|
void freeLuaScriptsSync(dict *lua_scripts, lua_State *lua) {
|
||||||
|
dictRelease(lua_scripts);
|
||||||
|
lua_close(lua);
|
||||||
|
|
||||||
|
#if !defined(USE_LIBC)
|
||||||
|
/* The lua interpreter may hold a lot of memory internally, and lua is
|
||||||
|
* using libc. libc may take a bit longer to return the memory to the OS,
|
||||||
|
* so after lua_close, we call malloc_trim try to purge it earlier.
|
||||||
|
*
|
||||||
|
* We do that only when Redis itself does not use libc. When Lua and Redis
|
||||||
|
* use different allocators, one won't use the fragmentation holes of the
|
||||||
|
* other, and released memory can take a long time until it is returned to
|
||||||
|
* the OS. */
|
||||||
|
zlibc_trim();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/* Release resources related to Lua scripting.
|
/* Release resources related to Lua scripting.
|
||||||
* This function is used in order to reset the scripting environment. */
|
* This function is used in order to reset the scripting environment. */
|
||||||
void scriptingRelease(int async) {
|
void scriptingRelease(int async) {
|
||||||
if (async)
|
if (async)
|
||||||
freeLuaScriptsAsync(lctx.lua_scripts);
|
freeLuaScriptsAsync(lctx.lua_scripts, lctx.lua);
|
||||||
else
|
else
|
||||||
dictRelease(lctx.lua_scripts);
|
freeLuaScriptsSync(lctx.lua_scripts, lctx.lua);
|
||||||
lctx.lua_scripts_mem = 0;
|
|
||||||
lua_close(lctx.lua);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void scriptingReset(int async) {
|
void scriptingReset(int async) {
|
||||||
|
@ -42,8 +42,9 @@ void lazyFreeTrackingTable(void *args[]) {
|
|||||||
/* Release the lua_scripts dict. */
|
/* Release the lua_scripts dict. */
|
||||||
void lazyFreeLuaScripts(void *args[]) {
|
void lazyFreeLuaScripts(void *args[]) {
|
||||||
dict *lua_scripts = args[0];
|
dict *lua_scripts = args[0];
|
||||||
|
lua_State *lua = args[1];
|
||||||
long long len = dictSize(lua_scripts);
|
long long len = dictSize(lua_scripts);
|
||||||
dictRelease(lua_scripts);
|
freeLuaScriptsSync(lua_scripts, lua);
|
||||||
atomicDecr(lazyfree_objects,len);
|
atomicDecr(lazyfree_objects,len);
|
||||||
atomicIncr(lazyfreed_objects,len);
|
atomicIncr(lazyfreed_objects,len);
|
||||||
}
|
}
|
||||||
@ -195,13 +196,14 @@ void freeTrackingRadixTreeAsync(rax *tracking) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Free lua_scripts dict, if the dict is huge enough, free it in async way. */
|
/* Free lua_scripts dict, if the dict is huge enough, free it in async way.
|
||||||
void freeLuaScriptsAsync(dict *lua_scripts) {
|
* Close lua interpreter, if there are a lot of lua scripts, close it in async way. */
|
||||||
|
void freeLuaScriptsAsync(dict *lua_scripts, lua_State *lua) {
|
||||||
if (dictSize(lua_scripts) > LAZYFREE_THRESHOLD) {
|
if (dictSize(lua_scripts) > LAZYFREE_THRESHOLD) {
|
||||||
atomicIncr(lazyfree_objects,dictSize(lua_scripts));
|
atomicIncr(lazyfree_objects,dictSize(lua_scripts));
|
||||||
bioCreateLazyFreeJob(lazyFreeLuaScripts,1,lua_scripts);
|
bioCreateLazyFreeJob(lazyFreeLuaScripts,2,lua_scripts,lua);
|
||||||
} else {
|
} else {
|
||||||
dictRelease(lua_scripts);
|
freeLuaScriptsSync(lua_scripts, lua);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3381,7 +3381,8 @@ void ldbKillForkedSessions(void);
|
|||||||
int ldbPendingChildren(void);
|
int ldbPendingChildren(void);
|
||||||
sds luaCreateFunction(client *c, robj *body);
|
sds luaCreateFunction(client *c, robj *body);
|
||||||
void luaLdbLineHook(lua_State *lua, lua_Debug *ar);
|
void luaLdbLineHook(lua_State *lua, lua_Debug *ar);
|
||||||
void freeLuaScriptsAsync(dict *lua_scripts);
|
void freeLuaScriptsSync(dict *lua_scripts, lua_State *lua);
|
||||||
|
void freeLuaScriptsAsync(dict *lua_scripts, lua_State *lua);
|
||||||
void freeFunctionsAsync(functionsLibCtx *lib_ctx);
|
void freeFunctionsAsync(functionsLibCtx *lib_ctx);
|
||||||
int ldbIsEnabled(void);
|
int ldbIsEnabled(void);
|
||||||
void ldbLog(sds entry);
|
void ldbLog(sds entry);
|
||||||
|
@ -50,7 +50,6 @@ void zlibc_free(void *ptr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <pthread.h>
|
|
||||||
#include "zmalloc.h"
|
#include "zmalloc.h"
|
||||||
#include "atomicvar.h"
|
#include "atomicvar.h"
|
||||||
|
|
||||||
@ -757,6 +756,15 @@ int jemalloc_purge(void) {
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* This function provides us access to the libc malloc_trim(). */
|
||||||
|
void zlibc_trim(void) {
|
||||||
|
#if defined(__GLIBC__) && !defined(USE_LIBC)
|
||||||
|
malloc_trim(0);
|
||||||
|
#else
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(__APPLE__)
|
#if defined(__APPLE__)
|
||||||
/* For proc_pidinfo() used later in zmalloc_get_smap_bytes_by_field().
|
/* For proc_pidinfo() used later in zmalloc_get_smap_bytes_by_field().
|
||||||
* Note that this file cannot be included in zmalloc.h because it includes
|
* Note that this file cannot be included in zmalloc.h because it includes
|
||||||
|
@ -71,6 +71,7 @@
|
|||||||
*/
|
*/
|
||||||
#ifndef ZMALLOC_LIB
|
#ifndef ZMALLOC_LIB
|
||||||
#define ZMALLOC_LIB "libc"
|
#define ZMALLOC_LIB "libc"
|
||||||
|
#define USE_LIBC 1
|
||||||
|
|
||||||
#if !defined(NO_MALLOC_USABLE_SIZE) && \
|
#if !defined(NO_MALLOC_USABLE_SIZE) && \
|
||||||
(defined(__GLIBC__) || defined(__FreeBSD__) || \
|
(defined(__GLIBC__) || defined(__FreeBSD__) || \
|
||||||
@ -93,6 +94,11 @@
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Includes for malloc_trim(), see zlibc_trim(). */
|
||||||
|
#if defined(__GLIBC__) && !defined(USE_LIBC)
|
||||||
|
#include <malloc.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
/* We can enable the Redis defrag capabilities only if we are using Jemalloc
|
/* We can enable the Redis defrag capabilities only if we are using Jemalloc
|
||||||
* and the version used is our special version modified for Redis having
|
* and the version used is our special version modified for Redis having
|
||||||
* the ability to return per-allocation fragmentation hints. */
|
* the ability to return per-allocation fragmentation hints. */
|
||||||
@ -130,6 +136,7 @@ size_t zmalloc_get_private_dirty(long pid);
|
|||||||
size_t zmalloc_get_smap_bytes_by_field(char *field, long pid);
|
size_t zmalloc_get_smap_bytes_by_field(char *field, long pid);
|
||||||
size_t zmalloc_get_memory_size(void);
|
size_t zmalloc_get_memory_size(void);
|
||||||
void zlibc_free(void *ptr);
|
void zlibc_free(void *ptr);
|
||||||
|
void zlibc_trim(void);
|
||||||
void zmadvise_dontneed(void *ptr);
|
void zmadvise_dontneed(void *ptr);
|
||||||
|
|
||||||
#ifdef HAVE_DEFRAG
|
#ifdef HAVE_DEFRAG
|
||||||
|
Loading…
x
Reference in New Issue
Block a user