]> git.ipfire.org Git - thirdparty/knot-dns.git/commitdiff
zone/purge: refactoring: perform as zone event instead by main thread...
authorLibor Peltan <libor.peltan@nic.cz>
Thu, 6 Nov 2025 13:09:35 +0000 (14:09 +0100)
committerDaniel Salzman <daniel.salzman@nic.cz>
Thu, 6 Nov 2025 18:27:55 +0000 (19:27 +0100)
...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
src/knot/Makefile.inc
src/knot/ctl/commands.c
src/knot/events/events.c
src/knot/events/events.h
src/knot/events/handlers.h
src/knot/events/handlers/expire.c
src/knot/events/handlers/purge.c [new file with mode: 0644]
src/knot/events/replan.c
src/knot/zone/zone.c
src/knot/zone/zone.h

index 437b96ed2307a22ad9dce6ab913ab5b97fca6c02..4f617a7eb431a8d20ed70f0d92e5be6081500fbc 100644 (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
index d32f7df02c512417c448a67630e63965ebd5758e..b325ea4fb0f2ae35c9a2b8be668294cc85b85a42 100644 (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         \
index 433ead8fbec42f44d457673163687c8c0734eace..392f0664a0303e49417b9a19d71d712fb9f6e018 100644 (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)
index 860f588bf8187038e5f5bccbfc60086a130f241e..b401c040611ed13efb34edaf4875869067e4b0b8 100644 (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:
index 1759acbd96bf95c98488690e5e6f76a89785e3b8..49bba840f7a5223c4cccfdff4347fc02de261167 100644 (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,
index 7f6e979de0026b5e25fb747b7b2f83aa50d1a33e..7cc96c7c70b9bbd85ca30a1b2a88fa010f8ef453 100644 (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. */
index c49cd8f9c09a33755a314ec875dc935640381825..5a45a757be029ce6b7ab9b7050d0a987c89dd2b0 100644 (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;
 }
diff --git a/src/knot/events/handlers/purge.c b/src/knot/events/handlers/purge.c
new file mode 100644 (file)
index 0000000..deb7e43
--- /dev/null
@@ -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);
+}
index 703811252ffd8c3439019ab4ce8421d7c2632792..e219d438333b034c2c3cc9838a853e82cd6909bc 100644 (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,
index 1d2169c17363419fd98b68dfac8511bbb7eae0a3..8d28ec4b7fde428ecda019a42414c8ecac87b232 100644 (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;
index 0a8cf528de5a05feef0f1fdd284c2a22f3b51105..52088de85e4789347a1327e8ffce1216220346dd 100644 (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.
  *