Commit cd71653b authored by Daniel Salzman's avatar Daniel Salzman
Browse files

Merge branch 'cat_impr' into 'master'

Reload changed catalog members only (reuse otherwise)

See merge request !1499
parents b27b901d 3fbdc932
Pipeline #107142 passed with stages
in 9 minutes and 31 seconds
......@@ -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 \
......
......@@ -30,8 +30,7 @@ Patch2: 02-revert-AC_PROG_CC.patch
BuildRequires: autoconf
BuildRequires: automake
BuildRequires: libtool
BuildRequires: make
BuildRequires: gcc
BuildRequires: devtoolset-7
BuildRequires: pkgconfig(liburcu)
BuildRequires: pkgconfig(gnutls) >= 3.3
BuildRequires: pkgconfig(libedit)
......@@ -156,6 +155,7 @@ CFLAGS="%{optflags} -DNDEBUG -Wno-unused"
autoreconf -if
export CC="/opt/rh/devtoolset-7/root/usr/bin/gcc"
%configure \
--sysconfdir=/etc \
--localstatedir=/var/lib \
......
/* 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();
}
......
......@@ -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);
......
......@@ -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();
......
......@@ -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"
......@@ -48,6 +50,17 @@ typedef enum {
ServerRunning = 1 << 0, /*!< Server is running. */
} 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.
*/
......@@ -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);
......@@ -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();
}
......
......@@ -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)
......
/* 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.
......
......@@ -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) {
......
......@@ -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()
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment