zone/purge: refactoring: perform as zone event instead by main thread...

...but only in case of knotc zone-purge; catalog-induced purges
are still performed by main thread while zone events all frozen
for all zones
This commit is contained in:
Libor Peltan 2025-11-06 14:09:35 +01:00 committed by Daniel Salzman
parent c1eb463e45
commit 605ddcc9dc
11 changed files with 76 additions and 56 deletions

View file

@ -268,6 +268,7 @@ src/knot/events/handlers/flush.c
src/knot/events/handlers/freeze_thaw.c
src/knot/events/handlers/load.c
src/knot/events/handlers/notify.c
src/knot/events/handlers/purge.c
src/knot/events/handlers/refresh.c
src/knot/events/handlers/update.c
src/knot/events/handlers/validate.c

View file

@ -94,6 +94,7 @@ libknotd_la_SOURCES = \
knot/events/handlers/freeze_thaw.c \
knot/events/handlers/load.c \
knot/events/handlers/notify.c \
knot/events/handlers/purge.c \
knot/events/handlers/refresh.c \
knot/events/handlers/update.c \
knot/events/handlers/validate.c \

View file

@ -1811,31 +1811,17 @@ static int orphans_purge(ctl_args_t *args)
static int zone_purge(zone_t *zone, ctl_args_t *args)
{
if (MATCH_OR_FILTER(args, CTL_FILTER_PURGE_EXPIRE)) {
// Abort possible editing transaction.
int ret = zone_txn_abort(zone, args);
if (ret != KNOT_EOK && ret != KNOT_TXN_ENOTEXISTS) {
log_zone_error(zone->name,
"failed to abort pending transaction (%s)",
knot_strerror(ret));
return ret;
}
// Expire the zone.
// No ret, KNOT_EOK is the only return value from event_expire().
(void)zone_events_schedule_blocking(zone, ZONE_EVENT_EXPIRE, true);
}
const purge_flag_t params =
MATCH_OR_FILTER(args, CTL_FILTER_PURGE_TIMERS) * PURGE_ZONE_TIMERS |
MATCH_OR_FILTER(args, CTL_FILTER_PURGE_ZONEFILE) * PURGE_ZONE_ZONEFILE |
MATCH_OR_FILTER(args, CTL_FILTER_PURGE_JOURNAL) * PURGE_ZONE_JOURNAL |
MATCH_OR_FILTER(args, CTL_FILTER_PURGE_KASPDB) * PURGE_ZONE_KASPDB |
MATCH_OR_FILTER(args, CTL_FILTER_PURGE_CATALOG) * PURGE_ZONE_CATALOG |
MATCH_OR_FILTER(args, CTL_FILTER_PURGE_EXPIRE) * PURGE_ZONE_EXPIRE |
PURGE_ZONE_NOSYNC; // Purge even zonefiles with disabled syncing.
// Purge the requested zone data.
return selective_zone_purge(conf(), zone, params);
zone_set_flag(zone, (zone_flag_t)params);
return schedule_trigger(zone, args, ZONE_EVENT_PURGE, true);
}
int ctl_dump_ctr(stats_dump_params_t *params, stats_dump_ctx_t *ctx)

View file

