diff --git a/daemon/bindings.c b/daemon/bindings.c index d5c20d7f52495a2f004eae967093399a6e042e4b..9221d27c1baea92d1dd3f36250b8ce27a1439587 100644 --- a/daemon/bindings.c +++ b/daemon/bindings.c @@ -328,7 +328,8 @@ static int cache_count(lua_State *L) lua_error(L); } - lua_pushinteger(L, storage->count(&txn.t)); + /* First key is a version counter, omit it. */ + lua_pushinteger(L, storage->count(&txn.t) - 1); kr_cache_txn_abort(&txn); return 1; } diff --git a/lib/cache.c b/lib/cache.c index f75cd76fd00fe08ed14d66081fb8431c2751fb24..5fd6ec1154e2d7ecd68b23e14dd106982998848c 100644 --- a/lib/cache.c +++ b/lib/cache.c @@ -29,22 +29,58 @@ #include "lib/defines.h" #include "lib/utils.h" +/* Cache version */ +#define KEY_VERSION "V\x01" /* Key size */ -#define KEY_HSIZE (1 + sizeof(uint16_t)) +#define KEY_HSIZE (sizeof(uint8_t) + sizeof(uint16_t)) #define KEY_SIZE (KEY_HSIZE + KNOT_DNAME_MAXLEN) -#define txn_api(txn) (txn->owner->api) +#define txn_api(txn) ((txn)->owner->api) + +/** @internal Check cache internal data version. Clear if it doesn't match. */ +static void assert_right_version(struct kr_cache *cache) +{ + /* Check cache ABI version */ + struct kr_cache_txn txn; + int ret = kr_cache_txn_begin(cache, &txn, 0); + if (ret != 0) { + return; /* N/A, doesn't work. */ + } + namedb_val_t key = { KEY_VERSION, 2 }; + namedb_val_t val = { NULL, 0 }; + ret = txn_api(&txn)->find(&txn.t, &key, &val, 0); + if (ret == 0) { /* Version is OK */ + kr_cache_txn_abort(&txn); + return; + } + /* Recreate cache and write version key */ + ret = txn_api(&txn)->count(&txn.t); + if (ret > 0) { /* Non-empty cache, purge it. */ + log_info("[cache] version mismatch, clearing\n"); + kr_cache_clear(&txn); + kr_cache_txn_commit(&txn); + ret = kr_cache_txn_begin(cache, &txn, 0); + } + /* Either purged or empty. */ + if (ret == 0) { + txn_api(&txn)->insert(&txn.t, &key, &val, 0); + kr_cache_txn_commit(&txn); + } +} int kr_cache_open(struct kr_cache *cache, const namedb_api_t *api, void *opts, mm_ctx_t *mm) { if (!cache) { return kr_error(EINVAL); } + /* Open cache */ cache->api = (api == NULL) ? namedb_lmdb_api() : api; int ret = cache->api->init(&cache->db, mm, opts); if (ret != 0) { return ret; } memset(&cache->stats, 0, sizeof(cache->stats)); + /* Check cache ABI version */ + assert_right_version(cache); return kr_ok(); } @@ -99,20 +135,23 @@ void kr_cache_txn_abort(struct kr_cache_txn *txn) } } -/** @internal Composed key as { u8 tag, u8[1-255] name, u16 type } */ +/** + * @internal Composed key as { u8 tag, u8[1-255] name, u16 type } + * The name is lowercased and label order is reverted for easy prefix search. + * e.g. '\x03nic\x02cz\x00' is saved as '\0x00cz\x00nic\x00' + */ static size_t cache_key(uint8_t *buf, uint8_t tag, const knot_dname_t *name, uint16_t rrtype) { - /* Write tag + type */ - buf[0] = tag; - memcpy(buf + 1, &rrtype, sizeof(uint16_t)); - buf += KEY_HSIZE; - /* Write lowercased name */ - int ret = knot_dname_to_wire(buf, name, KNOT_DNAME_MAXLEN); - if (ret <= 0) { + /* Convert to lookup format */ + int ret = knot_dname_lf(buf, name, NULL); + if (ret != 0) { return 0; } - knot_dname_to_lower(buf); - return KEY_HSIZE + ret; + /* Write tag + type */ + uint8_t name_len = buf[0]; + buf[0] = tag; + memcpy(buf + sizeof(uint8_t) + name_len, &rrtype, sizeof(uint16_t)); + return name_len + KEY_HSIZE; } static struct kr_cache_entry *cache_entry(struct kr_cache_txn *txn, uint8_t tag, const knot_dname_t *name, uint16_t type) diff --git a/lib/cache.h b/lib/cache.h index 4408a6bfa496855fa47607fb83d8fb16d725cb51..79852f011a6c637870ec228c47b6036c4b45ec65 100644 --- a/lib/cache.h +++ b/lib/cache.h @@ -36,6 +36,7 @@ struct kr_cache_entry uint32_t timestamp; uint32_t ttl; uint16_t count; + uint16_t rank; uint8_t data[]; }; diff --git a/lib/layer/rrcache.c b/lib/layer/rrcache.c index dde29829e0ee322034acedaaea7a38b038d448fb..4c9598f2256eec962f2c7560842addedc7bf7e2a 100644 --- a/lib/layer/rrcache.c +++ b/lib/layer/rrcache.c @@ -47,7 +47,7 @@ static int loot_rr(struct kr_cache_txn *txn, knot_pkt_t *pkt, const knot_dname_t if (fetch_rrsig) { ret = kr_cache_peek_rrsig(txn, &cache_rr, &drift); } else { - ret = kr_cache_peek_rr(txn, &cache_rr, &drift); + ret = kr_cache_peek_rr(txn, &cache_rr, &drift); } if (ret != 0) { return ret;