From 78e79ab51780641bb9d5370840691f221ba56b28 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marek=20Vavru=C5=A1a?= <marek.vavrusa@nic.cz>
Date: Mon, 5 Oct 2015 18:25:49 +0200
Subject: [PATCH] lib/cache: key format change, code to check versions

the key is now stored in a format friendly to prefix search, the values
also contain one more 16bit field to store rank of the data (to be
utilised later)
---
 daemon/bindings.c   |  3 ++-
 lib/cache.c         | 63 ++++++++++++++++++++++++++++++++++++---------
 lib/cache.h         |  1 +
 lib/layer/rrcache.c |  2 +-
 4 files changed, 55 insertions(+), 14 deletions(-)

diff --git a/daemon/bindings.c b/daemon/bindings.c
index d5c20d7f5..9221d27c1 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 f75cd76fd..5fd6ec115 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 4408a6bfa..79852f011 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 dde29829e..4c9598f22 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;
-- 
GitLab