* 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);
};
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))
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 = {
cdb_read_leq, cdb_read_less,
cdb_usage_percent, cdb_get_maxsize,
cdb_check_health,
+ cdb_it_first, cdb_it_next,
};
return &api;
}