]> git.ipfire.org Git - thirdparty/knot-dns.git/commitdiff
kaspdb: trash/garbage collector function for regular waste management of the "trash...
authorDavid Vašek <david.vasek@nic.cz>
Tue, 31 Mar 2026 09:25:57 +0000 (11:25 +0200)
committerDavid Vašek <david.vasek@nic.cz>
Fri, 26 Jun 2026 11:11:12 +0000 (13:11 +0200)
src/knot/dnssec/kasp/kasp_db.c
src/knot/dnssec/kasp/kasp_db.h
src/utils/keymgr/main.c

index 376da8a87148b8a433b0bfcf705ed29ba03e6528..2867071426cb8d54353e7a5511e9d237c206d923 100644 (file)
@@ -260,6 +260,18 @@ static bool trash_deserialize(const MDB_val *val, key_params_t *params)
        return false;
 }
 
+static bool trash_expired(const MDB_val *val, void *data)
+{
+       knot_time_t now = *(knot_time_t *)data;
+
+       if (val->mv_size < sizeof(knot_time_t)) {
+               return false;
+       }
+
+       knot_time_t timestamp = (knot_time_t)knot_wire_read_u64(val->mv_data);
+       return (timestamp < now && timestamp != 0);
+}
+
 static key_params_t *txn2params(knot_lmdb_txn_t *txn)
 {
        key_params_t *p = calloc(1, sizeof(*p));
@@ -546,7 +558,8 @@ int kasp_db_delete_all(knot_lmdb_db_t *db, const knot_dname_t *zone)
        return txn.ret;
 }
 
-int kasp_db_delete_trash(knot_lmdb_db_t *db, const knot_dname_t *zone_name, char *key_id)
+int kasp_db_delete_trash(knot_lmdb_db_t *db, const knot_dname_t *zone_name, char *key_id,
+                         bool (for_delete)(const MDB_val *, void *), void *cb_data)
 {
        assert(db);
 
@@ -575,8 +588,14 @@ int kasp_db_delete_trash(knot_lmdb_db_t *db, const knot_dname_t *zone_name, char
        } else {
                // Remove all trash keys belonging to the zone, or all trash keys.
                bool failed = false;
+               bool fatal = false;
                MDB_val prefix = make_key_str(KASPDBKEY_TRASH, NULL, NULL);
                knot_lmdb_foreach(&txn, &prefix) {
+                       // For background garbage collector.
+                       if (for_delete != NULL && !for_delete(&txn.cur_val, cb_data)) {
+                               continue;
+                       }
+
                        uint8_t kclass;
                        char *id;
                        knot_dname_t *dname;
@@ -589,25 +608,29 @@ int kasp_db_delete_trash(knot_lmdb_db_t *db, const knot_dname_t *zone_name, char
                                        continue;
                                }
 
+                               // For background garbage collection, log errors as debug.
                                ret = kdnssec_delete_from_keystores(keystores, id, dname, true,
-                                                                   false);
+                                                                   for_delete != NULL ? true : false);
                                ret = (ret == KNOT_ENOENT) ? KNOT_EOK : ret;
                                if (ret != KNOT_EOK) {
                                        // Note: it isn't sure that there still is a key to delete.
                                        failed = true;
+                                       ret = KNOT_EOK;
                                        continue;
                                }
                        } else {
                                // Corrupted or incompatible KASP DB? Stop all other deletes, but
                                // commit deletes of KASP records related to already removed keys.
                                ret = KNOT_EMALF;
+                               fatal = true;
                                break;
                        }
 
                        knot_lmdb_del_cur(&txn);
                }
                free(prefix.mv_data);
-               ret = (failed) ? KNOT_ERROR : ret;
+               // For background garbage collection, suppress trivial 'failed' errors.
+               ret = (for_delete != NULL) ? ret : ((failed && !fatal) ? KNOT_ERROR : ret);
        }
 
        knot_lmdb_commit(&txn);
@@ -615,6 +638,13 @@ int kasp_db_delete_trash(knot_lmdb_db_t *db, const knot_dname_t *zone_name, char
        return (ret == KNOT_EOK) ? txn.ret : ret;
 }
 
+int kasp_db_trash_gc(knot_lmdb_db_t *db)
+{
+       assert(db);
+       knot_time_t now = knot_time();
+       return kasp_db_delete_trash(db, NULL, NULL, trash_expired, &now);
+}
+
 int kasp_db_sweep(knot_lmdb_db_t *db, sweep_cb keep_zone, void *cb_data)
 {
        if (knot_lmdb_exists(db) == KNOT_ENODB) {
index 94ff17488980d603c127eb367c8531383c2b6f4b..9d98c7242ec505bac81c3daa3cd7e5f554683004 100644 (file)
@@ -93,7 +93,9 @@ int kasp_db_delete_all(knot_lmdb_db_t *db, const knot_dname_t *zone_name);
  *
  * \param db            KASP db
  * \param zone_name     zone to remove from
- * \param key_id        ID of the key to be removed
+ * \param key_id        ID of the key to be removed, or NULL for any
+ * \param for_delete    optional filtering callback, or NULL for no filtering
+ * \param cb_data       data passed to callback function, or NULL
  *
  * \note  If key_id is set, remove only that key,
  * \note  if zone_name is set, remove all keys belonging to that zone,
@@ -101,7 +103,17 @@ int kasp_db_delete_all(knot_lmdb_db_t *db, const knot_dname_t *zone_name);
  *
  * \return KNOT_E*
  */
-int kasp_db_delete_trash(knot_lmdb_db_t *db, const knot_dname_t *zone_name, char *key_id);
+int kasp_db_delete_trash(knot_lmdb_db_t *db, const knot_dname_t *zone_name, char *key_id,
+                         bool (for_delete)(const MDB_val *, void *), void *cb_data);
+
+/*!
+ * \brief Remove all expired trash keys from KASP DB (trash/garbage collector).
+ *
+ * \param db            KASP database.
+ *
+ * \return KNOT_E*
+ */
+int kasp_db_trash_gc(knot_lmdb_db_t *db);
 
 /*!
  * \brief Selectively delete zones from the database.
index 3ca89bc5bd1c6c6180ae958883556f6b1b960652..d98df1e2834c2fc5546c84f155eb47ecf6e9e69e 100644 (file)
@@ -295,7 +295,8 @@ static int key_command(int argc, char *argv[], int opt_ind, knot_lmdb_db_t *kasp
        } else if (same_command(argv[1], "trash-discard", false)) {
                CHECK_MISSING_ARG("Key ID not specified");
                bool all = !strncmp(argv[2], "-", 2) || !strncmp(argv[2], "--", 3);
-               ret = kasp_db_delete_trash(kaspdb, zone_name, all ? NULL : argv[2]);
+               ret = kasp_db_delete_trash(kaspdb, zone_name, all ? NULL : argv[2],
+                                          NULL, NULL);
        } else if (same_command(argv[1], "pregenerate", false)) {
                CHECK_MISSING_ARG("Timestamp to not specified");
                ret = keymgr_pregenerate_zsks(&kctx, argc > 3 ? argv[2] : NULL,