double usage_percent;
};
+/*! Pointer to a cache structure.
+ *
+ * This struct is opaque and never defined; the purpose is to get better
+ * type safety than with void *.
+ */
+typedef struct kr_cdb *kr_cdb_pt;
/*! Cache database API.
* This is a simplified version of generic DB API from libknot,
/* Context operations */
- int (*open)(knot_db_t **db, struct kr_cdb_stats *stat, struct kr_cdb_opts *opts, knot_mm_t *mm);
- void (*close)(knot_db_t *db, struct kr_cdb_stats *stat);
- int (*count)(knot_db_t *db, struct kr_cdb_stats *stat);
- int (*clear)(knot_db_t *db, struct kr_cdb_stats *stat);
+ int (*open)(kr_cdb_pt *db, struct kr_cdb_stats *stat, struct kr_cdb_opts *opts, knot_mm_t *mm);
+ void (*close)(kr_cdb_pt db, struct kr_cdb_stats *stat);
+ int (*count)(kr_cdb_pt db, struct kr_cdb_stats *stat);
+ int (*clear)(kr_cdb_pt db, struct kr_cdb_stats *stat);
/** Run after a row of operations to release transaction/lock if needed. */
- int (*commit)(knot_db_t *db, struct kr_cdb_stats *stat);
+ int (*commit)(kr_cdb_pt db, struct kr_cdb_stats *stat);
/* Data access */
- int (*read)(knot_db_t *db, struct kr_cdb_stats *stat,
+ int (*read)(kr_cdb_pt db, struct kr_cdb_stats *stat,
const knot_db_val_t *key, knot_db_val_t *val, int maxcount);
- int (*write)(knot_db_t *db, struct kr_cdb_stats *stat, const knot_db_val_t *key,
+ int (*write)(kr_cdb_pt db, struct kr_cdb_stats *stat, const knot_db_val_t *key,
knot_db_val_t *val, int maxcount);
/** Remove maxcount keys.
* \returns the number of succesfully removed keys or the first error code
* It returns on first error, but ENOENT is not considered an error. */
- int (*remove)(knot_db_t *db, struct kr_cdb_stats *stat,
+ int (*remove)(kr_cdb_pt db, struct kr_cdb_stats *stat,
knot_db_val_t keys[], int maxcount);
/* Specialised operations */
/** Find key-value pairs that are prefixed by the given key, limited by maxcount.
* \return the number of pairs or negative error. */
- int (*match)(knot_db_t *db, struct kr_cdb_stats *stat,
+ int (*match)(kr_cdb_pt db, struct kr_cdb_stats *stat,
knot_db_val_t *key, knot_db_val_t keyval[][2], int maxcount);
/** Less-or-equal search (lexicographic ordering).
* On successful return, key->data and val->data point to DB-owned data.
* return: 0 for equality, > 0 for less, < 0 kr_error */
- int (*read_leq)(knot_db_t *db, struct kr_cdb_stats *stat,
+ int (*read_leq)(kr_cdb_pt db, struct kr_cdb_stats *stat,
knot_db_val_t *key, knot_db_val_t *val);
double (*usage_percent)(knot_db_t *db);
/** Return the current cache size limit in bytes; could be cached by check_health(). */
- size_t (*get_maxsize)(knot_db_t *db);
+ size_t (*get_maxsize)(kr_cdb_pt db);
/** Perform maintenance.
* In LMDB case it checks whether data.mdb is still the same
* 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)(knot_db_t *db, struct kr_cdb_stats *stat);
+ int (*check_health)(kr_cdb_pt db, struct kr_cdb_stats *stat);
};
knot_mm_t *pool;
};
+/** Type-safe conversion helper.
+ *
+ * We keep lmdb_env as a separate type from kr_db_pt, as different implementation of API
+ * would need to define the contents differently.
+ */
+static inline struct lmdb_env * db2env(kr_cdb_pt db)
+{
+ return (struct lmdb_env *)db;
+}
+static inline kr_cdb_pt env2db(struct lmdb_env *env)
+{
+ return (kr_cdb_pt)env;
+}
-static int cdb_commit(knot_db_t *db, struct kr_cdb_stats *stats);
+static int cdb_commit(kr_cdb_pt db, struct kr_cdb_stats *stats);
/** @brief Convert LMDB error code. */
static int lmdb_error(int error)
* It's much lighter than reopen_env(). */
static int refresh_mapsize(struct lmdb_env *env)
{
- int ret = cdb_commit(env, NULL);
+ int ret = cdb_commit(env2db(env), NULL);
if (!ret) ret = lmdb_error(mdb_env_set_mapsize(env->env, 0));
if (ret) return ret;
return kr_ok();
}
-static int cdb_commit(knot_db_t *db, struct kr_cdb_stats *stats)
+static int cdb_commit(kr_cdb_pt db, struct kr_cdb_stats *stats)
{
- struct lmdb_env *env = db;
+ struct lmdb_env *env = db2env(db);
int ret = kr_ok();
if (env->txn.rw) {
if (stats) stats->commit++;
}
/* Only in a read-only txn; TODO: it's a bit messy/coupled */
if (env->txn.rw) {
- int ret = cdb_commit(env, stats);
+ int ret = cdb_commit(env2db(env), stats);
if (ret) return ret;
}
MDB_txn *txn = NULL;
/* Get rid of any transactions. */
txn_free_ro(env);
- cdb_commit(env, stats);
+ cdb_commit(env2db(env), stats);
mdb_env_sync(env->env, 1);
stats->close++;
return kr_error(ret);
}
-static int cdb_init(knot_db_t **db, struct kr_cdb_stats *stats,
+static int cdb_init(kr_cdb_pt *db, struct kr_cdb_stats *stats,
struct kr_cdb_opts *opts, knot_mm_t *pool)
{
if (!db || !stats || !opts) {
return ret;
}
- *db = env;
+ *db = env2db(env);
return 0;
}
-static void cdb_deinit(knot_db_t *db, struct kr_cdb_stats *stats)
+static void cdb_deinit(kr_cdb_pt db, struct kr_cdb_stats *stats)
{
- struct lmdb_env *env = db;
- cdb_close_env(env, stats);
- free(env);
+ cdb_close_env(db2env(db), stats);
+ free(db);
}
-static int cdb_count(knot_db_t *db, struct kr_cdb_stats *stats)
+static int cdb_count(kr_cdb_pt db, struct kr_cdb_stats *stats)
{
- struct lmdb_env *env = db;
+ struct lmdb_env *env = db2env(db);
MDB_txn *txn = NULL;
int ret = txn_get(env, &txn, true);
if (ret != 0) {
return cdb_open_env(env, path_copy, mapsize, stats);
}
-static int cdb_check_health(knot_db_t *db, struct kr_cdb_stats *stats)
+static int cdb_check_health(kr_cdb_pt db, struct kr_cdb_stats *stats)
{
- struct lmdb_env *env = db;
+ struct lmdb_env *env = db2env(db);
struct stat st;
if (stat(env->mdb_data_path, &st)) {
return err;
}
-static int cdb_clear(knot_db_t *db, struct kr_cdb_stats *stats)
+static int cdb_clear(kr_cdb_pt db, struct kr_cdb_stats *stats)
{
- struct lmdb_env *env = db;
+ struct lmdb_env *env = db2env(db);
stats->clear++;
/* First try mdb_drop() to clear the DB; this may fail with ENOSPC. */
{
* though it's best for them to reopen soon. */
/* We are about to switch to a different file, so end all txns, to be sure. */
- txn_free_ro(db);
+ txn_free_ro(env);
(void) cdb_commit(db, stats);
const char *path = NULL;
return ret;
}
-static int cdb_readv(knot_db_t *db, struct kr_cdb_stats *stats,
+static int cdb_readv(kr_cdb_pt db, struct kr_cdb_stats *stats,
const knot_db_val_t *key, knot_db_val_t *val, int maxcount)
{
- struct lmdb_env *env = db;
+ struct lmdb_env *env = db2env(db);
MDB_txn *txn = NULL;
int ret = txn_get(env, &txn, true);
if (ret) {
return kr_ok();
}
-static int cdb_writev(knot_db_t *db, struct kr_cdb_stats *stats,
+static int cdb_writev(kr_cdb_pt db, struct kr_cdb_stats *stats,
const knot_db_val_t *key, knot_db_val_t *val, int maxcount)
{
- struct lmdb_env *env = db;
+ struct lmdb_env *env = db2env(db);
MDB_txn *txn = NULL;
int ret = txn_get(env, &txn, false);
return ret;
}
-static int cdb_remove(knot_db_t *db, struct kr_cdb_stats *stats,
+static int cdb_remove(kr_cdb_pt db, struct kr_cdb_stats *stats,
knot_db_val_t keys[], int maxcount)
{
- struct lmdb_env *env = db;
+ struct lmdb_env *env = db2env(db);
MDB_txn *txn = NULL;
int ret = txn_get(env, &txn, false);
int deleted = 0;
return ret < 0 ? ret : deleted;
}
-static int cdb_match(knot_db_t *db, struct kr_cdb_stats *stats,
+static int cdb_match(kr_cdb_pt db, struct kr_cdb_stats *stats,
knot_db_val_t *key, knot_db_val_t keyval[][2], int maxcount)
{
- struct lmdb_env *env = db;
+ struct lmdb_env *env = db2env(db);
MDB_txn *txn = NULL;
int ret = txn_get(env, &txn, true);
if (ret != 0) {
}
-static int cdb_read_leq(knot_db_t *env, struct kr_cdb_stats *stats,
+static int cdb_read_leq(kr_cdb_pt db, struct kr_cdb_stats *stats,
knot_db_val_t *key, knot_db_val_t *val)
{
- assert(env && key && key->data && val);
+ assert(db && key && key->data && val);
+ struct lmdb_env *env = db2env(db);
MDB_cursor *curs = NULL;
int ret = txn_curs_get(env, &curs, stats);
if (ret) return ret;
return db_usage;
}
-static size_t cdb_get_maxsize(knot_db_t *db)
+static size_t cdb_get_maxsize(kr_cdb_pt db)
{
- struct lmdb_env *env = db;
- return env->mapsize;
+ return db2env(db)->mapsize;
}
/** Conversion between knot and lmdb structs. */
-knot_db_t *knot_db_t_kres2libknot(const knot_db_t * db)
+knot_db_t *kr_cdb_pt2knot_db_t(kr_cdb_pt db)
{
/* this is struct lmdb_env as in resolver/cdb_lmdb.c */
- const struct lmdb_env *kres_db = db;
+ const struct lmdb_env *kres_db = db2env(db);
struct libknot_lmdb_env *libknot_db = malloc(sizeof(*libknot_db));
if (libknot_db != NULL) {
libknot_db->shared = false;