Commit fb9c5daf authored by Marek Vavruša's avatar Marek Vavruša

cache: wrapped namedb_t+txn into structure, counters

this prepares cache/txn structures to hold API as well, so we can get
rid of the global api
parent 7b171e58
......@@ -312,14 +312,14 @@ static int cache_count(lua_State *L)
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;
}
......@@ -366,16 +366,14 @@ static int cache_open(lua_State *L)
}
/* 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);
}
......@@ -396,12 +394,7 @@ static int cache_open(lua_State *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;
}
......
......@@ -237,8 +237,7 @@ void engine_deinit(struct engine *engine)
}
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) {
......
......@@ -40,50 +40,61 @@
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);
}
}
......@@ -113,34 +124,39 @@ static struct kr_cache_entry *cache_entry(namedb_txn_t *txn, uint8_t tag, const
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;
}
......@@ -151,7 +167,7 @@ static void entry_write(struct kr_cache_entry *dst, struct kr_cache_entry *heade
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) {
......@@ -166,7 +182,7 @@ int kr_cache_insert(namedb_txn_t *txn, uint8_t tag, const knot_dname_t *name, ui
/* 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;
}
......@@ -178,7 +194,7 @@ int kr_cache_insert(namedb_txn_t *txn, uint8_t tag, const knot_dname_t *name, ui
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;
......@@ -188,7 +204,7 @@ int kr_cache_insert(namedb_txn_t *txn, uint8_t tag, const knot_dname_t *name, ui
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);
......@@ -197,19 +213,20 @@ int kr_cache_remove(namedb_txn_t *txn, uint8_t tag, const knot_dname_t *name, ui
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);
......@@ -258,7 +275,7 @@ knot_rrset_t kr_cache_materialize(const knot_rrset_t *src, uint32_t drift, mm_ct
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);
......
......@@ -38,6 +38,28 @@ struct kr_cache_entry
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);
......@@ -49,18 +71,19 @@ static inline void kr_cache_storage_set(const namedb_api_t *(*api)(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).
......@@ -70,20 +93,20 @@ void kr_cache_close(namedb_t *cache);
* @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)
......@@ -95,7 +118,7 @@ void kr_cache_txn_abort(namedb_txn_t *txn);
* @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);
/**
......@@ -108,7 +131,7 @@ struct kr_cache_entry *kr_cache_peek(namedb_txn_t *txn, uint8_t tag, const knot_
* @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);
/**
......@@ -119,14 +142,14 @@ int kr_cache_insert(namedb_txn_t *txn, uint8_t tag, const knot_dname_t *name, ui
* @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)
......@@ -136,7 +159,7 @@ int kr_cache_clear(namedb_txn_t *txn);
* @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.
......@@ -154,4 +177,4 @@ knot_rrset_t kr_cache_materialize(const knot_rrset_t *src, uint32_t drift, mm_ct
* @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);
......@@ -54,7 +54,7 @@ static void adjust_ttl(knot_rrset_t *rr, uint32_t drift)
}
}
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;
......@@ -91,7 +91,7 @@ static int loot_cache_pkt(namedb_txn_t *txn, knot_pkt_t *pkt, const knot_dname_t
}
/** @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;
......@@ -122,8 +122,8 @@ static int peek(knot_layer_t *ctx, knot_pkt_t *pkt)
}
/* 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;
}
......@@ -196,8 +196,8 @@ static int stash(knot_layer_t *ctx)
}
/* 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);
......
......@@ -32,7 +32,7 @@ static int begin(knot_layer_t *ctx, void *module_param)
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 */
......@@ -63,7 +63,7 @@ static int loot_rr(namedb_txn_t *txn, knot_pkt_t *pkt, const knot_dname_t *name,
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);
......@@ -74,7 +74,7 @@ static int loot_cache_set(namedb_txn_t *txn, knot_pkt_t *pkt, const knot_dname_t
}
/** @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;
......@@ -101,8 +101,8 @@ static int peek(knot_layer_t *ctx, knot_pkt_t *pkt)
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;
}
......@@ -152,7 +152,7 @@ static int merge_in_section(knot_rrset_t *cache_rr, const knot_pktsection_t *sec
}
/** 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;
......@@ -192,7 +192,7 @@ static int write_cache_rr(const knot_pktsection_t *section, knot_rrset_t *rr, na
}
/** 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));
......@@ -202,7 +202,7 @@ static int write_cache_answer(knot_pkt_t *pkt, namedb_txn_t *txn, mm_ctx_t *pool
}
/** 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 };
......@@ -252,8 +252,8 @@ static int stash(knot_layer_t *ctx, knot_pkt_t *pkt)
/* 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. */
}
......
......@@ -290,8 +290,8 @@ int kr_resolve_query(struct kr_request *request, const knot_dname_t *qname, uint
}
/* 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);
......
......@@ -23,6 +23,7 @@
#include "lib/generic/array.h"
#include "lib/rplan.h"
#include "lib/module.h"
#include "lib/cache.h"
/**
* @file resolve.h
......@@ -98,7 +99,7 @@ typedef array_t(struct kr_module *) module_array_t;
struct kr_context
{
mm_ctx_t *pool;
struct kr_cache *cache;
struct kr_cache cache;
module_array_t *modules;
uint32_t options;
};
......
......@@ -189,7 +189,7 @@ int kr_zonecut_set_sbelt(struct kr_zonecut *cut)
}
/** 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;
......@@ -209,7 +209,7 @@ static int fetch_ns(struct kr_zonecut *cut, const knot_dname_t *name, namedb_txn
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);
......@@ -222,11 +222,11 @@ int kr_zonecut_find_cached(struct kr_zonecut *cut, namedb_txn_t *txn, uint32_t t
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. */
......
......@@ -104,4 +104,4 @@ int kr_zonecut_set_sbelt(struct kr_zonecut *cut);
* @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);
......@@ -283,7 +283,7 @@ Here's an example how a module can expose its property:
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;
......
......@@ -53,8 +53,8 @@ static char* prune(void *env, struct kr_module *module, const char *args)
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;
}
......@@ -62,7 +62,7 @@ static char* prune(void *env, struct kr_module *module, const char *args)
/* 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;
......@@ -73,7 +73,7 @@ static char* prune(void *env, struct kr_module *module, const char *args)
/* 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);
......@@ -101,8 +101,8 @@ static char* clear(void *env, struct kr_module *module, const char *args)
{
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;
}
......
......@@ -24,7 +24,7 @@
#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;
......@@ -81,6 +81,42 @@ static int test_ins(namedb_txn_t *txn, namedb_val_t *key, namedb_val_t *val, uns
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)
......@@ -96,18 +132,41 @@ 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, &timestamp));
assert_null(kr_cache_peek(&global_txn, 0, dname, KNOT_RRTYPE_TSIG, &timestamp));
......@@ -128,57 +187,6 @@ static void test_invalid(void **state)
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;