From a57c94371f35e9edab0bfcd11b9be814ad20afe7 Mon Sep 17 00:00:00 2001 From: "W.C.A. Wijngaards" Date: Tue, 9 Jan 2024 12:06:00 +0100 Subject: [PATCH] - fast-reload, reload the config and swap trees for forwards and stub hints. --- daemon/remote.c | 79 +++++++++++++++++++++++++++++++++++++++++++ iterator/iter_fwd.c | 8 +++++ iterator/iter_fwd.h | 9 +++++ iterator/iter_hints.c | 8 +++++ iterator/iter_hints.h | 9 +++++ 5 files changed, 113 insertions(+) diff --git a/daemon/remote.c b/daemon/remote.c index 28c2ceccd..ead1067f2 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -3709,6 +3709,9 @@ struct fast_reload_construct { struct iter_forwards* fwds; /** construct for stubs */ struct iter_hints* hints; + /** storage for the old configuration elements. The outer struct + * is allocated with malloc here, the items are from config. */ + struct config_file* oldcfg; }; /** fast reload thread, read config */ @@ -3754,6 +3757,13 @@ fr_construct_clear(struct fast_reload_construct* ct) return; forwards_delete(ct->fwds); hints_delete(ct->hints); + /* Delete the log identity here so that the global value is not + * reset by config_delete. */ + if(ct->oldcfg->log_identity) { + free(ct->oldcfg->log_identity); + ct->oldcfg->log_identity = NULL; + } + config_delete(ct->oldcfg); } /** fast reload thread, construct from config the new items */ @@ -3779,6 +3789,11 @@ fr_construct_from_config(struct fast_reload_thread* fr, if(fr_poll_for_quit(fr)) return 1; + if(!(ct->oldcfg = (struct config_file*)calloc(1, + sizeof(*ct->oldcfg)))) { + fr_construct_clear(ct); + return 0; + } return 1; } @@ -3816,6 +3831,62 @@ fr_finish_time(struct fast_reload_thread* fr, struct timeval* time_start, return 1; } +/** fast reload thread, reload config with putting the new config items + * in place and swapping out the old items. */ +static int +fr_reload_config(struct fast_reload_thread* fr, struct config_file* newcfg, + struct fast_reload_construct* ct) +{ + struct daemon* daemon = fr->worker->daemon; + struct module_env* env = daemon->env; + + /* Grab big locks to satisfy lock conditions. */ + lock_rw_wrlock(&ct->fwds->lock); + lock_rw_wrlock(&ct->hints->lock); + lock_rw_wrlock(&env->fwds->lock); + lock_rw_wrlock(&env->hints->lock); + + /* Store old config elements. */ + *ct->oldcfg = *env->cfg; + /* Insert new config elements. */ + *env->cfg = *newcfg; + if(env->cfg->log_identity || ct->oldcfg->log_identity) { + /* pick up new log_identity string to use for log output. */ + log_ident_set_or_default(env->cfg->log_identity); + } + /* the newcfg elements are in env->cfg, so should not be freed here. */ + memset(newcfg, 0, sizeof(*newcfg)); + + /* Quickly swap the tree roots themselves with the already allocated + * elements. This is a quick swap operation on the pointer. + * The other threads are stopped and locks are held, so that a + * consistent view of the configuration, before, and after, exists + * towards the state machine for query resolution. */ + forwards_swap_tree(env->fwds, ct->fwds); + hints_swap_tree(env->hints, ct->hints); + + /* Set globals with new config. */ + config_apply(env->cfg); + + lock_rw_unlock(&env->fwds->lock); + lock_rw_unlock(&env->hints->lock); + lock_rw_unlock(&ct->fwds->lock); + lock_rw_unlock(&ct->hints->lock); + + return 1; +} + +/** fast reload thread, reload ipc communication to stop and start threads. */ +static int +fr_reload_ipc(struct fast_reload_thread* fr, struct config_file* newcfg, + struct fast_reload_construct* ct) +{ + if(!fr_reload_config(fr, newcfg, ct)) { + return 0; + } + return 1; +} + /** fast reload thread, load config */ static int fr_load_config(struct fast_reload_thread* fr, struct timeval* time_read, @@ -3854,6 +3925,14 @@ fr_load_config(struct fast_reload_thread* fr, struct timeval* time_read, } /* Reload server. */ + if(!fr_reload_ipc(fr, newcfg, &ct)) { + config_delete(newcfg); + fr_construct_clear(&ct); + if(!fr_output_printf(fr, "error: reload failed\n")) + return 0; + fr_send_notification(fr, fast_reload_notification_printout); + return 0; + } if(gettimeofday(time_reload, NULL) < 0) log_err("gettimeofday: %s", strerror(errno)); diff --git a/iterator/iter_fwd.c b/iterator/iter_fwd.c index cf418b072..e2697bab4 100644 --- a/iterator/iter_fwd.c +++ b/iterator/iter_fwd.c @@ -539,3 +539,11 @@ forwards_delete_stub_hole(struct iter_forwards* fwd, uint16_t c, uint8_t* nm) fwd_zone_free(z); fwd_init_parents(fwd); } + +void +forwards_swap_tree(struct iter_forwards* fwd, struct iter_forwards* data) +{ + rbtree_type* oldtree = fwd->tree; + fwd->tree = data->tree; + data->tree = oldtree; +} diff --git a/iterator/iter_fwd.h b/iterator/iter_fwd.h index c1160b853..e51165ede 100644 --- a/iterator/iter_fwd.h +++ b/iterator/iter_fwd.h @@ -207,4 +207,13 @@ int forwards_add_stub_hole(struct iter_forwards* fwd, uint16_t c, uint8_t* nm); void forwards_delete_stub_hole(struct iter_forwards* fwd, uint16_t c, uint8_t* nm); +/** + * Swap internal tree with preallocated entries. Caller should manage + * the locks. + * @param fwd: the forward data structure. + * @param data: the data structure used to take elements from. This contains + * the old elements on return. + */ +void forwards_swap_tree(struct iter_forwards* fwd, struct iter_forwards* data); + #endif /* ITERATOR_ITER_FWD_H */ diff --git a/iterator/iter_hints.c b/iterator/iter_hints.c index a56aa8e40..ce2741eaf 100644 --- a/iterator/iter_hints.c +++ b/iterator/iter_hints.c @@ -575,3 +575,11 @@ hints_delete_stub(struct iter_hints* hints, uint16_t c, uint8_t* nm) hints_stub_free(z); name_tree_init_parents(&hints->tree); } + +void +hints_swap_tree(struct iter_hints* hints, struct iter_hints* data) +{ + rbnode_type* oldroot = hints->tree.root; + hints->tree.root = data->tree.root; + data->tree.root = oldroot; +} diff --git a/iterator/iter_hints.h b/iterator/iter_hints.h index f201d8c11..6f6b6dc68 100644 --- a/iterator/iter_hints.h +++ b/iterator/iter_hints.h @@ -168,4 +168,13 @@ int hints_add_stub(struct iter_hints* hints, uint16_t c, struct delegpt* dp, */ void hints_delete_stub(struct iter_hints* hints, uint16_t c, uint8_t* nm); +/** + * Swap internal tree with preallocated entries. Caller should manage + * the locks. + * @param hints: the hints data structure. + * @param data: the data structure used to take elements from. This contains + * the old elements on return. + */ +void hints_swap_tree(struct iter_hints* hints, struct iter_hints* data); + #endif /* ITERATOR_ITER_HINTS_H */ -- 2.47.2