diff --git a/Knot.files b/Knot.files
index 437b96ed2..4f617a7eb 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 d32f7df02..b325ea4fb 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 433ead8fb..392f0664a 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 860f588bf..b401c0406 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 1759acbd9..49bba840f 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 7f6e979de..7cc96c7c7 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 c49cd8f9c..5a45a757b 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 000000000..deb7e437b
--- /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 703811252..e219d4383 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 1d2169c17..8d28ec4b7 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 0a8cf528d..52088de85 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.
*