From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: From: Serge Petrenko Subject: [PATCH v4 2/2] box: implement on_shutdown triggers Date: Sat, 29 Dec 2018 16:45:40 +0300 Message-Id: <9dcaebf07a3018f46968748a8df04007b36ba4d6.1546090754.git.sergepetrenko@tarantool.org> In-Reply-To: References: In-Reply-To: References: To: vdavydov.dev@gmail.com Cc: kostja@tarantool.org, tarantool-patches@freelists.org, Serge Petrenko List-ID: Add on_shutdown triggers which are run by a preallocated fiber on shutdown and make it possible to register them via box.ctl.on_shutdown() Make use of the new triggers: now dedicate an on_shutdown trigger to break event loop instead of doing it explicitly from signal handler. The trigger is run last, so that all other on_shutdown triggers may yield, sleep and so on. Also make sure we can register lbox_triggers without push_event function in case we don't need one. Closes #1607 @TarantoolBot document Title: Document box.ctl.on_shutdown triggers on_shutdown triggers may be set similar to space:on_replace triggers: ``` box.ctl.on_shutdown(new_trigger, old_trigger) ``` The triggers will be run when tarantool exits due to receiving one of the signals: `SIGTERM`, `SIGINT`, `SIGHUP`. Note that the triggers will not be run if you exit tarantool by typing `os.exit()` to the lua console or if tarantool receives a fatal signal: `SIGSEGV`, `SIGABORT` or any signal causing immediate program termination. --- src/box/box.cc | 2 ++ src/box/box.h | 3 ++ src/box/lua/ctl.c | 8 +++++ src/lua/trigger.c | 5 ++- src/main.cc | 51 ++++++++++++++++++++++++++++-- test/box/misc.result | 72 ++++++++++++++++++++++++++++++++++++++++++ test/box/misc.test.lua | 32 +++++++++++++++++++ 7 files changed, 170 insertions(+), 3 deletions(-) diff --git a/src/box/box.cc b/src/box/box.cc index 9642364f6..049ed234f 100644 --- a/src/box/box.cc +++ b/src/box/box.cc @@ -79,6 +79,8 @@ static char status[64] = "unknown"; /** box.stat rmean */ struct rmean *rmean_box; +struct rlist box_on_shutdown = RLIST_HEAD_INITIALIZER(box_on_shutdown); + static void title(const char *new_status) { snprintf(status, sizeof(status), "%s", new_status); diff --git a/src/box/box.h b/src/box/box.h index cb9a512be..16adc4135 100644 --- a/src/box/box.h +++ b/src/box/box.h @@ -64,6 +64,9 @@ struct vclock; */ extern const struct vclock *box_vclock; +/** Invoked on box shutdown. */ +extern struct rlist box_on_shutdown; + /* * Initialize box library * @throws C++ exception diff --git a/src/box/lua/ctl.c b/src/box/lua/ctl.c index 9a105ed5c..7010be138 100644 --- a/src/box/lua/ctl.c +++ b/src/box/lua/ctl.c @@ -37,6 +37,7 @@ #include #include "lua/utils.h" +#include "lua/trigger.h" #include "box/box.h" @@ -64,9 +65,16 @@ lbox_ctl_wait_rw(struct lua_State *L) return 0; } +static int +lbox_ctl_on_shutdown(struct lua_State *L) +{ + return lbox_trigger_reset(L, 2, &box_on_shutdown, NULL, NULL); +} + static const struct luaL_Reg lbox_ctl_lib[] = { {"wait_ro", lbox_ctl_wait_ro}, {"wait_rw", lbox_ctl_wait_rw}, + {"on_shutdown", lbox_ctl_on_shutdown}, {NULL, NULL} }; diff --git a/src/lua/trigger.c b/src/lua/trigger.c index 2c2ede212..ec4d8aab3 100644 --- a/src/lua/trigger.c +++ b/src/lua/trigger.c @@ -91,7 +91,10 @@ lbox_trigger_run(struct trigger *ptr, void *event) } int top = lua_gettop(L); lua_rawgeti(L, LUA_REGISTRYINDEX, trigger->ref); - int nargs = trigger->push_event(L, event); + int nargs = 0; + if (trigger->push_event != NULL) { + nargs = trigger->push_event(L, event); + } if (luaT_call(L, nargs, LUA_MULTRET)) { luaL_unref(tarantool_L, LUA_REGISTRYINDEX, coro_ref); diag_raise(); diff --git a/src/main.cc b/src/main.cc index 4303fb32c..a6bdac5d8 100644 --- a/src/main.cc +++ b/src/main.cc @@ -89,6 +89,10 @@ static const int ev_sig_count = sizeof(ev_sigs)/sizeof(*ev_sigs); static double start_time; +/** A preallocated fiber to run on_shutdown triggers. */ +static struct fiber *on_exit_fiber = NULL; +static bool is_shutting_down = false; + double tarantool_uptime(void) { @@ -119,9 +123,32 @@ sig_checkpoint(ev_loop * /* loop */, struct ev_signal * /* w */, fiber_wakeup(f); } +static int +on_exit_f(va_list ap) +{ + (void) ap; + trigger_run(&box_on_shutdown, NULL); + return 0; +} + +void +tarantool_exit(void) +{ + if (is_shutting_down) + /* + * We are already running on_shutdown triggers, + * and will exit as soon as they'll finish. + * Do not execute them twice. + */ + return; + is_shutting_down = true; + fiber_wakeup(on_exit_fiber); +} + static void signal_cb(ev_loop *loop, struct ev_signal *w, int revents) { + (void) loop; (void) w; (void) revents; @@ -135,8 +162,7 @@ signal_cb(ev_loop *loop, struct ev_signal *w, int revents) if (pid_file) say_crit("got signal %d - %s", w->signum, strsignal(w->signum)); start_loop = false; - /* Terminate the main event loop */ - ev_break(loop, EVBREAK_ALL); + tarantool_exit(); } static void @@ -636,6 +662,12 @@ print_help(const char *program) puts("to see online documentation, submit bugs or contribute a patch."); } +void +break_loop(struct trigger *, void *) +{ + ev_break(loop(), EVBREAK_ALL); +} + int main(int argc, char **argv) { @@ -759,6 +791,21 @@ main(int argc, char **argv) try { box_init(); box_lua_init(tarantool_L); + /* Reserve a fiber to run on_shutdown triggers. */ + on_exit_fiber = fiber_new("on_exit", on_exit_f); + if (on_exit_fiber == NULL) + diag_raise(); + /* + * Register a on_shutdown trigger which will break the + * main event loop. The trigger will be the last to run + * since it's the first one we register. + */ + struct trigger *trig = (struct trigger *)malloc(sizeof(*trig)); + if (trig == NULL) + tnt_raise(OutOfMemory, sizeof(*trig), + "malloc", "struct trigger"); + trigger_create(trig, break_loop, NULL, NULL); + trigger_add(&box_on_shutdown, trig); atexit(tarantool_atexit); diff --git a/test/box/misc.result b/test/box/misc.result index 9fecbce76..9ffc11b88 100644 --- a/test/box/misc.result +++ b/test/box/misc.result @@ -1249,3 +1249,75 @@ box.cfg{too_long_threshold = too_long_threshold} s:drop() --- ... +-- +-- gh-1607: on_shutdown triggers. +-- +f = function() print('on_shutdown 1') end +--- +... +g = function() print('on_shutdown 2') end +--- +... +h = function() print('on_shutdown 3') end +--- +... +-- Check that on_shutdown triggers may yield +-- and perform some complicated actions. +fiber = require('fiber') +--- +... +test_run:cmd("setopt delimiter ';'") +--- +- true +... +trig = function() + fiber.sleep(0.01) + fiber.yield() + box.schema.space.create("shutdown") + box.space.shutdown:create_index("pk") + box.space.shutdown:insert{1,2,3} + print('on_shutdown 4') +end; +--- +... +test_run:cmd("setopt delimiter ''"); +--- +- true +... +_ = box.ctl.on_shutdown(f) +--- +... +_ = box.ctl.on_shutdown(g) +--- +... +-- Check that replacing triggers works +_ = box.ctl.on_shutdown(h, g) +--- +... +_ = box.ctl.on_shutdown(trig) +--- +... +test_run:cmd('restart server default') +test_run:grep_log('default', 'on_shutdown 1', nil, {noreset=true}) +--- +- on_shutdown 1 +... +test_run:grep_log('default', 'on_shutdown 2', nil, {noreset=true}) +--- +- null +... +test_run:grep_log('default', 'on_shutdown 3', nil, {noreset=true}) +--- +- on_shutdown 3 +... +test_run:grep_log('default', 'on_shutdown 4', nil, {noreset=true}) +--- +- on_shutdown 4 +... +box.space.shutdown:select{} +--- +- - [1, 2, 3] +... +box.space.shutdown:drop() +--- +... diff --git a/test/box/misc.test.lua b/test/box/misc.test.lua index cc6cb34fb..f1c9d8e8c 100644 --- a/test/box/misc.test.lua +++ b/test/box/misc.test.lua @@ -352,3 +352,35 @@ rows == expected_rows lsn == expected_lsn box.cfg{too_long_threshold = too_long_threshold} s:drop() + +-- +-- gh-1607: on_shutdown triggers. +-- +f = function() print('on_shutdown 1') end +g = function() print('on_shutdown 2') end +h = function() print('on_shutdown 3') end +-- Check that on_shutdown triggers may yield +-- and perform some complicated actions. +fiber = require('fiber') +test_run:cmd("setopt delimiter ';'") +trig = function() + fiber.sleep(0.01) + fiber.yield() + box.schema.space.create("shutdown") + box.space.shutdown:create_index("pk") + box.space.shutdown:insert{1,2,3} + print('on_shutdown 4') +end; +test_run:cmd("setopt delimiter ''"); +_ = box.ctl.on_shutdown(f) +_ = box.ctl.on_shutdown(g) +-- Check that replacing triggers works +_ = box.ctl.on_shutdown(h, g) +_ = box.ctl.on_shutdown(trig) +test_run:cmd('restart server default') +test_run:grep_log('default', 'on_shutdown 1', nil, {noreset=true}) +test_run:grep_log('default', 'on_shutdown 2', nil, {noreset=true}) +test_run:grep_log('default', 'on_shutdown 3', nil, {noreset=true}) +test_run:grep_log('default', 'on_shutdown 4', nil, {noreset=true}) +box.space.shutdown:select{} +box.space.shutdown:drop() -- 2.17.2 (Apple Git-113)