@ -31,6 +31,7 @@ static const event_info_t EVENT_INFO[] = {
{ ZONE_EVENT_REFRESH, event_refresh, "refresh" },
{ ZONE_EVENT_UPDATE, event_update, "update" },
{ ZONE_EVENT_EXPIRE, event_expire, "expiration" },
{ ZONE_EVENT_PURGE, event_purge, "purge" },
{ ZONE_EVENT_FLUSH, event_flush, "flush" },
{ ZONE_EVENT_BACKUP, event_backup, "backup/restore" },
{ ZONE_EVENT_NOTIFY, event_notify, "notify" },
@ -68,6 +69,7 @@ bool ufreeze_applies(zone_event_type_t type)
case ZONE_EVENT_LOAD:
case ZONE_EVENT_REFRESH:
case ZONE_EVENT_UPDATE:
case ZONE_EVENT_PURGE:
case ZONE_EVENT_FLUSH:
case ZONE_EVENT_DNSSEC:
case ZONE_EVENT_DS_CHECK:

View file

@ -23,6 +23,7 @@ typedef enum zone_event_type {
ZONE_EVENT_REFRESH,
ZONE_EVENT_UPDATE,
ZONE_EVENT_EXPIRE,
ZONE_EVENT_PURGE,
ZONE_EVENT_FLUSH,
ZONE_EVENT_BACKUP,
ZONE_EVENT_NOTIFY,

View file

@ -17,6 +17,8 @@ int event_refresh(conf_t *conf, zone_t *zone);
int event_update(conf_t *conf, zone_t *zone);
/*! \brief Empties in-memory zone contents. */
int event_expire(conf_t *conf, zone_t *zone);
/*! \brief Expires the zone and purges metadata based on zone->flags. */
int event_purge(conf_t *conf, zone_t *zone);
/*! \brief Flushes zone contents into text file. */
int event_flush(conf_t *conf, zone_t *zone);
/*! \brief Backs up zone contents, metadata, keys, etc to a directory. */

View file

@ -3,41 +3,11 @@
* For more information, see <https://www.knot-dns.cz/>
*/
#include <assert.h>
#include <urcu.h>
#include "knot/common/log.h"
#include "knot/conf/conf.h"
#include "knot/events/handlers.h"
#include "knot/events/replan.h"
#include "knot/zone/contents.h"
#include "knot/zone/zone.h"
int event_expire(conf_t *conf, zone_t *zone)
{
assert(zone);
zone_contents_t *expired = zone_switch_contents(zone, NULL);
log_zone_info(zone->name, "zone expired");
synchronize_rcu();
pthread_mutex_lock(&zone->cu_lock);
assert(zone->control_update == NULL || !(zone->control_update->flags & UPDATE_WFEV));
zone_control_clear(zone);
pthread_mutex_unlock(&zone->cu_lock);
knot_sem_wait(&zone->cow_lock);
zone_contents_deep_free(expired);
knot_sem_post(&zone->cow_lock);
zone->zonefile.exists = false;
zone_set_last_master(zone, NULL);
zone->timers.next_expire = time(NULL);
zone->timers.next_refresh = zone->timers.next_expire;
replan_from_timers(conf, zone);
zone_perform_expire(conf, zone);
return KNOT_EOK;
}

View file

@ -0,0 +1,17 @@
/* Copyright (C) CZ.NIC, z.s.p.o. and contributors
* SPDX-License-Identifier: GPL-2.0-or-later
* For more information, see <https://www.knot-dns.cz/>
*/
#include "knot/zone/zone.h"
int event_purge(conf_t *conf, zone_t *zone)
{
purge_flag_t what = (purge_flag_t)zone_get_flag(zone, (zone_flag_t)PURGE_ZONE_FLAGS, true);
if (what & PURGE_ZONE_EXPIRE) {
zone_perform_expire(conf, zone);
}
return selective_zone_purge(conf, zone, what);
}

View file

@ -49,6 +49,7 @@ static void replan_from_zone(zone_t *zone, zone_t *old_zone)
const zone_event_type_t types[] = {
ZONE_EVENT_REFRESH,
ZONE_EVENT_PURGE,
ZONE_EVENT_FLUSH,
ZONE_EVENT_BACKUP,
ZONE_EVENT_NOTIFY,

View file

@ -359,6 +359,31 @@ int selective_zone_purge(conf_t *conf, zone_t *zone, purge_flag_t params)
return KNOT_EOK;
}
void zone_perform_expire(conf_t *conf, zone_t *zone)
{
zone_contents_t *expired = zone_switch_contents(zone, NULL);
log_zone_info(zone->name, "zone expired");
synchronize_rcu();
pthread_mutex_lock(&zone->cu_lock);
assert(zone->control_update == NULL || !(zone->control_update->flags & UPDATE_WFEV));
zone_control_clear(zone);
pthread_mutex_unlock(&zone->cu_lock);
knot_sem_wait(&zone->cow_lock);
zone_contents_deep_free(expired);
knot_sem_post(&zone->cow_lock);
zone->zonefile.exists = false;
zone_set_last_master(zone, NULL);
zone->timers.next_expire = time(NULL);
zone->timers.next_refresh = zone->timers.next_expire;
replan_from_timers(conf, zone);
}
knot_lmdb_db_t *zone_journaldb(const zone_t *zone)
{
return &zone->server->journaldb;

View file

@ -40,6 +40,9 @@ typedef enum {
ZONE_USER_FLUSH = 1 << 8, /*!< User-triggered flush. */
ZONE_LAST_SIGN_OK = 1 << 9, /*!< Last full-sign event finished OK. */
ZONE_PREF_MASTER_2X = 1 << 10, /*!< Preferred master has been overwritten at least once. */
ZONE_FLAG_MAX = 1 << 19, /*!< Maximal usable flag below purge_flag_t. */
ZONE_FLAG_TYPESIZE = 1 << 30, /*!< Enforces the compiler to use 32-bit variable for this enum. */
} zone_flag_t;
/*!
@ -50,16 +53,19 @@ knot_dynarray_declare(notifailed_rmt, notifailed_rmt_hash, DYNARRAY_VISIBILITY_N
/*!
* \brief Zone purging parameter flags.
*
* \warning Note they are and must be mutually exclusive with zone_flag_t so that they can be stored in zone->flags.
*/
typedef enum {
PURGE_ZONE_BEST = 1 << 0, /*!< Best effort -- continue on failures. */
PURGE_ZONE_LOG = 1 << 1, /*!< Log a purged zone even if requested less. */
PURGE_ZONE_NOSYNC = 1 << 2, /*!< Remove even zone files with disabled syncing. */
PURGE_ZONE_TIMERS = 1 << 3, /*!< Purge the zone timers. */
PURGE_ZONE_ZONEFILE = 1 << 4, /*!< Purge the zone file. */
PURGE_ZONE_JOURNAL = 1 << 5, /*!< Purge the zone journal. */
PURGE_ZONE_KASPDB = 1 << 6, /*!< Purge KASP DB. */
PURGE_ZONE_CATALOG = 1 << 7, /*!< Purge the catalog. */
PURGE_ZONE_BEST = 1 << 20, /*!< Best effort -- continue on failures. */
PURGE_ZONE_LOG = 1 << 21, /*!< Log a purged zone even if requested less. */
PURGE_ZONE_NOSYNC = 1 << 22, /*!< Remove even zone files with disabled syncing. */
PURGE_ZONE_TIMERS = 1 << 23, /*!< Purge the zone timers. */
PURGE_ZONE_ZONEFILE = 1 << 24, /*!< Purge the zone file. */
PURGE_ZONE_JOURNAL = 1 << 25, /*!< Purge the zone journal. */
PURGE_ZONE_KASPDB = 1 << 26, /*!< Purge KASP DB. */
PURGE_ZONE_CATALOG = 1 << 27, /*!< Purge the catalog. */
PURGE_ZONE_EXPIRE = 1 << 28, /*!< Expire the zone, free contents. */
} purge_flag_t;
/*!< All data. */
@ -69,6 +75,9 @@ typedef enum {
/*!< Standard purge (respect C_ZONEFILE_SYNC param). */
#define PURGE_ZONE_ALL (PURGE_ZONE_DATA | PURGE_ZONE_BEST | PURGE_ZONE_LOG)
/*!< All purge-related flags. */
#define PURGE_ZONE_FLAGS (PURGE_ZONE_ALL | PURGE_ZONE_NOSYNC | PURGE_ZONE_EXPIRE)
/*!
* \brief Structure for holding DNS zone.
*/
@ -187,6 +196,11 @@ void zone_reset(conf_t *conf, zone_t *zone);
*/
int selective_zone_purge(conf_t *conf, zone_t *zone, purge_flag_t params);
/*!
* \brief Expire zone, NULL and free zone->contents, clear CTL txn, expire timers, replan events.
*/
void zone_perform_expire(conf_t *conf, zone_t *zone);
/*!
* \brief Clears possible control update transaction.
*