From: David VaĊĦek Date: Tue, 31 Mar 2026 09:25:57 +0000 (+0200) Subject: kaspdb: trash/garbage collector function for regular waste management of the "trash... X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=520edc8f1bbb946fc052fd7994710e4cbca1812f;p=thirdparty%2Fknot-dns.git kaspdb: trash/garbage collector function for regular waste management of the "trash bin" --- diff --git a/src/knot/dnssec/kasp/kasp_db.c b/src/knot/dnssec/kasp/kasp_db.c index 376da8a871..2867071426 100644 --- a/src/knot/dnssec/kasp/kasp_db.c +++ b/src/knot/dnssec/kasp/kasp_db.c @@ -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) { diff --git a/src/knot/dnssec/kasp/kasp_db.h b/src/knot/dnssec/kasp/kasp_db.h index 94ff174889..9d98c7242e 100644 --- a/src/knot/dnssec/kasp/kasp_db.h +++ b/src/knot/dnssec/kasp/kasp_db.h @@ -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. diff --git a/src/utils/keymgr/main.c b/src/utils/keymgr/main.c index 3ca89bc5bd..d98df1e283 100644 --- a/src/utils/keymgr/main.c +++ b/src/utils/keymgr/main.c @@ -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,