]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
lib/cache/cdb_*: add API for iteration with MDB_DUPSORT
authorVladimír Čunát <vladimir.cunat@nic.cz>
Fri, 1 Sep 2023 08:35:09 +0000 (10:35 +0200)
committerVladimír Čunát <vladimir.cunat@nic.cz>
Thu, 5 Oct 2023 07:09:53 +0000 (09:09 +0200)
lib/cache/cdb_api.h
lib/cache/cdb_lmdb.c

index 41130b621cd436ffc31274ab89943bfbf46b696f..bce8740f7701c0beb951190f7da6999762c27e78 100644 (file)
@@ -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);
 };
index 96cc2cd0ec07750e472d0fef26330ea0d251f1a7..5351cd737b6e8722d57658cadaab27673dc92754 100644 (file)
@@ -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;
 }