Skip to content

Commit 4de59f5

Browse files
committed
feature: now we recycle lua thread GC objects for our "light threads" and added lua_thread_cache_max_entries directive to configure the cache size.
1 parent 4695419 commit 4de59f5

16 files changed

+451
-190
lines changed

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ install:
8888
- git clone https://github.com/openresty/lua-resty-mysql.git ../lua-resty-mysql
8989
- git clone https://github.com/openresty/lua-resty-string.git ../lua-resty-string
9090
- git clone https://github.com/openresty/stream-lua-nginx-module.git ../stream-lua-nginx-module
91-
- git clone -b v2.1-agentzh https://github.com/openresty/luajit2.git luajit2
91+
- git clone -b reset-thread https://github.com/openresty/luajit2.git luajit2
9292

9393
before_script:
9494
- mysql -uroot -e 'create database ngx_test; grant all on ngx_test.* to "ngx_test"@"%" identified by "ngx_test"; flush privileges;'

README.markdown

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1063,6 +1063,7 @@ Directives
10631063
* [lua_use_default_type](#lua_use_default_type)
10641064
* [lua_malloc_trim](#lua_malloc_trim)
10651065
* [lua_code_cache](#lua_code_cache)
1066+
* [lua_thread_cache_max_entries](#lua_thread_cache_max_entries)
10661067
* [lua_regex_cache_max_entries](#lua_regex_cache_max_entries)
10671068
* [lua_regex_match_limit](#lua_regex_match_limit)
10681069
* [lua_package_path](#lua_package_path)
@@ -1293,6 +1294,27 @@ development as it has a significant negative impact on overall performance. For
12931294

12941295
[Back to TOC](#directives)
12951296

1297+
lua_thread_cache_max_entries
1298+
----------------------------
1299+
1300+
**syntax:** *lua_thread_cache_max_entries <num>*
1301+
1302+
**default:** *lua_thread_cache_max_entries 1024*
1303+
1304+
**context:** *http*
1305+
1306+
Specifies the maximum number of entries allowed in the worker process level lua thread object cache.
1307+
1308+
This cache recycles the lua thread GC objects among all our "light threads".
1309+
1310+
A zero value of `<num>` disables the cache.
1311+
1312+
Note that this feature requires OpenResty's LuaJIT with the new C API `lua_resetthread`.
1313+
1314+
This feature was first introduced in verson `v0.10.9`.
1315+
1316+
[Back to TOC](#directives)
1317+
12961318
lua_regex_cache_max_entries
12971319
---------------------------
12981320

doc/HttpLuaModule.wiki

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1029,6 +1029,24 @@ Disabling the Lua code cache is strongly
10291029
discouraged for production use and should only be used during
10301030
development as it has a significant negative impact on overall performance. For example, the performance of a "hello world" Lua example can drop by an order of magnitude after disabling the Lua code cache.
10311031
1032+
== lua_thread_cache_max_entries ==
1033+
1034+
'''syntax:''' ''lua_thread_cache_max_entries <num>''
1035+
1036+
'''default:''' ''lua_thread_cache_max_entries 1024''
1037+
1038+
'''context:''' ''http''
1039+
1040+
Specifies the maximum number of entries allowed in the worker process level lua thread object cache.
1041+
1042+
This cache recycles the lua thread GC objects among all our "light threads".
1043+
1044+
A zero value of `<num>` disables the cache.
1045+
1046+
Note that this feature requires OpenResty's LuaJIT with the new C API `lua_resetthread`.
1047+
1048+
This feature was first introduced in verson `v0.10.9`.
1049+
10321050
== lua_regex_cache_max_entries ==
10331051
10341052
'''syntax:''' ''lua_regex_cache_max_entries <num>''

src/ngx_http_lua_common.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,13 @@ typedef struct {
185185
} ngx_http_lua_preload_hook_t;
186186

187187

188+
typedef struct {
189+
int ref;
190+
lua_State *co;
191+
ngx_queue_t queue;
192+
} ngx_http_lua_thread_ref_t;
193+
194+
188195
struct ngx_http_lua_main_conf_s {
189196
lua_State *lua;
190197
ngx_pool_cleanup_t *vm_cleanup;
@@ -203,6 +210,8 @@ struct ngx_http_lua_main_conf_s {
203210

204211
ngx_connection_t *watcher; /* for watching the process exit event */
205212

213+
ngx_int_t lua_thread_cache_max_entries;
214+
206215
#if (NGX_PCRE)
207216
ngx_int_t regex_cache_entries;
208217
ngx_int_t regex_cache_max_entries;
@@ -276,6 +285,9 @@ struct ngx_http_lua_main_conf_s {
276285

277286
ngx_flag_t set_sa_restart;
278287

288+
ngx_queue_t free_lua_threads; /* of ngx_http_lua_thread_ref_t */
289+
ngx_queue_t cached_lua_threads; /* of ngx_http_lua_thread_ref_t */
290+
279291
unsigned requires_header_filter:1;
280292
unsigned requires_body_filter:1;
281293
unsigned requires_capture_filter:1;

src/ngx_http_lua_control.c

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,7 @@ ngx_http_lua_ngx_redirect(lua_State *L)
305305
static int
306306
ngx_http_lua_on_abort(lua_State *L)
307307
{
308+
int co_ref;
308309
ngx_http_request_t *r;
309310
ngx_http_lua_ctx_t *ctx;
310311
ngx_http_lua_co_ctx_t *coctx = NULL;
@@ -335,18 +336,9 @@ ngx_http_lua_on_abort(lua_State *L)
335336
return 2;
336337
}
337338

338-
ngx_http_lua_coroutine_create_helper(L, r, ctx, &coctx);
339-
340-
lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask(
341-
coroutines_key));
342-
lua_rawget(L, LUA_REGISTRYINDEX);
343-
lua_pushvalue(L, -2);
344-
345-
dd("on_wait thread 1: %p", lua_tothread(L, -1));
346-
347-
coctx->co_ref = luaL_ref(L, -2);
348-
lua_pop(L, 1);
339+
ngx_http_lua_coroutine_create_helper(L, r, ctx, &coctx, &co_ref);
349340

341+
coctx->co_ref = co_ref;
350342
coctx->is_uthread = 1;
351343
ctx->on_abort_co_ctx = coctx;
352344

src/ngx_http_lua_coroutine.c

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ ngx_http_lua_coroutine_create(lua_State *L)
5959
return luaL_error(L, "no request ctx found");
6060
}
6161

62-
return ngx_http_lua_coroutine_create_helper(L, r, ctx, NULL);
62+
return ngx_http_lua_coroutine_create_helper(L, r, ctx, NULL, NULL);
6363
}
6464

6565

@@ -92,7 +92,7 @@ ngx_http_lua_coroutine_wrap(lua_State *L)
9292
return luaL_error(L, "no request ctx found");
9393
}
9494

95-
ngx_http_lua_coroutine_create_helper(L, r, ctx, &coctx);
95+
ngx_http_lua_coroutine_create_helper(L, r, ctx, &coctx, NULL);
9696

9797
coctx->is_wrap = 1;
9898

@@ -104,11 +104,12 @@ ngx_http_lua_coroutine_wrap(lua_State *L)
104104

105105
int
106106
ngx_http_lua_coroutine_create_helper(lua_State *L, ngx_http_request_t *r,
107-
ngx_http_lua_ctx_t *ctx, ngx_http_lua_co_ctx_t **pcoctx)
107+
ngx_http_lua_ctx_t *ctx, ngx_http_lua_co_ctx_t **pcoctx, int *co_ref)
108108
{
109109
lua_State *vm; /* the Lua VM */
110110
lua_State *co; /* new coroutine to be created */
111111
ngx_http_lua_co_ctx_t *coctx; /* co ctx for the new coroutine */
112+
ngx_http_lua_main_conf_t *lmcf;
112113

113114
luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), 1,
114115
"Lua function expected");
@@ -120,7 +121,13 @@ ngx_http_lua_coroutine_create_helper(lua_State *L, ngx_http_request_t *r,
120121
/* create new coroutine on root Lua state, so it always yields
121122
* to main Lua thread
122123
*/
123-
co = lua_newthread(vm);
124+
if (co_ref == NULL) {
125+
co = lua_newthread(vm);
126+
127+
} else {
128+
lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module);
129+
*co_ref = ngx_http_lua_new_cached_thread(vm, &co, lmcf, 0);
130+
}
124131

125132
ngx_http_lua_probe_user_coroutine_create(r, L, co);
126133

@@ -151,6 +158,10 @@ ngx_http_lua_coroutine_create_helper(lua_State *L, ngx_http_request_t *r,
151158

152159
lua_xmove(vm, L, 1); /* move coroutine from main thread to L */
153160

161+
if (co_ref) {
162+
lua_pop(vm, 1); /* pop coroutines */
163+
}
164+
154165
lua_pushvalue(L, 1); /* copy entry function to top of L*/
155166
lua_xmove(L, co, 1); /* move entry function from L to co */
156167

src/ngx_http_lua_coroutine.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
void ngx_http_lua_inject_coroutine_api(ngx_log_t *log, lua_State *L);
1616

1717
int ngx_http_lua_coroutine_create_helper(lua_State *L, ngx_http_request_t *r,
18-
ngx_http_lua_ctx_t *ctx, ngx_http_lua_co_ctx_t **pcoctx);
18+
ngx_http_lua_ctx_t *ctx, ngx_http_lua_co_ctx_t **pcoctx, int *co_ref);
1919

2020

2121
#endif /* _NGX_HTTP_LUA_COROUTINE_H_INCLUDED_ */

src/ngx_http_lua_module.c

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,13 @@ static ngx_command_t ngx_http_lua_cmds[] = {
8585
0,
8686
NULL },
8787

88+
{ ngx_string("lua_thread_cache_max_entries"),
89+
NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
90+
ngx_conf_set_num_slot,
91+
NGX_HTTP_MAIN_CONF_OFFSET,
92+
offsetof(ngx_http_lua_main_conf_t, lua_thread_cache_max_entries),
93+
NULL },
94+
8895
{ ngx_string("lua_max_running_timers"),
8996
NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
9097
ngx_conf_set_num_slot,
@@ -793,6 +800,13 @@ ngx_http_lua_init(ngx_conf_t *cf)
793800
"the OpenResty releases from https://openresty.org/"
794801
"en/download.html)");
795802
}
803+
#elif !defined(HAVE_LUA_RESETTHREAD)
804+
ngx_log_error(NGX_LOG_ALERT, cf->log, 0,
805+
"detected an old version of OpenResty's LuaJIT missing "
806+
"the lua_resetthread API and thus the "
807+
"performance will be compromised; please upgrade to the "
808+
"latest version of OpenResty's LuaJIT: "
809+
"https://github.com/openresty/luajit2");
796810
#endif
797811

798812
ngx_http_lua_content_length_hash =
@@ -915,6 +929,7 @@ ngx_http_lua_create_main_conf(ngx_conf_t *cf)
915929
lmcf->pool = cf->pool;
916930
lmcf->max_pending_timers = NGX_CONF_UNSET;
917931
lmcf->max_running_timers = NGX_CONF_UNSET;
932+
lmcf->lua_thread_cache_max_entries = NGX_CONF_UNSET;
918933
#if (NGX_PCRE)
919934
lmcf->regex_cache_max_entries = NGX_CONF_UNSET;
920935
lmcf->regex_match_limit = NGX_CONF_UNSET;
@@ -942,7 +957,27 @@ ngx_http_lua_create_main_conf(ngx_conf_t *cf)
942957
static char *
943958
ngx_http_lua_init_main_conf(ngx_conf_t *cf, void *conf)
944959
{
945-
ngx_http_lua_main_conf_t *lmcf = conf;
960+
#ifdef HAVE_LUA_RESETTHREAD
961+
ngx_int_t i, n;
962+
ngx_http_lua_thread_ref_t *trefs;
963+
#endif
964+
965+
ngx_http_lua_main_conf_t *lmcf = conf;
966+
967+
if (lmcf->lua_thread_cache_max_entries < 0) {
968+
lmcf->lua_thread_cache_max_entries = 1024;
969+
970+
#ifndef HAVE_LUA_RESETTHREAD
971+
972+
} else if (lmcf->lua_thread_cache_max_entries > 0) {
973+
ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
974+
"lua_thread_cache_max_entries has no effect when "
975+
"LuaJIT has no support for the lua_resetthread API "
976+
"(you forgot to use OpenResty's LuaJIT?)");
977+
return NGX_CONF_ERROR;
978+
979+
#endif
980+
}
946981

947982
#if (NGX_PCRE)
948983
if (lmcf->regex_cache_max_entries == NGX_CONF_UNSET) {
@@ -976,6 +1011,26 @@ ngx_http_lua_init_main_conf(ngx_conf_t *cf, void *conf)
9761011

9771012
lmcf->cycle = cf->cycle;
9781013

1014+
ngx_queue_init(&lmcf->free_lua_threads);
1015+
ngx_queue_init(&lmcf->cached_lua_threads);
1016+
1017+
#ifdef HAVE_LUA_RESETTHREAD
1018+
n = lmcf->lua_thread_cache_max_entries;
1019+
1020+
if (n > 0) {
1021+
trefs = ngx_palloc(cf->pool, n * sizeof(ngx_http_lua_thread_ref_t));
1022+
if (trefs == NULL) {
1023+
return NGX_CONF_ERROR;
1024+
}
1025+
1026+
for (i = 0; i < n; i++) {
1027+
trefs[i].ref = LUA_NOREF;
1028+
trefs[i].co = NULL;
1029+
ngx_queue_insert_head(&lmcf->free_lua_threads, &trefs[i].queue);
1030+
}
1031+
}
1032+
#endif
1033+
9791034
return NGX_CONF_OK;
9801035
}
9811036

0 commit comments

Comments
 (0)