From 605ddcc9dc86dd7650e395475e78b19aaffe7a47 Mon Sep 17 00:00:00 2001 From: Libor Peltan Date: Thu, 6 Nov 2025 14:09:35 +0100 Subject: [PATCH] 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 --- Knot.files | 1 + src/knot/Makefile.inc | 1 + src/knot/ctl/commands.c | 20 +++---------------- src/knot/events/events.c | 2 ++ src/knot/events/events.h | 1 + src/knot/events/handlers.h | 2 ++ src/knot/events/handlers/expire.c | 32 +------------------------------ src/knot/events/handlers/purge.c | 17 ++++++++++++++++ src/knot/events/replan.c | 1 + src/knot/zone/zone.c | 25 ++++++++++++++++++++++++ src/knot/zone/zone.h | 30 +++++++++++++++++++++-------- 11 files changed, 76 insertions(+), 56 deletions(-) create mode 100644 src/knot/events/handlers/purge.c diff --git a/Knot.files b/Knot.files index 437b96ed23..4f617a7eb4 100644 --- a/Knot.files +++ b/Knot.files @@ -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 diff --git a/src/knot/Makefile.inc b/src/knot/Makefile.inc index d32f7df02c..b325ea4fb0 100644 --- a/src/knot/Makefile.inc +++ b/src/knot/Makefile.inc @@ -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 \ diff --git a/src/knot/ctl/commands.c b/src/knot/ctl/commands.c index 433ead8fbe..392f0664a0 100644 --- a/src/knot/ctl/commands.c +++ b/src/knot/ctl/commands.c @@ -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) diff --git a/src/knot/events/events.c b/src/knot/events/events.c index 860f588bf8..b401c04061 100644 --- a/src/knot/events/events.c +++ b/src/knot/events/events.c @@ -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: diff --git a/src/knot/events/events.h b/src/knot/events/events.h index 1759acbd96..49bba840f7 100644 --- a/src/knot/events/events.h +++ b/src/knot/events/events.h @@ -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, diff --git a/src/knot/events/handlers.h b/src/knot/events/handlers.h index 7f6e979de0..7cc96c7c70 100644 --- a/src/knot/events/handlers.h +++ b/src/knot/events/handlers.h @@ -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. */ diff --git a/src/knot/events/handlers/expire.c b/src/knot/events/handlers/expire.c index c49cd8f9c0..5a45a757be 100644 --- a/src/knot/events/handlers/expire.c +++ b/src/knot/events/handlers/expire.c @@ -3,41 +3,11 @@ * For more information, see */ -#include -#include - -#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; } diff --git a/src/knot/events/handlers/purge.c b/src/knot/events/handlers/purge.c new file mode 100644 index 0000000000..deb7e437bc --- /dev/null +++ b/src/knot/events/handlers/purge.c @@ -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 + */ + +#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); +} diff --git a/src/knot/events/replan.c b/src/knot/events/replan.c index 703811252f..e219d43833 100644 --- a/src/knot/events/replan.c +++ b/src/knot/events/replan.c @@ -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, diff --git a/src/knot/zone/zone.c b/src/knot/zone/zone.c index 1d2169c173..8d28ec4b7f 100644 --- a/src/knot/zone/zone.c +++ b/src/knot/zone/zone.c @@ -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; diff --git a/src/knot/zone/zone.h b/src/knot/zone/zone.h index 0a8cf528de..52088de85e 100644 --- a/src/knot/zone/zone.h +++ b/src/knot/zone/zone.h @@ -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. * -- 2.47.3