From fb9c5daf6e40b4356855b675496dade82ca5a9ec Mon Sep 17 00:00:00 2001 From: =?utf8?q?Marek=20Vavru=C5=A1a?= Date: Wed, 27 May 2015 19:25:04 +0200 Subject: [PATCH] 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 --- daemon/bindings.c | 21 ++--- daemon/engine.c | 3 +- lib/cache.c | 73 +++++++++++------- lib/cache.h | 47 ++++++++--- lib/layer/pktcache.c | 12 +-- lib/layer/rrcache.c | 20 ++--- lib/resolve.c | 4 +- lib/resolve.h | 3 +- lib/zonecut.c | 6 +- lib/zonecut.h | 2 +- modules/README.rst | 2 +- modules/cachectl/cachectl.c | 12 +-- tests/test_cache.c | 150 ++++++++++++++++++++---------------- tests/test_integration.c | 4 +- 14 files changed, 204 insertions(+), 155 deletions(-) diff --git a/daemon/bindings.c b/daemon/bindings.c index 28a826b98..77e558a61 100644 --- a/daemon/bindings.c +++ b/daemon/bindings.c @@ -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; } diff --git a/daemon/engine.c b/daemon/engine.c index b31cac666..5b70184a3 100644 --- a/daemon/engine.c +++ b/daemon/engine.c @@ -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) { diff --git a/lib/cache.c b/lib/cache.c index 67d4634bd..475755552 100644 --- a/lib/cache.c +++ b/lib/cache.c @@ -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); diff --git a/lib/cache.h b/lib/cache.h index 647169caa..55c2eb027 100644 --- a/lib/cache.h +++ b/lib/cache.h @@ -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); diff --git a/lib/layer/pktcache.c b/lib/layer/pktcache.c index 15891294a..e45ac1351 100644 --- a/lib/layer/pktcache.c +++ b/lib/layer/pktcache.c @@ -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); diff --git a/lib/layer/rrcache.c b/lib/layer/rrcache.c index 7722320bd..b907760b0 100644 --- a/lib/layer/rrcache.c +++ b/lib/layer/rrcache.c @@ -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. */ } diff --git a/lib/resolve.c b/lib/resolve.c index 9f0425381..ec50f7c12 100644 --- a/lib/resolve.c +++ b/lib/resolve.c @@ -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); diff --git a/lib/resolve.h b/lib/resolve.h index 70f72de6b..1b17d8b23 100644 --- a/lib/resolve.h +++ b/lib/resolve.h @@ -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; }; diff --git a/lib/zonecut.c b/lib/zonecut.c index fef8061ee..51ede9b15 100644 --- a/lib/zonecut.c +++ b/lib/zonecut.c @@ -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. */ diff --git a/lib/zonecut.h b/lib/zonecut.h index fd708c1b0..0c4670699 100644 --- a/lib/zonecut.h +++ b/lib/zonecut.h @@ -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); diff --git a/modules/README.rst b/modules/README.rst index a39f7a593..5dad0fc38 100644 --- a/modules/README.rst +++ b/modules/README.rst @@ -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; diff --git a/modules/cachectl/cachectl.c b/modules/cachectl/cachectl.c index d0e438e4d..39cf66110 100644 --- a/modules/cachectl/cachectl.c +++ b/modules/cachectl/cachectl.c @@ -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; } diff --git a/tests/test_cache.c b/tests/test_cache.c index 7e5e73cfa..a4125d834 100644 --- a/tests/test_cache.c +++ b/tests/test_cache.c @@ -24,7 +24,7 @@ #include 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, ×tamp)); assert_null(kr_cache_peek(&global_txn, 0, dname, KNOT_RRTYPE_TSIG, ×tamp)); @@ -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; -} - - -/* 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 */ @@ -189,7 +197,7 @@ static void test_insert(void **state) 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); @@ -225,7 +233,7 @@ static void test_query(void **state) 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; @@ -245,7 +253,7 @@ static void test_query_aged(void **state) 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); @@ -258,7 +266,7 @@ static void test_remove(void **state) 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); @@ -269,7 +277,7 @@ static void test_remove(void **state) /* 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; @@ -301,7 +309,7 @@ static void test_fill(void **state) /* 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); @@ -314,9 +322,15 @@ int main(void) 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), @@ -331,10 +345,12 @@ int main(void) 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; } diff --git a/tests/test_integration.c b/tests/test_integration.c index 2d65d720a..357129c8e 100644 --- a/tests/test_integration.c +++ b/tests/test_integration.c @@ -72,8 +72,8 @@ static PyObject* init(PyObject* self, PyObject* args) 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) { -- 2.47.3