From: Vladimír Čunát Date: Fri, 1 Sep 2023 08:35:09 +0000 (+0200) Subject: lib/cache/cdb_*: add API for iteration with MDB_DUPSORT X-Git-Tag: v6.0.4~1^2~5 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c336c8bb285a54f6a382cc471c68c746f49c8a45;p=thirdparty%2Fknot-resolver.git lib/cache/cdb_*: add API for iteration with MDB_DUPSORT --- diff --git a/lib/cache/cdb_api.h b/lib/cache/cdb_api.h index 41130b621..bce8740f7 100644 --- a/lib/cache/cdb_api.h +++ b/lib/cache/cdb_api.h @@ -106,4 +106,15 @@ struct kr_cdb_api { * and reopens it if it isn't; it errors out if the file doesn't exist anymore. * \return 0 if OK, 1 if reopened OK, < 0 kr_error */ int (*check_health)(kr_cdb_pt db, struct kr_cdb_stats *stat); + + + /** Start iterating; return the first *val with *key. + * + * This only makes sense if !is_cache. + * TODO: it only works inside RO transactions for now. + */ + int (*it_first)(kr_cdb_pt db, struct kr_cdb_stats *stat, + const knot_db_val_t *key, knot_db_val_t *val); + /** Advance to the next *val with the same key. */ + int (*it_next)(kr_cdb_pt db, struct kr_cdb_stats *stat, knot_db_val_t *val); }; diff --git a/lib/cache/cdb_lmdb.c b/lib/cache/cdb_lmdb.c index 96cc2cd0e..5351cd737 100644 --- a/lib/cache/cdb_lmdb.c +++ b/lib/cache/cdb_lmdb.c @@ -244,7 +244,8 @@ static int cdb_commit(kr_cdb_pt db, struct kr_cdb_stats *stats, bool accept) return ret; } -/** Obtain a read-only cursor (and a read-only transaction). */ +/** Obtain a read-only cursor (and a read-only transaction). + * TODO: allow RW transaction (for ruledb iterator) */ static int txn_curs_get(struct lmdb_env *env, MDB_cursor **curs, struct kr_cdb_stats *stats) { if (kr_fails_assert(env && curs)) @@ -907,6 +908,47 @@ knot_db_t *kr_cdb_pt2knot_db_t(kr_cdb_pt db) return libknot_db; } +static int cdb_it_first(kr_cdb_pt db, struct kr_cdb_stats *stats, + const knot_db_val_t *key, knot_db_val_t *val) +{ + if (kr_fails_assert(db && key && key->data && val)) + return kr_error(EINVAL); + struct lmdb_env *env = db2env(db); + if (kr_fails_assert(!env->is_cache)) + return kr_error(EINVAL); + + MDB_cursor *curs = NULL; + int ret = txn_curs_get(env, &curs, stats); + if (ret) return ret; + + MDB_val key2_m = val_knot2mdb(*key); + MDB_val val2_m = { 0, NULL }; + ret = mdb_cursor_get(curs, &key2_m, &val2_m, MDB_SET); + if (ret) return lmdb_error(env, ret); + ret = mdb_cursor_get(curs, &key2_m, &val2_m, MDB_FIRST_DUP); + if (ret) return lmdb_error(env, ret); + *val = val_mdb2knot(val2_m); + return kr_ok(); +} +static int cdb_it_next(kr_cdb_pt db, struct kr_cdb_stats *stats, knot_db_val_t *val) +{ + if (kr_fails_assert(db && val)) + return kr_error(EINVAL); + struct lmdb_env *env = db2env(db); + if (kr_fails_assert(!env->is_cache && env->txn.ro_curs_active)) + return kr_error(EINVAL); + + MDB_cursor *curs = NULL; + int ret = txn_curs_get(env, &curs, stats); + if (ret) return ret; + MDB_val val2_m = { 0, NULL }; + ret = mdb_cursor_get(curs, NULL, &val2_m, MDB_NEXT_DUP); + if (ret) return lmdb_error(env, ret); + *val = val_mdb2knot(val2_m); + return kr_ok(); +} + + const struct kr_cdb_api *kr_cdb_lmdb(void) { static const struct kr_cdb_api api = { @@ -917,6 +959,7 @@ const struct kr_cdb_api *kr_cdb_lmdb(void) cdb_read_leq, cdb_read_less, cdb_usage_percent, cdb_get_maxsize, cdb_check_health, + cdb_it_first, cdb_it_next, }; return &api; }