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));
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);
} 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;
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);
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) {
*
* \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,
*
* \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.
} 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,