summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Salzman <daniel.salzman@nic.cz>2022-11-24 20:31:34 +0100
committerDaniel Salzman <daniel.salzman@nic.cz>2022-12-05 15:14:43 +0100
commit089cbd1023f4cb7b7495362152f1583fd615ff71 (patch)
tree5582dbdad5db85044e0b44079174b99bb3a0ebf4
parentdoc/reference: make effect of missing ACL "address" and "key" items clear (diff)
downloadknot-089cbd1023f4cb7b7495362152f1583fd615ff71.tar.xz
knot-089cbd1023f4cb7b7495362152f1583fd615ff71.zip
zonedb: reload changed catalog members only (reuse otherwise), refactoring
-rw-r--r--configure.ac2
-rw-r--r--src/knot/catalog/catalog_update.c3
-rw-r--r--src/knot/ctl/commands.c4
-rw-r--r--src/knot/server/server.c8
-rw-r--r--src/knot/server/server.h28
-rw-r--r--src/knot/updates/zone-update.c10
-rw-r--r--src/knot/zone/zonedb-load.c62
-rw-r--r--src/knot/zone/zonedb-load.h9
-rw-r--r--src/utils/knotd/main.c8
-rw-r--r--tests-extra/tests/catalog/multi/test.py6
10 files changed, 86 insertions, 54 deletions
diff --git a/configure.ac b/configure.ac
index 43b8b8217..8fecd828a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -712,7 +712,7 @@ LIBS="$save_LIBS"
# Checks for header files.
AC_HEADER_RESOLV
-AC_CHECK_HEADERS_ONCE([pthread_np.h sys/uio.h bsd/string.h])
+AC_CHECK_HEADERS_ONCE([pthread_np.h stdatomic.h sys/uio.h bsd/string.h])
# Checks for optional library functions.
AC_CHECK_FUNCS([accept4 clock_gettime fgetln getline initgroups malloc_trim \
diff --git a/src/knot/catalog/catalog_update.c b/src/knot/catalog/catalog_update.c
index faed011f3..50f38cbc2 100644
--- a/src/knot/catalog/catalog_update.c
+++ b/src/knot/catalog/catalog_update.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2021 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+/* Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -398,6 +398,7 @@ int catalog_zone_purge(server_t *server, conf_t *conf, const knot_dname_t *zone)
int ret = catalog_update_del_all(&server->catalog_upd, &server->catalog, zone, &members);
if (ret == KNOT_EOK && members > 0) {
log_zone_info(zone, "catalog zone purged, %zd member zones deconfigured", members);
+ server->catalog_upd_signal = true;
if (kill(getpid(), SIGUSR1) != 0) {
ret = knot_map_errno();
}
diff --git a/src/knot/ctl/commands.c b/src/knot/ctl/commands.c
index 8d502e29c..8a4dbe993 100644
--- a/src/knot/ctl/commands.c
+++ b/src/knot/ctl/commands.c
@@ -1839,7 +1839,7 @@ static int ctl_server(ctl_args_t *args, ctl_cmd_t cmd)
ret = KNOT_CTL_ESTOP;
break;
case CTL_RELOAD:
- ret = server_reload(args->server);
+ ret = server_reload(args->server, RELOAD_FULL);
if (ret != KNOT_EOK) {
send_error(args, knot_strerror(ret));
}
@@ -2059,7 +2059,7 @@ static int ctl_conf_txn(ctl_args_t *args, ctl_cmd_t cmd)
break;
}
- ret = server_reload(args->server);
+ ret = server_reload(args->server, RELOAD_COMMIT);
break;
default:
assert(0);
diff --git a/src/knot/server/server.c b/src/knot/server/server.c
index c4fa12ae1..616a8d93f 100644
--- a/src/knot/server/server.c
+++ b/src/knot/server/server.c
@@ -1047,7 +1047,7 @@ static void warn_server_reconfigure(conf_t *conf, server_t *server)
}
}
-int server_reload(server_t *server)
+int server_reload(server_t *server, reload_t mode)
{
if (server == NULL) {
return KNOT_EINVAL;
@@ -1109,7 +1109,7 @@ int server_reload(server_t *server)
stats_reconfigure(conf(), server);
}
if (full || (flags & (CONF_IO_FRLD_ZONES | CONF_IO_FRLD_ZONE))) {
- server_update_zones(conf(), server);
+ server_update_zones(conf(), server, mode);
}
/* Free old config needed for module unload in zone reload. */
@@ -1303,7 +1303,7 @@ int server_reconfigure(conf_t *conf, server_t *server)
return KNOT_EOK;
}
-void server_update_zones(conf_t *conf, server_t *server)
+void server_update_zones(conf_t *conf, server_t *server, reload_t mode)
{
if (conf == NULL || server == NULL) {
return;
@@ -1319,7 +1319,7 @@ void server_update_zones(conf_t *conf, server_t *server)
worker_pool_wait(server->workers);
/* Reload zone database and free old zones. */
- zonedb_reload(conf, server);
+ zonedb_reload(conf, server, mode);
/* Trim extra heap. */
mem_trim();
diff --git a/src/knot/server/server.h b/src/knot/server/server.h
index 98f28f0ac..5adafdb6a 100644
--- a/src/knot/server/server.h
+++ b/src/knot/server/server.h
@@ -16,6 +16,8 @@
#pragma once
+#include <stdatomic.h>
+
#include "knot/conf/conf.h"
#include "knot/catalog/catalog_update.h"
#include "knot/common/evsched.h"
@@ -49,6 +51,17 @@ typedef enum {
} server_state_t;
/*!
+ * \brief Server reload kinds.
+ */
+typedef enum {
+ RELOAD_NONE = 0,
+ RELOAD_FULL = 1 << 0, /*!< Reload the server and all zones. */
+ RELOAD_COMMIT = 1 << 1, /*!< Process changes from dynamic configuration. */
+ RELOAD_ZONES = 1 << 2, /*!< Reload all zones. */
+ RELOAD_CATALOG = 1 << 3, /*!< Process catalog zone changes. */
+} reload_t;
+
+/*!
* \brief Server interface structure.
*/
typedef struct {
@@ -103,8 +116,9 @@ typedef struct server {
iface_t *ifaces;
size_t n_ifaces;
- /*! \brief Pending changes to catalog member zones. */
+ /*! \brief Pending changes to catalog member zones, update indication. */
catalog_update_t catalog_upd;
+ atomic_bool catalog_upd_signal;
/*! \brief Context of pending zones' backup. */
zone_backup_ctxs_t backup_ctxs;
@@ -152,10 +166,11 @@ void server_wait(server_t *server);
* \brief Reload server configuration.
*
* \param server Server instance.
+ * \param mode Reload mode.
*
* \return Error code, KNOT_EOK if success.
*/
-int server_reload(server_t *server);
+int server_reload(server_t *server, reload_t mode);
/*!
* \brief Requests server to stop.
@@ -169,6 +184,9 @@ void server_stop(server_t *server);
*
* Routine for dynamic server reconfiguration.
*
+ * \param conf Configuration.
+ * \param server Server instance.
+ *
* \return Error code, KNOT_EOK if success.
*/
int server_reconfigure(conf_t *conf, server_t *server);
@@ -177,5 +195,9 @@ int server_reconfigure(conf_t *conf, server_t *server);
* \brief Reconfigure zone database.
*
* Routine for dynamic server zones reconfiguration.
+ *
+ * \param conf Configuration.
+ * \param server Server instance.
+ * \param mode Reload mode.
*/
-void server_update_zones(conf_t *conf, server_t *server);
+void server_update_zones(conf_t *conf, server_t *server, reload_t mode);
diff --git a/src/knot/updates/zone-update.c b/src/knot/updates/zone-update.c
index f857be269..952db4809 100644
--- a/src/knot/updates/zone-update.c
+++ b/src/knot/updates/zone-update.c
@@ -14,10 +14,15 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
+#include <signal.h>
+#include <unistd.h>
+#include <urcu.h>
+
#include "knot/catalog/interpret.h"
#include "knot/common/log.h"
#include "knot/common/systemd.h"
#include "knot/dnssec/zone-events.h"
+#include "knot/server/server.h"
#include "knot/updates/zone-update.h"
#include "knot/zone/adds_tree.h"
#include "knot/zone/adjust.h"
@@ -28,10 +33,6 @@
#include "contrib/trim.h"
#include "contrib/ucw/lists.h"
-#include <signal.h>
-#include <unistd.h>
-#include <urcu.h>
-
// Call mem_trim() whenever accumulated size of updated zones reaches this size.
#define UPDATE_MEMTRIM_AT (10 * 1024 * 1024)
@@ -783,6 +784,7 @@ static int update_catalog(conf_t *conf, zone_update_t *update)
if (ret == KNOT_EOK) {
log_zone_info(update->zone->name, "catalog reloaded, %zd updates", upd_count);
+ update->zone->server->catalog_upd_signal = true;
if (kill(getpid(), SIGUSR1) != 0) {
ret = knot_map_errno();
}
diff --git a/src/knot/zone/zonedb-load.c b/src/knot/zone/zonedb-load.c
index 842258a20..cedf83378 100644
--- a/src/knot/zone/zonedb-load.c
+++ b/src/knot/zone/zonedb-load.c
@@ -32,9 +32,6 @@
#include "knot/zone/zonefile.h"
#include "libknot/libknot.h"
-#define FULL(conf) (!((conf)->io.flags & CONF_IO_FACTIVE) || \
- ((conf)->io.flags & CONF_IO_FRLD_ZONES))
-
static bool zone_file_updated(conf_t *conf, const zone_t *old_zone,
const knot_dname_t *zone_name)
{
@@ -278,14 +275,12 @@ static bool check_open_catalog(catalog_t *cat)
}
static zone_t *reuse_member_zone(zone_t *zone, server_t *server, conf_t *conf,
- list_t *expired_contents)
+ reload_t mode, list_t *expired_contents)
{
if (!zone_get_flag(zone, ZONE_IS_CAT_MEMBER, false)) {
return NULL;
}
- bool full = FULL(conf);
-
catalog_upd_val_t *upd = catalog_update_get(&server->catalog_upd, zone->name);
if (upd != NULL) {
switch (upd->type) {
@@ -295,10 +290,12 @@ static zone_t *reuse_member_zone(zone_t *zone, server_t *server, conf_t *conf,
ptrlist_add(expired_contents, zone_expire(zone), NULL);
knot_sem_post(&zone->cow_lock);
// FALLTHROUGH
- case CAT_UPD_INVALID:
- case CAT_UPD_MINOR:
case CAT_UPD_PROP:
+ zone->change_type = CONF_IO_TRELOAD;
break; // reload the member zone
+ case CAT_UPD_INVALID:
+ case CAT_UPD_MINOR:
+ return zone; // reuse the member zone
case CAT_UPD_REM:
return NULL; // remove the member zone
case CAT_UPD_ADD: // cannot add existing member
@@ -306,9 +303,7 @@ static zone_t *reuse_member_zone(zone_t *zone, server_t *server, conf_t *conf,
assert(0);
return NULL;
}
- }
-
- if (!full && (upd == NULL || upd->type != CAT_UPD_UNIQ)) {
+ } else if (mode & (RELOAD_COMMIT | RELOAD_CATALOG)) {
return zone; // reuse the member zone
}
@@ -400,11 +395,13 @@ static zone_t *add_member_zone(catalog_upd_val_t *val, knot_zonedb_t *check,
*
* \param conf New server configuration.
* \param server Server instance.
+ * \param mode Reload mode.
* \param expired_contents Out: ptrlist of zone_contents_t to be deep freed after sync RCU.
*
* \return New zone database.
*/
-static knot_zonedb_t *create_zonedb(conf_t *conf, server_t *server, list_t *expired_contents)
+static knot_zonedb_t *create_zonedb(conf_t *conf, server_t *server, reload_t mode,
+ list_t *expired_contents)
{
assert(conf);
assert(server);
@@ -415,10 +412,8 @@ static knot_zonedb_t *create_zonedb(conf_t *conf, server_t *server, list_t *expi
return NULL;
}
- bool full = FULL(conf);
-
- /* Mark changed zones. */
- if (!full) {
+ /* Mark changed zones during dynamic configuration. */
+ if (mode == RELOAD_COMMIT) {
mark_changed_zones(db_old, conf->io.zones);
}
@@ -429,7 +424,7 @@ static knot_zonedb_t *create_zonedb(conf_t *conf, server_t *server, list_t *expi
const knot_dname_t *name = conf_dname(&id);
zone_t *old_zone = knot_zonedb_find(db_old, name);
- if (old_zone != NULL && !full) {
+ if (old_zone != NULL && (mode & (RELOAD_COMMIT | RELOAD_CATALOG))) {
/* Reuse unchanged zone. */
if (!(old_zone->change_type & CONF_IO_TRELOAD)) {
knot_zonedb_insert(db_new, old_zone);
@@ -449,13 +444,14 @@ static knot_zonedb_t *create_zonedb(conf_t *conf, server_t *server, list_t *expi
knot_zonedb_insert(db_new, zone);
}
- /* Remove deleted cataloged zones from conf before catalog removals are commited. */
+ /* Purge decataloged zones before catalog removals are commited. */
catalog_it_t *cat_it = catalog_it_begin(&server->catalog_upd);
while (!catalog_it_finished(cat_it)) {
catalog_upd_val_t *upd = catalog_it_val(cat_it);
if (upd->type == CAT_UPD_REM) {
zone_t *zone = knot_zonedb_find(db_old, upd->member);
if (zone != NULL) {
+ zone->change_type = CONF_IO_TUNSET;
zone_purge(conf, zone);
}
}
@@ -474,7 +470,8 @@ static knot_zonedb_t *create_zonedb(conf_t *conf, server_t *server, list_t *expi
knot_zonedb_iter_t *it = knot_zonedb_iter_begin(db_old);
while (!knot_zonedb_iter_finished(it)) {
zone_t *newzone = reuse_member_zone(knot_zonedb_iter_val(it),
- server, conf, expired_contents);
+ server, conf, mode,
+ expired_contents);
if (newzone != NULL) {
knot_zonedb_insert(db_new, newzone);
}
@@ -536,14 +533,12 @@ static knot_zonedb_t *create_zonedb(conf_t *conf, server_t *server, list_t *expi
* \param server Server context.
*/
static void remove_old_zonedb(conf_t *conf, knot_zonedb_t *db_old,
- server_t *server)
+ server_t *server, reload_t mode)
{
catalog_commit_cleanup(&server->catalog);
knot_zonedb_t *db_new = server->zone_db;
- bool full = FULL(conf);
-
if (db_old == NULL) {
goto catalog_only;
}
@@ -551,7 +546,7 @@ static void remove_old_zonedb(conf_t *conf, knot_zonedb_t *db_old,
knot_zonedb_iter_t *it = knot_zonedb_iter_begin(db_old);
while (!knot_zonedb_iter_finished(it)) {
zone_t *zone = knot_zonedb_iter_val(it);
- if (full) {
+ if (mode & (RELOAD_FULL | RELOAD_ZONES)) {
/* Check if reloaded (reused contents). */
zone_t *new_zone = knot_zonedb_find(db_new, zone->name);
if (new_zone != NULL) {
@@ -565,7 +560,6 @@ static void remove_old_zonedb(conf_t *conf, knot_zonedb_t *db_old,
zone_t *new_zone = knot_zonedb_find(db_new, zone->name);
assert(new_zone);
replan_events(conf, new_zone, zone);
-
zone->contents = NULL;
zone_free(&zone);
/* Check if removed (drop also contents). */
@@ -584,27 +578,37 @@ catalog_only:
* thread while all zone events are paused. */
catalog_update_clear(&server->catalog_upd);
- if (full) {
+ if (mode & (RELOAD_FULL | RELOAD_ZONES)) {
knot_zonedb_deep_free(&db_old, false);
} else {
knot_zonedb_free(&db_old);
}
}
-void zonedb_reload(conf_t *conf, server_t *server)
+void zonedb_reload(conf_t *conf, server_t *server, reload_t mode)
{
if (conf == NULL || server == NULL) {
return;
}
+ if (mode == RELOAD_COMMIT) {
+ assert(conf->io.flags & CONF_IO_FACTIVE);
+ if (conf->io.flags & CONF_IO_FRLD_ZONES) {
+ mode = RELOAD_ZONES;
+ }
+ }
+
list_t contents_tofree;
init_list(&contents_tofree);
catalog_update_finalize(&server->catalog_upd, &server->catalog, conf);
- log_info("catalog, updating, %zu changes", trie_weight(server->catalog_upd.upd));
+ size_t cat_upd_size = trie_weight(server->catalog_upd.upd);
+ if (cat_upd_size > 0) {
+ log_info("catalog, updating, %zu changes", cat_upd_size);
+ }
/* Insert all required zones to the new zone DB. */
- knot_zonedb_t *db_new = create_zonedb(conf, server, &contents_tofree);
+ knot_zonedb_t *db_new = create_zonedb(conf, server, mode, &contents_tofree);
if (db_new == NULL) {
log_error("failed to create new zone database");
return;
@@ -622,7 +626,7 @@ void zonedb_reload(conf_t *conf, server_t *server)
ptrlist_free_custom(&contents_tofree, NULL, (ptrlist_free_cb)zone_contents_deep_free);
/* Remove old zone DB. */
- remove_old_zonedb(conf, db_old, server);
+ remove_old_zonedb(conf, db_old, server, mode);
}
int zone_reload_modules(conf_t *conf, server_t *server, const knot_dname_t *zone_name)
diff --git a/src/knot/zone/zonedb-load.h b/src/knot/zone/zonedb-load.h
index 1a0ea3268..c69b831d9 100644
--- a/src/knot/zone/zonedb-load.h
+++ b/src/knot/zone/zonedb-load.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2020 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+/* Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -22,10 +22,11 @@
/*!
* \brief Update zone database according to configuration.
*
- * \param[in] conf Configuration.
- * \param[in] server Server instance.
+ * \param conf Configuration.
+ * \param server Server instance.
+ * \param mode Reload mode.
*/
-void zonedb_reload(conf_t *conf, server_t *server);
+void zonedb_reload(conf_t *conf, server_t *server, reload_t mode);
/*!
* \brief Re-create zone_t struct in zoneDB so that the zone is reloaded incl modules.
diff --git a/src/utils/knotd/main.c b/src/utils/knotd/main.c
index 3f8ce4b5a..34990288f 100644
--- a/src/utils/knotd/main.c
+++ b/src/utils/knotd/main.c
@@ -259,11 +259,13 @@ static void event_loop(server_t *server, const char *socket)
/* Interrupts. */
if (sig_req_reload && !sig_req_stop) {
sig_req_reload = false;
- server_reload(server);
+ server_reload(server, RELOAD_FULL);
}
if (sig_req_zones_reload && !sig_req_stop) {
sig_req_zones_reload = false;
- server_update_zones(conf(), server);
+ reload_t mode = server->catalog_upd_signal ? RELOAD_CATALOG : RELOAD_ZONES;
+ server->catalog_upd_signal = false;
+ server_update_zones(conf(), server, mode);
}
if (sig_req_stop) {
break;
@@ -571,7 +573,7 @@ int main(int argc, char **argv)
/* Populate zone database. */
log_info("loading %zu zones", conf_id_count(conf(), C_ZONE));
- server_update_zones(conf(), &server);
+ server_update_zones(conf(), &server, RELOAD_ZONES);
/* Check number of loaded zones. */
if (knot_zonedb_size(server.zone_db) == 0) {
diff --git a/tests-extra/tests/catalog/multi/test.py b/tests-extra/tests/catalog/multi/test.py
index 0858fe6d8..1d5b1948e 100644
--- a/tests-extra/tests/catalog/multi/test.py
+++ b/tests-extra/tests/catalog/multi/test.py
@@ -58,14 +58,14 @@ master.ctl("zone-reload %s" % zone[1].name)
t.sleep(5)
check_exists(master, "member1.example.", True, "First")
-check_exists(master, "member2.example.", True, "First")
-check_exists(master, "member3.example.", True, "First")
+check_exists(master, "member2.example.", False, "First")
+check_exists(master, "member3.example.", False, "First")
master.ctl("zone-reload %s" % zone[2].name)
t.sleep(5)
check_exists(master, "member1.example.", True, "Second")
check_exists(master, "member2.example.", True, "Second")
-check_exists(master, "member3.example.", True, "Second")
+check_exists(master, "member3.example.", False, "Second")
t.end()