Repository: trafficserver Updated Branches: refs/heads/master b6680179a -> d30401990
TS-4129: Support TSContSchedule in ts_lua plugin. This closes #420 Project: http://git-wip-us.apache.org/repos/asf/trafficserver/repo Commit: http://git-wip-us.apache.org/repos/asf/trafficserver/commit/d3040199 Tree: http://git-wip-us.apache.org/repos/asf/trafficserver/tree/d3040199 Diff: http://git-wip-us.apache.org/repos/asf/trafficserver/diff/d3040199 Branch: refs/heads/master Commit: d30401990ada424cb0b6acbcb4cfeab31bdb979f Parents: b668017 Author: Kit Chan <[email protected]> Authored: Wed Jan 20 23:26:42 2016 -0800 Committer: Kit Chan <[email protected]> Committed: Wed Jan 20 23:26:42 2016 -0800 ---------------------------------------------------------------------- doc/admin-guide/plugins/ts_lua.en.rst | 30 +++++ .../ts_lua/example/test_schedule.lua | 48 +++++++ plugins/experimental/ts_lua/ts_lua_misc.c | 124 +++++++++++++++++++ plugins/experimental/ts_lua/ts_lua_util.c | 41 ++++++ plugins/experimental/ts_lua/ts_lua_util.h | 3 + 5 files changed, 246 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/trafficserver/blob/d3040199/doc/admin-guide/plugins/ts_lua.en.rst ---------------------------------------------------------------------- diff --git a/doc/admin-guide/plugins/ts_lua.en.rst b/doc/admin-guide/plugins/ts_lua.en.rst index 66de2d9..2cc8dc2 100644 --- a/doc/admin-guide/plugins/ts_lua.en.rst +++ b/doc/admin-guide/plugins/ts_lua.en.rst @@ -2379,6 +2379,36 @@ Here is an example: `TOP <#ts-lua-plugin>`_ +ts.schedule +----------- +**syntax:** *ts.schedule(THREAD_TYPE, sec, FUNCTION, param1?, param2?, ...)* + +**context:** *after do_remap* + +**description:** Schedule function to be run after specified seconds without blocking. + +Behind the scene, this method makes use of the ATS event model. + +Here is an example: + +:: + + function schedule() + ts.debug('test schedule starts') + end + + function cache_lookup() + ts.debug('cache-lookup') + ts.schedule(TS_LUA_THREAD_POOL_NET, 0, schedule) + return 0 + end + + function do_remap() + ts.hook(TS_LUA_HOOK_CACHE_LOOKUP_COMPLETE, cache_lookup) + end + +`TOP <#ts-lua-plugin>`_ + ts.http.config_int_get ---------------------- **syntax:** *val = ts.http.config_int_get(CONFIG)* http://git-wip-us.apache.org/repos/asf/trafficserver/blob/d3040199/plugins/experimental/ts_lua/example/test_schedule.lua ---------------------------------------------------------------------- diff --git a/plugins/experimental/ts_lua/example/test_schedule.lua b/plugins/experimental/ts_lua/example/test_schedule.lua new file mode 100644 index 0000000..d80e843 --- /dev/null +++ b/plugins/experimental/ts_lua/example/test_schedule.lua @@ -0,0 +1,48 @@ +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. + + +function schedule() + ts.debug('test schedule starts') + + -- test.com needs to be handled by ATS in remap.config + local url = 'http://test.com/test.php' + local res = ts.fetch(url) + ts.debug('test fetch') + if res.status == 200 then + local b = res.body + local len = string.len(b) + ts.debug(len) + end + ts.debug('test schedule ends') +end + +function cache_lookup() + ts.debug('cache-lookup') + ts.schedule(TS_LUA_THREAD_POOL_NET, 0, schedule) + return 0 +end + +function do_global_read_request() + local inner = ts.http.is_internal_request() + if inner ~= 0 then + ts.debug('internal') + return 0 + end + + ts.hook(TS_LUA_HOOK_CACHE_LOOKUP_COMPLETE, cache_lookup) + return 0 +end http://git-wip-us.apache.org/repos/asf/trafficserver/blob/d3040199/plugins/experimental/ts_lua/ts_lua_misc.c ---------------------------------------------------------------------- diff --git a/plugins/experimental/ts_lua/ts_lua_misc.c b/plugins/experimental/ts_lua/ts_lua_misc.c index 5fc5b00..e9f8223 100644 --- a/plugins/experimental/ts_lua/ts_lua_misc.c +++ b/plugins/experimental/ts_lua/ts_lua_misc.c @@ -24,9 +24,13 @@ static int ts_lua_get_now_time(lua_State *L); static int ts_lua_debug(lua_State *L); static int ts_lua_error(lua_State *L); static int ts_lua_sleep(lua_State *L); +static int ts_lua_schedule(lua_State *L); static int ts_lua_sleep_cleanup(ts_lua_async_item *ai); static int ts_lua_sleep_handler(TSCont contp, TSEvent event, void *edata); +static int ts_lua_schedule_handler(TSCont contp, TSEvent event, void *edata); + +static void ts_lua_inject_misc_variables(lua_State *L); void ts_lua_inject_misc_api(lua_State *L) @@ -46,6 +50,21 @@ ts_lua_inject_misc_api(lua_State *L) /* ts.sleep(...) */ lua_pushcfunction(L, ts_lua_sleep); lua_setfield(L, -2, "sleep"); + + /* ts.schedule(...) */ + lua_pushcfunction(L, ts_lua_schedule); + lua_setfield(L, -2, "schedule"); + + ts_lua_inject_misc_variables(L); +} + +static void +ts_lua_inject_misc_variables(lua_State *L) +{ + lua_pushinteger(L, TS_THREAD_POOL_NET); + lua_setglobal(L, "TS_LUA_THREAD_POOL_NET"); + lua_pushinteger(L, TS_THREAD_POOL_TASK); + lua_setglobal(L, "TS_LUA_THREAD_POOL_TASK"); } static int @@ -82,6 +101,111 @@ ts_lua_error(lua_State *L) } static int +ts_lua_schedule(lua_State *L) +{ + int sec; + int type; + int entry; + + ts_lua_http_ctx *actx; + + int n; + + TSCont contp; + ts_lua_cont_info *ci; + ts_lua_cont_info *nci; + + ci = ts_lua_get_cont_info(L); + if (ci == NULL) + return 0; + + entry = lua_tointeger(L, 1); + + sec = luaL_checknumber(L, 2); + if (sec < 1) { + sec = 0; + } + + type = lua_type(L, 3); + if (type != LUA_TFUNCTION) + return 0; + + n = lua_gettop(L); + + if (n < 3) { + TSError("[ts_lua] ts.http.schedule need at least three params"); + return 0; + } + + // TO-DO unset the original context in L + actx = ts_lua_create_async_ctx(L, ci, n); + + contp = TSContCreate(ts_lua_schedule_handler, ci->mutex); + TSContDataSet(contp, actx); + + nci = &actx->cinfo; + nci->contp = contp; + nci->mutex = ci->mutex; + + TSContSchedule(contp, sec * 1000, entry); + + return 0; +} + +static int +ts_lua_schedule_handler(TSCont contp, TSEvent ev, void *edata) +{ + lua_State *L; + ts_lua_cont_info *ci; + ts_lua_coroutine *crt; + int event, n, ret, rc; + ts_lua_http_ctx *actx; + ts_lua_main_ctx *main_ctx; + + event = (int)ev; + TSDebug(TS_LUA_DEBUG_TAG, "getting actx and other info"); + actx = (ts_lua_http_ctx *)TSContDataGet(contp); + + TSDebug(TS_LUA_DEBUG_TAG, "getting http_Ctx"); + ci = &actx->cinfo; + crt = &ci->routine; + + main_ctx = crt->mctx; + L = crt->lua; + + rc = ret = 0; + + TSMutexLock(main_ctx->mutexp); + ts_lua_set_cont_info(L, ci); + + if (event == TS_LUA_EVENT_COROUTINE_CONT) { + TSDebug(TS_LUA_DEBUG_TAG, "event is coroutine_cont"); + n = (intptr_t)edata; + ret = lua_resume(L, n); + } else { + TSDebug(TS_LUA_DEBUG_TAG, "event is not coroutine_cont"); + n = lua_gettop(L); + ret = lua_resume(L, n - 1); + } + + if (ret == LUA_YIELD) { + TSMutexUnlock(main_ctx->mutexp); + goto done; + } + + if (ret != 0) { + TSError("[ts_lua] lua_resume failed: %s", lua_tostring(L, -1)); + } + + lua_pop(L, lua_gettop(L)); + TSMutexUnlock(main_ctx->mutexp); + ts_lua_destroy_async_ctx(actx); + +done: + return 0; +} + +static int ts_lua_sleep(lua_State *L) { int sec; http://git-wip-us.apache.org/repos/asf/trafficserver/blob/d3040199/plugins/experimental/ts_lua/ts_lua_util.c ---------------------------------------------------------------------- diff --git a/plugins/experimental/ts_lua/ts_lua_util.c b/plugins/experimental/ts_lua/ts_lua_util.c index ddef163..19e0bac 100644 --- a/plugins/experimental/ts_lua/ts_lua_util.c +++ b/plugins/experimental/ts_lua/ts_lua_util.c @@ -338,6 +338,47 @@ ts_lua_get_cont_info(lua_State *L) return ci; } +ts_lua_http_ctx * +ts_lua_create_async_ctx(lua_State *L, ts_lua_cont_info *hci, int n) +{ + int i; + lua_State *l; + ts_lua_coroutine *crt; + ts_lua_http_ctx *actx; + + actx = TSmalloc(sizeof(ts_lua_http_ctx)); + memset(actx, 0, sizeof(ts_lua_http_ctx)); + + // create lua_thread + l = lua_newthread(L); + + // init the coroutine + crt = &actx->cinfo.routine; + crt->mctx = hci->routine.mctx; + crt->lua = l; + crt->ref = luaL_ref(L, LUA_REGISTRYINDEX); + + // replace the param; start with 2 because first two params are not needed + for (i = 2; i < n; i++) { + lua_pushvalue(L, i + 1); + } + + lua_xmove(L, l, n - 2); + + return actx; +} + +void +ts_lua_destroy_async_ctx(ts_lua_http_ctx *http_ctx) +{ + ts_lua_cont_info *ci; + + ci = &http_ctx->cinfo; + + ts_lua_release_cont_info(ci); + TSfree(http_ctx); +} + void ts_lua_set_http_ctx(lua_State *L, ts_lua_http_ctx *ctx) { http://git-wip-us.apache.org/repos/asf/trafficserver/blob/d3040199/plugins/experimental/ts_lua/ts_lua_util.h ---------------------------------------------------------------------- diff --git a/plugins/experimental/ts_lua/ts_lua_util.h b/plugins/experimental/ts_lua/ts_lua_util.h index 7cd7675..e3dc9a9 100644 --- a/plugins/experimental/ts_lua/ts_lua_util.h +++ b/plugins/experimental/ts_lua/ts_lua_util.h @@ -39,6 +39,9 @@ ts_lua_instance_conf *ts_lua_get_instance_conf(lua_State *L); void ts_lua_set_cont_info(lua_State *L, ts_lua_cont_info *ci); ts_lua_cont_info *ts_lua_get_cont_info(lua_State *L); +ts_lua_http_ctx *ts_lua_create_async_ctx(lua_State *L, ts_lua_cont_info *hci, int n); +void ts_lua_destroy_async_ctx(ts_lua_http_ctx *http_ctx); + void ts_lua_set_http_ctx(lua_State *L, ts_lua_http_ctx *ctx); ts_lua_http_ctx *ts_lua_get_http_ctx(lua_State *L);
