const namedb_api_t *storage = kr_cache_storage();
/* Fetch item count */
- namedb_txn_t txn;
- int ret = kr_cache_txn_begin(engine->resolver.cache, &txn, NAMEDB_RDONLY);
+ struct kr_cache_txn txn;
+ int ret = kr_cache_txn_begin(&engine->resolver.cache, &txn, NAMEDB_RDONLY);
if (ret != 0) {
format_error(L, kr_strerror(ret));
lua_error(L);
}
- lua_pushinteger(L, storage->count(&txn));
+ lua_pushinteger(L, storage->count((namedb_txn_t *)&txn));
kr_cache_txn_abort(&txn);
return 1;
}
}
/* Close if already open */
- if (engine->resolver.cache != NULL) {
- kr_cache_close(engine->resolver.cache);
- }
+ kr_cache_close(&engine->resolver.cache);
/* Reopen cache */
kr_cache_storage_set(storage->api);
void *storage_opts = storage->opts_create(conf, cache_size);
- engine->resolver.cache = kr_cache_open(storage_opts, engine->pool);
+ int ret = kr_cache_open(&engine->resolver.cache, storage_opts, engine->pool);
free(storage_opts);
- if (engine->resolver.cache == NULL) {
+ if (ret != 0) {
format_error(L, "can't open cache");
lua_error(L);
}
static int cache_close(lua_State *L)
{
struct engine *engine = engine_luaget(L);
- if (engine->resolver.cache != NULL) {
- struct kr_cache *cache = engine->resolver.cache;
- engine->resolver.cache = NULL;
- kr_cache_close(cache);
- }
-
+ kr_cache_close(&engine->resolver.cache);
lua_pushboolean(L, 1);
return 1;
}
}
network_deinit(&engine->net);
- kr_cache_close(engine->resolver.cache);
- engine->resolver.cache = NULL;
+ kr_cache_close(&engine->resolver.cache);
/* Unload modules. */
for (size_t i = 0; i < engine->modules.len; ++i) {
const namedb_api_t *(*kr_cache_storage)(void) = namedb_lmdb_api;
#define db_api kr_cache_storage()
-namedb_t *kr_cache_open(void *opts, mm_ctx_t *mm)
+int kr_cache_open(struct kr_cache *cache, void *opts, mm_ctx_t *mm)
{
- namedb_t *db = NULL;
- int ret = db_api->init(&db, mm, opts);
+ if (!cache) {
+ return kr_error(EINVAL);
+ }
+ int ret = db_api->init(&cache->db, mm, opts);
if (ret != 0) {
- return NULL;
+ return ret;
}
-
- return db;
+ memset(&cache->stats, 0, sizeof(cache->stats));
+ return kr_ok();
}
-void kr_cache_close(namedb_t *cache)
+void kr_cache_close(struct kr_cache *cache)
{
- if (cache && db_api) {
- db_api->deinit(cache);
+ if (cache && cache->db) {
+ if (db_api) {
+ db_api->deinit(cache->db);
+ }
+ cache->db = NULL;
}
}
-int kr_cache_txn_begin(namedb_t *cache, namedb_txn_t *txn, unsigned flags)
+int kr_cache_txn_begin(struct kr_cache *cache, struct kr_cache_txn *txn, unsigned flags)
{
- if (!cache || !txn) {
+ if (!cache || !cache->db || !txn) {
return kr_error(EINVAL);
}
- return db_api->txn_begin(cache, txn, flags);
+ if (flags & NAMEDB_RDONLY) {
+ cache->stats.txn_read += 1;
+ } else {
+ cache->stats.txn_write += 1;
+ }
+ txn->owner = cache;
+ return db_api->txn_begin(cache->db, (namedb_txn_t *)txn, flags);
}
-int kr_cache_txn_commit(namedb_txn_t *txn)
+int kr_cache_txn_commit(struct kr_cache_txn *txn)
{
if (!txn) {
return kr_error(EINVAL);
}
- int ret = db_api->txn_commit(txn);
+ int ret = db_api->txn_commit((namedb_txn_t *)txn);
if (ret != 0) {
kr_cache_txn_abort(txn);
}
return ret;
}
-void kr_cache_txn_abort(namedb_txn_t *txn)
+void kr_cache_txn_abort(struct kr_cache_txn *txn)
{
if (txn) {
- db_api->txn_abort(txn);
+ db_api->txn_abort((namedb_txn_t *)txn);
}
}
return (struct kr_cache_entry *)val.data;
}
-struct kr_cache_entry *kr_cache_peek(namedb_txn_t *txn, uint8_t tag, const knot_dname_t *name,
+struct kr_cache_entry *kr_cache_peek(struct kr_cache_txn *txn, uint8_t tag, const knot_dname_t *name,
uint16_t type, uint32_t *timestamp)
{
- if (!txn || !tag || !name) {
+ if (!txn || !txn->owner || !tag || !name) {
return NULL;
}
- struct kr_cache_entry *entry = cache_entry(txn, tag, name, type);
+ struct kr_cache_entry *entry = cache_entry((namedb_txn_t *)txn, tag, name, type);
if (!entry) {
+ txn->owner->stats.miss += 1;
return NULL;
}
/* No time constraint */
if (!timestamp) {
+ txn->owner->stats.hit += 1;
return entry;
} else if (*timestamp <= entry->timestamp) {
/* John Connor record cached in the future. */
*timestamp = 0;
+ txn->owner->stats.hit += 1;
return entry;
} else {
/* Check if the record is still valid. */
uint32_t drift = *timestamp - entry->timestamp;
if (drift < entry->ttl) {
*timestamp = drift;
+ txn->owner->stats.hit += 1;
return entry;
}
}
+ txn->owner->stats.miss += 1;
return NULL;
}
memcpy(dst->data, data.data, data.len);
}
-int kr_cache_insert(namedb_txn_t *txn, uint8_t tag, const knot_dname_t *name, uint16_t type,
+int kr_cache_insert(struct kr_cache_txn *txn, uint8_t tag, const knot_dname_t *name, uint16_t type,
struct kr_cache_entry *header, namedb_val_t data)
{
if (!txn || !name || !tag || !header) {
/* LMDB can do late write and avoid copy */
if (db_api == namedb_lmdb_api()) {
- int ret = db_api->insert(txn, &key, &entry, 0);
+ int ret = db_api->insert((namedb_txn_t *)txn, &key, &entry, 0);
if (ret != 0) {
return ret;
}
return kr_error(ENOMEM);
}
entry_write(entry.data, header, data);
- int ret = db_api->insert(txn, &key, &entry, 0);
+ int ret = db_api->insert((namedb_txn_t *)txn, &key, &entry, 0);
free(entry.data);
if (ret != 0) {
return ret;
return kr_ok();
}
-int kr_cache_remove(namedb_txn_t *txn, uint8_t tag, const knot_dname_t *name, uint16_t type)
+int kr_cache_remove(struct kr_cache_txn *txn, uint8_t tag, const knot_dname_t *name, uint16_t type)
{
if (!txn || !tag || !name ) {
return kr_error(EINVAL);
uint8_t keybuf[KEY_SIZE];
size_t key_len = cache_key(keybuf, tag, name, type);
namedb_val_t key = { keybuf, key_len };
- return db_api->del(txn, &key);
+ txn->owner->stats.delete += 1;
+ return db_api->del((namedb_txn_t *)txn, &key);
}
-int kr_cache_clear(namedb_txn_t *txn)
+int kr_cache_clear(struct kr_cache_txn *txn)
{
if (!txn) {
return kr_error(EINVAL);
}
- return db_api->clear(txn);
+ return db_api->clear((namedb_txn_t *)txn);
}
-int kr_cache_peek_rr(namedb_txn_t *txn, knot_rrset_t *rr, uint32_t *timestamp)
+int kr_cache_peek_rr(struct kr_cache_txn *txn, knot_rrset_t *rr, uint32_t *timestamp)
{
if (!txn || !rr || !timestamp) {
return kr_error(EINVAL);
return copy;
}
-int kr_cache_insert_rr(namedb_txn_t *txn, const knot_rrset_t *rr, uint32_t timestamp)
+int kr_cache_insert_rr(struct kr_cache_txn *txn, const knot_rrset_t *rr, uint32_t timestamp)
{
if (!txn || !rr) {
return kr_error(EINVAL);
uint8_t data[];
};
+/**
+ * Cache structure, keeps API, instance and metadata.
+ */
+struct kr_cache
+{
+ namedb_t *db; /**< Storage instance */
+ struct {
+ uint32_t hit; /**< Number of cache hits */
+ uint32_t miss; /**< Number of cache misses */
+ uint32_t insert; /**< Number of insertions */
+ uint32_t delete; /**< Number of deletions */
+ uint32_t txn_read; /**< Number of read transactions */
+ uint32_t txn_write; /**< Number of write transactions */
+ } stats;
+};
+
+/** Cache transaction */
+struct kr_cache_txn {
+ namedb_txn_t txn; /**< Storage transaction */
+ struct kr_cache *owner; /**< Transaction owner */
+};
+
/** Used storage backend for cache (default LMDB) */
extern const namedb_api_t *(*kr_cache_storage)(void);
/**
* Open/create cache with provided storage options.
+ * @param cache cache structure to be initialized
* @param storage_opts Storage-specific options (may be NULL for default)
* @param mm Memory context.
- * @return database instance or NULL
+ * @return 0 or an error code
*/
-namedb_t *kr_cache_open(void *storage_opts, mm_ctx_t *mm);
+int kr_cache_open(struct kr_cache *cache, void *opts, mm_ctx_t *mm);
/**
* Close persistent cache.
* @note This doesn't clear the data, just closes the connection to the database.
* @param cache database instance
*/
-void kr_cache_close(namedb_t *cache);
+void kr_cache_close(struct kr_cache *cache);
/**
* Begin cache transaction (read-only or write).
* @param flags transaction flags (see namedb.h in libknot)
* @return 0 or an errcode
*/
-int kr_cache_txn_begin(namedb_t *cache, namedb_txn_t *txn, unsigned flags);
+int kr_cache_txn_begin(struct kr_cache *cache, struct kr_cache_txn *txn, unsigned flags);
/**
* Commit existing transaction.
* @param txn transaction instance
* @return 0 or an errcode
*/
-int kr_cache_txn_commit(namedb_txn_t *txn);
+int kr_cache_txn_commit(struct kr_cache_txn *txn);
/**
* Abort existing transaction instance.
* @param txn transaction instance
*/
-void kr_cache_txn_abort(namedb_txn_t *txn);
+void kr_cache_txn_abort(struct kr_cache_txn *txn);
/**
* Peek the cache for asset (name, type, tag)
* @param timestamp current time (will be replaced with drift if successful)
* @return cache entry or NULL
*/
-struct kr_cache_entry *kr_cache_peek(namedb_txn_t *txn, uint8_t tag, const knot_dname_t *name,
+struct kr_cache_entry *kr_cache_peek(struct kr_cache_txn *txn, uint8_t tag, const knot_dname_t *name,
uint16_t type, uint32_t *timestamp);
/**
* @param data inserted data
* @return 0 or an errcode
*/
-int kr_cache_insert(namedb_txn_t *txn, uint8_t tag, const knot_dname_t *name, uint16_t type,
+int kr_cache_insert(struct kr_cache_txn *txn, uint8_t tag, const knot_dname_t *name, uint16_t type,
struct kr_cache_entry *header, namedb_val_t data);
/**
* @param type record type
* @return 0 or an errcode
*/
-int kr_cache_remove(namedb_txn_t *txn, uint8_t tag, const knot_dname_t *name, uint16_t type);
+int kr_cache_remove(struct kr_cache_txn *txn, uint8_t tag, const knot_dname_t *name, uint16_t type);
/**
* Clear all items from the cache.
* @param txn transaction instance
* @return 0 or an errcode
*/
-int kr_cache_clear(namedb_txn_t *txn);
+int kr_cache_clear(struct kr_cache_txn *txn);
/**
* Peek the cache for given RRSet (name, type)
* @param timestamp current time (will be replaced with drift if successful)
* @return 0 or an errcode
*/
-int kr_cache_peek_rr(namedb_txn_t *txn, knot_rrset_t *rr, uint32_t *timestamp);
+int kr_cache_peek_rr(struct kr_cache_txn *txn, knot_rrset_t *rr, uint32_t *timestamp);
/**
* Clone read-only RRSet and adjust TTLs.
* @param timestamp current time
* @return 0 or an errcode
*/
-int kr_cache_insert_rr(namedb_txn_t *txn, const knot_rrset_t *rr, uint32_t timestamp);
+int kr_cache_insert_rr(struct kr_cache_txn *txn, const knot_rrset_t *rr, uint32_t timestamp);
}
}
-static int loot_cache_pkt(namedb_txn_t *txn, knot_pkt_t *pkt, const knot_dname_t *qname,
+static int loot_cache_pkt(struct kr_cache_txn *txn, knot_pkt_t *pkt, const knot_dname_t *qname,
uint16_t rrtype, uint8_t tag, uint32_t timestamp)
{
struct kr_cache_entry *entry;
}
/** @internal Try to find a shortcut directly to searched packet, otherwise try to find minimised QNAME. */
-static int loot_cache(namedb_txn_t *txn, knot_pkt_t *pkt, uint8_t tag, struct kr_query *qry)
+static int loot_cache(struct kr_cache_txn *txn, knot_pkt_t *pkt, uint8_t tag, struct kr_query *qry)
{
uint32_t timestamp = qry->timestamp.tv_sec;
const knot_dname_t *qname = qry->sname;
}
/* Prepare read transaction */
- namedb_txn_t txn;
- struct kr_cache *cache = req->ctx->cache;
+ struct kr_cache_txn txn;
+ struct kr_cache *cache = &req->ctx->cache;
if (kr_cache_txn_begin(cache, &txn, NAMEDB_RDONLY) != 0) {
return ctx->state;
}
}
/* Open write transaction and prepare answer */
- namedb_txn_t txn;
- if (kr_cache_txn_begin(req->ctx->cache, &txn, 0) != 0) {
+ struct kr_cache_txn txn;
+ if (kr_cache_txn_begin(&req->ctx->cache, &txn, 0) != 0) {
return ctx->state; /* Couldn't acquire cache, ignore. */
}
const knot_dname_t *qname = knot_pkt_qname(pkt);
return ctx->state;
}
-static int loot_rr(namedb_txn_t *txn, knot_pkt_t *pkt, const knot_dname_t *name,
+static int loot_rr(struct kr_cache_txn *txn, knot_pkt_t *pkt, const knot_dname_t *name,
uint16_t rrclass, uint16_t rrtype, struct kr_query *qry)
{
/* Check if record exists in cache */
return kr_ok();
}
-static int loot_cache_set(namedb_txn_t *txn, knot_pkt_t *pkt, const knot_dname_t *qname,
+static int loot_cache_set(struct kr_cache_txn *txn, knot_pkt_t *pkt, const knot_dname_t *qname,
uint16_t rrclass, uint16_t rrtype, struct kr_query *qry)
{
int ret = loot_rr(txn, pkt, qname, rrclass, rrtype, qry);
}
/** @internal Try to find a shortcut directly to searched record, otherwise try to find minimised QNAME. */
-static int loot_cache(namedb_txn_t *txn, knot_pkt_t *pkt, struct kr_query *qry)
+static int loot_cache(struct kr_cache_txn *txn, knot_pkt_t *pkt, struct kr_query *qry)
{
const knot_dname_t *qname = qry->sname;
uint16_t rrclass = qry->sclass;
return ctx->state;
}
- namedb_txn_t txn;
- struct kr_cache *cache = req->ctx->cache;
+ struct kr_cache_txn txn;
+ struct kr_cache *cache = &req->ctx->cache;
if (kr_cache_txn_begin(cache, &txn, NAMEDB_RDONLY) != 0) {
return ctx->state;
}
}
/** Cache direct answer. */
-static int write_cache_rr(const knot_pktsection_t *section, knot_rrset_t *rr, namedb_txn_t *txn, mm_ctx_t *pool, uint32_t timestamp)
+static int write_cache_rr(const knot_pktsection_t *section, knot_rrset_t *rr, struct kr_cache_txn *txn, mm_ctx_t *pool, uint32_t timestamp)
{
/* Check if already cached. */
knot_rrset_t query_rr;
}
/** Cache direct answer. */
-static int write_cache_answer(knot_pkt_t *pkt, namedb_txn_t *txn, mm_ctx_t *pool, uint32_t timestamp)
+static int write_cache_answer(knot_pkt_t *pkt, struct kr_cache_txn *txn, mm_ctx_t *pool, uint32_t timestamp)
{
knot_rrset_t cache_rr;
knot_rrset_init(&cache_rr, (knot_dname_t *)knot_pkt_qname(pkt), knot_pkt_qtype(pkt), knot_pkt_qclass(pkt));
}
/** Cache stub nameservers. */
-static int write_cache_authority(knot_pkt_t *pkt, namedb_txn_t *txn, mm_ctx_t *pool, uint32_t timestamp)
+static int write_cache_authority(knot_pkt_t *pkt, struct kr_cache_txn *txn, mm_ctx_t *pool, uint32_t timestamp)
{
knot_rrset_t glue_rr = { NULL, 0, 0 };
knot_rrset_t cache_rr = { NULL, 0, 0 };
/* Open write transaction */
mm_ctx_t *pool = rplan->pool;
uint32_t timestamp = query->timestamp.tv_sec;
- struct kr_cache *cache = req->ctx->cache;
- namedb_txn_t txn;
+ struct kr_cache *cache = &req->ctx->cache;
+ struct kr_cache_txn txn;
if (kr_cache_txn_begin(cache, &txn, 0) != 0) {
return ctx->state; /* Couldn't acquire cache, ignore. */
}
}
/* Find closest zone cut for this query. */
- namedb_txn_t txn;
- if (kr_cache_txn_begin(rplan->context->cache, &txn, NAMEDB_RDONLY) != 0) {
+ struct kr_cache_txn txn;
+ if (kr_cache_txn_begin(&rplan->context->cache, &txn, NAMEDB_RDONLY) != 0) {
kr_zonecut_set_sbelt(&qry->zone_cut);
} else {
kr_zonecut_find_cached(&qry->zone_cut, &txn, qry->timestamp.tv_sec);
#include "lib/generic/array.h"
#include "lib/rplan.h"
#include "lib/module.h"
+#include "lib/cache.h"
/**
* @file resolve.h
struct kr_context
{
mm_ctx_t *pool;
- struct kr_cache *cache;
+ struct kr_cache cache;
module_array_t *modules;
uint32_t options;
};
}
/** Fetch best NS for zone cut. */
-static int fetch_ns(struct kr_zonecut *cut, const knot_dname_t *name, namedb_txn_t *txn, uint32_t timestamp)
+static int fetch_ns(struct kr_zonecut *cut, const knot_dname_t *name, struct kr_cache_txn *txn, uint32_t timestamp)
{
uint32_t drift = timestamp;
knot_rrset_t cached_rr;
return kr_ok();
}
-int kr_zonecut_find_cached(struct kr_zonecut *cut, namedb_txn_t *txn, uint32_t timestamp)
+int kr_zonecut_find_cached(struct kr_zonecut *cut, struct kr_cache_txn *txn, uint32_t timestamp)
{
if (cut == NULL) {
return kr_error(EINVAL);
update_cut_name(cut, name);
return kr_ok();
}
+ name = knot_wire_next_label(name, NULL);
/* Subtract label from QNAME. */
if (name[0] == '\0') {
break;
}
- name = knot_wire_next_label(name, NULL);
}
/* Name server not found, start with SBELT. */
* @param timestamp transaction timestamp
* @return 0 or error code
*/
-int kr_zonecut_find_cached(struct kr_zonecut *cut, namedb_txn_t *txn, uint32_t timestamp);
+int kr_zonecut_find_cached(struct kr_zonecut *cut, struct kr_cache_txn *txn, uint32_t timestamp);
namedb_t *cache = engine->resolver.cache;
/* Open read transaction */
- namedb_txn_t txn;
+ struct kr_cache_txn txn;
int ret = kr_cache_txn_begin(cache, &txn, NAMEDB_RDONLY);
if (ret != 0) {
return NULL;
struct engine *engine = env;
const namedb_api_t *storage = kr_cache_storage();
- namedb_txn_t txn;
- int ret = kr_cache_txn_begin(engine->resolver.cache, &txn, 0);
+ struct kr_cache_txn txn;
+ int ret = kr_cache_txn_begin(&engine->resolver.cache, &txn, 0);
if (ret != 0) {
return NULL;
}
/* Iterate cache and find expired records. */
int pruned = 0;
uint32_t now = time(NULL);
- namedb_iter_t *it = storage->iter_begin(&txn, 0);
+ namedb_iter_t *it = storage->iter_begin((namedb_txn_t *)&txn, 0);
while (it) {
/* Fetch RR from cache */
namedb_val_t key, val;
/* Prune expired records. */
struct kr_cache_entry *entry = val.data;
if (is_expired(entry, now - entry->timestamp)) {
- storage->del(&txn, &key);
+ storage->del((namedb_txn_t *)&txn, &key);
pruned += 1;
}
it = storage->iter_next(it);
{
struct engine *engine = env;
- namedb_txn_t txn;
- int ret = kr_cache_txn_begin(engine->resolver.cache, &txn, 0);
+ struct kr_cache_txn txn;
+ int ret = kr_cache_txn_begin(&engine->resolver.cache, &txn, 0);
if (ret != 0) {
return NULL;
}
#include <time.h>
mm_ctx_t global_mm;
-namedb_txn_t global_txn;
+struct kr_cache_txn global_txn;
knot_rrset_t global_rr;
const char *global_env;
struct kr_cache_entry global_fake_ce;
return err;
}
+/* Test cache open */
+static void test_open(void **state)
+{
+ static struct kr_cache cache;
+ struct namedb_lmdb_opts opts;
+ memset(&opts, 0, sizeof(opts));
+ opts.path = global_env;
+ opts.mapsize = CACHE_SIZE;
+ int ret = kr_cache_open(&cache, &opts, &global_mm);
+ assert_int_equal(ret, 0);
+ *state = &cache;
+}
+
+/* Test cache teardown. */
+static void test_close(void **state)
+{
+ kr_cache_close(*state);
+ *state = NULL;
+}
+
+
+/* Open transaction */
+static struct kr_cache_txn *test_txn_write(void **state)
+{
+ assert_non_null(*state);
+ assert_int_equal(kr_cache_txn_begin(*state, &global_txn, 0), KNOT_EOK);
+ return &global_txn;
+}
+
+/* Open transaction */
+static struct kr_cache_txn *test_txn_rdonly(void **state)
+{
+ assert_non_null(*state);
+ assert_int_equal(kr_cache_txn_begin(*state, &global_txn, NAMEDB_RDONLY), 0);
+ return &global_txn;
+}
/* Fake api */
static const namedb_api_t *namedb_lmdb_api_fake(void)
return &api_fake;
}
+static void test_failures(void **state)
+{
+ const namedb_api_t *(*kr_cache_storage_saved)(void);
+ void *ret_cache_peek;
+ int ret_commit;
+ int ret_open;
+ knot_dname_t dname[] = "";
+
+ /* Get read transaction */
+ struct kr_cache_txn *txn = test_txn_rdonly(state);
+ /* save original api */
+ kr_cache_storage_saved = kr_cache_storage;
+ /* fake to simulate failures or constant success */
+ kr_cache_storage_set(namedb_lmdb_api_fake);
+
+ /* call kr_cache_peek() with no time constraint */
+ ret_cache_peek = kr_cache_peek(txn, KR_CACHE_USER, dname, KNOT_RRTYPE_TSIG, 0);
+ ret_open = kr_cache_open(NULL, NULL, NULL);
+ ret_commit = kr_cache_txn_commit(txn);
+
+ /* restore */
+ kr_cache_storage_set(kr_cache_storage_saved);
+ assert_int_equal(ret_cache_peek, &global_fake_ce);
+ assert_int_not_equal(ret_open, KNOT_EOK);
+ assert_int_not_equal(ret_commit, KNOT_EOK);
+}
/* Test invalid parameters and some api failures. */
static void test_invalid(void **state)
{
- const namedb_api_t *(*kr_cache_storage_saved)(void);
- void *ret_open, *ret_cache_peek;
- int ret_commit;
- uint32_t timestamp = CACHE_TIME;
knot_dname_t dname[] = "";
+ uint32_t timestamp = CACHE_TIME;
assert_int_not_equal(kr_cache_txn_begin(NULL, &global_txn, 0), 0);
- assert_int_not_equal(kr_cache_txn_begin(&global_env, NULL, 0), 0);
+ assert_int_not_equal(kr_cache_txn_begin(*state, NULL, 0), 0);
assert_int_not_equal(kr_cache_txn_commit(NULL), 0);
assert_null(kr_cache_peek(NULL, KR_CACHE_USER, dname, KNOT_RRTYPE_TSIG, ×tamp));
assert_null(kr_cache_peek(&global_txn, 0, dname, KNOT_RRTYPE_TSIG, ×tamp));
assert_int_not_equal(kr_cache_remove(&global_txn, KR_CACHE_RR, NULL, 0), 0);
assert_int_not_equal(kr_cache_remove(NULL, 0, NULL, 0), 0);
assert_int_not_equal(kr_cache_clear(NULL), 0);
-
- /* save original api */
- kr_cache_storage_saved = kr_cache_storage;
- /* fake to simulate failures or constant success */
- kr_cache_storage_set(namedb_lmdb_api_fake);
-
- /* call kr_cache_peek() with no time constraint */
- ret_cache_peek = kr_cache_peek(&global_txn, KR_CACHE_USER, dname, KNOT_RRTYPE_TSIG, 0);
- ret_open = kr_cache_open(NULL, NULL);
- ret_commit = kr_cache_txn_commit(&global_txn);
-
- /* restore */
- kr_cache_storage_set(kr_cache_storage_saved);
- assert_int_equal(ret_cache_peek, &global_fake_ce);
- assert_null(ret_open);
- assert_int_not_equal(ret_commit, KNOT_EOK);
-}
-
-/* Test cache open */
-static void test_open(void **state)
-{
- struct namedb_lmdb_opts opts;
- memset(&opts, 0, sizeof(opts));
- opts.path = global_env;
- opts.mapsize = CACHE_SIZE;
- *state = kr_cache_open(&opts, &global_mm);
- assert_non_null(*state);
-}
-
-/* Test cache teardown. */
-static void test_close(void **state)
-{
- kr_cache_close(*state);
- *state = NULL;
-}
-
-
-/* Open transaction */
-static namedb_txn_t *test_txn_write(void **state)
-{
- assert_non_null(*state);
- assert_int_equal(kr_cache_txn_begin(*state, &global_txn, 0), KNOT_EOK);
- return &global_txn;
-}
-
-/* Open transaction */
-static namedb_txn_t *test_txn_rdonly(void **state)
-{
- assert_non_null(*state);
- assert_int_equal(kr_cache_txn_begin(*state, &global_txn, NAMEDB_RDONLY), 0);
- return &global_txn;
}
/* Test cache write */
knot_dname_t dname[] = "";
test_random_rr(&global_rr, CACHE_TTL);
- namedb_txn_t *txn = test_txn_write(state);
+ struct kr_cache_txn *txn = test_txn_write(state);
int ret = kr_cache_insert_rr(txn, &global_rr, CACHE_TIME);
if (ret == KNOT_EOK) {
ret = kr_cache_txn_commit(txn);
knot_rrset_t cache_rr;
knot_rrset_init(&cache_rr, global_rr.owner, global_rr.type, global_rr.rclass);
- namedb_txn_t *txn = test_txn_rdonly(state);
+ struct kr_cache_txn *txn = test_txn_rdonly(state);
for (uint32_t timestamp = CACHE_TIME; timestamp < CACHE_TIME + CACHE_TTL; ++timestamp) {
uint32_t drift = timestamp;
knot_rrset_t cache_rr;
knot_rrset_init(&cache_rr, global_rr.owner, global_rr.type, global_rr.rclass);
- namedb_txn_t *txn = test_txn_rdonly(state);
+ struct kr_cache_txn *txn = test_txn_rdonly(state);
int ret = kr_cache_peek_rr(txn, &cache_rr, ×tamp);
assert_int_equal(ret, KNOT_ENOENT);
kr_cache_txn_abort(txn);
knot_rrset_t cache_rr;
knot_rrset_init(&cache_rr, global_rr.owner, global_rr.type, global_rr.rclass);
- namedb_txn_t *txn = test_txn_write(state);
+ struct kr_cache_txn *txn = test_txn_write(state);
int ret = kr_cache_remove(txn, KR_CACHE_RR, cache_rr.owner, cache_rr.type);
assert_int_equal(ret, KNOT_EOK);
ret = kr_cache_peek_rr(txn, &cache_rr, ×tamp);
/* Test cache fill */
static void test_fill(void **state)
{
- namedb_txn_t *txn = test_txn_write(state);
+ struct kr_cache_txn *txn = test_txn_write(state);
/* Fill with random values. */
int ret = KNOT_EOK;
/* Test cache clear */
static void test_clear(void **state)
{
- namedb_txn_t *txn = test_txn_write(state);
+ struct kr_cache_txn *txn = test_txn_write(state);
int preempt_ret = kr_cache_clear(txn);
int commit_ret = kr_cache_txn_commit(txn);
assert_int_equal(preempt_ret, KNOT_EOK);
test_mm_ctx_init(&global_mm);
global_env = test_tmpdir_create();
- const UnitTest tests[] = {
- /* Invalid input */
+ /* Invalid input */
+ const UnitTest tests_bad[] = {
+ group_test_setup(test_open),
unit_test(test_invalid),
+ unit_test(test_failures),
+ group_test_teardown(test_close)
+ };
+
+ const UnitTest tests[] = {
/* Cache persistence */
group_test_setup(test_open),
unit_test(test_insert),
group_test_teardown(test_close)
};
- int ret = run_group_tests(tests);
+ int ret = run_group_tests(tests_bad);
+ if (ret == 0) {
+ ret = run_group_tests(tests);
+ }
/* Cleanup */
test_tmpdir_remove(global_env);
-
return ret;
}
opts.path = global_tmpdir;
opts.mapsize = 100 * 4096;
kr_cache_storage_set(namedb_lmdb_api);
- global_context.cache = kr_cache_open(&opts, &global_mm);
- assert(global_context.cache);
+ int ret = kr_cache_open(&global_context.cache, &opts, &global_mm);
+ assert(ret == 0);
/* No configuration parsing support yet. */
if (strstr(config, "query-minimization: on") == NULL) {