diff --git a/utils/kr_cache_gc/Makefile b/utils/kr_cache_gc/Makefile
index fe45efea34d1d76fcaeffa00196005e889abac7a..99c6308b84a3e91c2f7eeaa074479699ede6fd0c 100644
--- a/utils/kr_cache_gc/Makefile
+++ b/utils/kr_cache_gc/Makefile
@@ -1,12 +1,18 @@
 
 all: kr_cache_gc
 
-kr_cache_gc: kr_cache_gc.o main.c kr_cache_gc.h ../../lib/defines.h
-	gcc -std=gnu99 -o $@ main.c kr_cache_gc.o -Wl,-Bdynamic -L../../lib -lknot -lkres -I../..
+kr_cache_gc: kr_cache_gc.o categories.o db.o main.c kr_cache_gc.h ../../lib/defines.h
+	gcc -std=gnu99 -o $@ main.c kr_cache_gc.o categories.o db.o -Wl,-Bdynamic -L../../lib -lknot -lkres -I../..
 
-kr_cache_gc.o: kr_cache_gc.c ../../contrib/dynarray.h ../../lib/defines.h ../../lib/cache/api.h ../../lib/cache/impl.h
+kr_cache_gc.o: kr_cache_gc.c kr_cache_gc.h categories.h db.h ../../contrib/dynarray.h ../../lib/defines.h ../../lib/cache/api.h ../../lib/cache/impl.h
 	gcc -std=gnu99 -o $@ -c $< -I../.. -I../../contrib -I/usr/include/luajit-2.0
 
+categories.o: categories.c categories.h kr_cache_gc.h
+	gcc -std=gnu99 -o $@ -c $<
+
+db.o: db.c db.h kr_cache_gc.h
+	 gcc -std=gnu99 -o $@ -c $< -I../.. -I../../contrib -I/usr/include/luajit-2.0
+
 clean:
-	rm -f kr_cache_gc kr_cache_gc.o
+	rm -f kr_cache_gc kr_cache_gc.o categories.o db.o
 
diff --git a/utils/kr_cache_gc/categories.c b/utils/kr_cache_gc/categories.c
new file mode 100644
index 0000000000000000000000000000000000000000..57c3f2fad37fb25aee8b057202fbf1fd44cc1e8d
--- /dev/null
+++ b/utils/kr_cache_gc/categories.c
@@ -0,0 +1,26 @@
+#include "categories.h"
+
+#include <libknot/libknot.h>
+
+// TODO this is just an example, make this more clever
+category_t kr_gc_categorize(gc_record_info_t *info)
+{
+	category_t res = 60;
+
+	switch (info->rrtype) {
+	case KNOT_RRTYPE_NS:
+	case KNOT_RRTYPE_DS:
+	case KNOT_RRTYPE_DNSKEY:
+	case KNOT_RRTYPE_A:
+	case KNOT_RRTYPE_AAAA:
+		if (info->expires_in > 0) {
+			res = 30;
+		} else {
+			res = 45;
+		}
+		break;
+	}
+
+	return res;
+}
+
diff --git a/utils/kr_cache_gc/categories.h b/utils/kr_cache_gc/categories.h
new file mode 100644
index 0000000000000000000000000000000000000000..e6e91371c7008f54eab8ec0209738e58d890e545
--- /dev/null
+++ b/utils/kr_cache_gc/categories.h
@@ -0,0 +1,10 @@
+#pragma once
+
+#include "kr_cache_gc.h"
+
+typedef uint8_t category_t;
+
+#define CATEGORIES 100 // number of categories
+
+category_t kr_gc_categorize(gc_record_info_t *info);
+
diff --git a/utils/kr_cache_gc/db.c b/utils/kr_cache_gc/db.c
new file mode 100644
index 0000000000000000000000000000000000000000..d05262451337e9c436771d1dd932f6ea8dc3171c
--- /dev/null
+++ b/utils/kr_cache_gc/db.c
@@ -0,0 +1,180 @@
+#include "db.h"
+
+#include <lib/cache/impl.h>
+//#include <lib/defines.h>
+
+#include <sys/stat.h>
+
+struct libknot_lmdb_env
+{
+	bool shared;
+	unsigned dbi;
+	void *env;
+	knot_mm_t *pool;
+};
+
+struct kres_lmdb_env
+{
+	size_t mapsize;
+	unsigned dbi;
+	void *env;
+	// sub-struct txn ommited
+};
+
+static knot_db_t *knot_db_t_kres2libknot(const knot_db_t *db)
+{
+	const struct kres_lmdb_env *kres_db = db; // this is struct lmdb_env as in resolver/cdb_lmdb.c
+	struct libknot_lmdb_env *libknot_db = malloc(sizeof(*libknot_db));
+	if (libknot_db != NULL) {
+		libknot_db->shared = false;
+		libknot_db->pool = NULL;
+		libknot_db->env = kres_db->env;
+		libknot_db->dbi = kres_db->dbi;
+	}
+	return libknot_db;
+}
+
+int kr_gc_cache_open(const char *cache_path, struct kr_cache *kres_db, knot_db_t **libknot_db, double *usage)
+{
+	char cache_data[strlen(cache_path) + 10];
+	snprintf(cache_data, sizeof(cache_data), "%s/data.mdb", cache_path);
+
+	struct stat st = { 0 };
+	if (stat(cache_path, &st) || !(st.st_mode & S_IFDIR) || stat(cache_data, &st)) {
+		printf("Error: %s does not exist or is not a LMDB.\n", cache_path);
+		return -ENOENT;
+	}
+
+	size_t cache_size = st.st_size;
+
+	struct kr_cdb_opts opts = { cache_path, cache_size };
+
+open_kr_cache:
+	;
+	int ret = kr_cache_open(kres_db, NULL, &opts, NULL);
+	if (ret || kres_db->db == NULL) {
+		printf("Error opening Resolver cache (%s).\n", kr_strerror(ret));
+		return -EINVAL;
+	}
+
+	*libknot_db = knot_db_t_kres2libknot(kres_db->db);
+	if (*libknot_db == NULL) {
+		printf("Out of memory.\n");
+		return -ENOMEM;
+	}
+
+	size_t real_size = knot_db_lmdb_get_mapsize(*libknot_db), usageb = knot_db_lmdb_get_usage(*libknot_db);
+	*usage = (double)usageb / real_size * 100.0;
+	printf("Cache size: %zu, Usage: %zu (%.2lf%%)\n", real_size, usageb, *usage);
+
+#if 1
+	if (*usage > 90.0) {
+		free(*libknot_db);
+		kr_cache_close(kres_db);
+		cache_size += cache_size / 10;
+		opts.maxsize = cache_size;
+		goto open_kr_cache;
+	}
+# endif
+	return 0;
+}
+
+void kr_gc_cache_close(struct kr_cache *kres_db, knot_db_t *knot_db)
+{
+	free(knot_db);
+	kr_cache_close(kres_db);
+}
+
+const uint16_t *kr_gc_key_consistent(knot_db_val_t key)
+{
+	const static uint16_t NSEC1 = KNOT_RRTYPE_NSEC;
+	uint8_t *p = key.data;
+	while(*p != 0) {
+		while(*p++ != 0) {
+			if (p - (uint8_t *)key.data >= key.len) {
+				return NULL;
+			}
+		}
+	}
+	if (p - (uint8_t *)key.data >= key.len) {
+		return NULL;
+	}
+	switch (*++p) {
+	case 'E':
+		return (p + 2 - (uint8_t *)key.data >= key.len ? NULL : (uint16_t *)(p + 1));
+	case '1':
+		return &NSEC1;
+	default:
+		return NULL;
+	}
+}
+
+// expects that key is consistent!
+static uint8_t entry_labels(knot_db_val_t *key)
+{
+	uint8_t lab = 0, *p = key->data;
+	while (*p != 0) {
+		while (*p++ != 0) {
+			if (p - (uint8_t *)key->data >= key->len) {
+				return 0;
+			}
+		}
+		lab++;
+	}
+	return lab;
+}
+
+int kr_gc_cache_iter(knot_db_t *knot_db, kr_gc_iter_callback callback, void *ctx)
+{
+	knot_db_txn_t txn = { 0 };
+	knot_db_iter_t *it = NULL;
+	const knot_db_api_t *api = knot_db_lmdb_api();
+	gc_record_info_t info = { 0 };
+	// TODO remove and use time(NULL) ! this is just for debug with pre-generated cache
+	int64_t now = 1524301784;
+
+	int ret = api->txn_begin(knot_db, &txn, KNOT_DB_RDONLY);
+	if (ret != KNOT_EOK) {
+		printf("Error starting DB transaction (%s).\n", knot_strerror(ret));
+		return ret;
+	}
+
+	it = api->iter_begin(&txn, KNOT_DB_FIRST);
+	if (it == NULL) {
+		printf("Error iterationg database.\n");
+		api->txn_abort(&txn);
+		return KNOT_ERROR;
+	}
+
+	while (it != NULL) {
+		knot_db_val_t key = { 0 }, val = { 0 };
+		ret = api->iter_key(it, &key);
+		if (ret == KNOT_EOK) {
+			ret = api->iter_val(it, &val);
+		}
+
+		const uint16_t *entry_type = ret == KNOT_EOK ? kr_gc_key_consistent(key) : NULL;
+		if (entry_type != NULL) {
+			struct entry_h *entry = entry_h_consistent(val, *entry_type);
+
+			info.rrtype = *entry_type;
+			info.entry_size = key.len + val.len;
+			info.expires_in = entry->time + entry->ttl - now;
+			info.no_labels = entry_labels(&key);
+
+			ret = callback(&key, &info, ctx);
+		}
+
+		if (ret != KNOT_EOK) {
+			printf("Error iterating database (%s).\n", knot_strerror(ret));
+			api->iter_finish(it);
+			api->txn_abort(&txn);
+			return ret;
+		}
+
+		it = api->iter_next(it);
+	}
+
+	api->txn_abort(&txn);
+	return KNOT_EOK;
+}
diff --git a/utils/kr_cache_gc/db.h b/utils/kr_cache_gc/db.h
new file mode 100644
index 0000000000000000000000000000000000000000..12e01ec7fac2ec777e9f08b65caf281c5f31f5a2
--- /dev/null
+++ b/utils/kr_cache_gc/db.h
@@ -0,0 +1,16 @@
+#pragma once
+
+#include <lib/cache/api.h>
+#include <libknot/libknot.h>
+
+#include "kr_cache_gc.h"
+
+int kr_gc_cache_open(const char *cache_path, struct kr_cache *kres_db, knot_db_t **libknot_db, double *usage);
+
+void kr_gc_cache_close(struct kr_cache *kres_db, knot_db_t *knot_db);
+
+typedef int (*kr_gc_iter_callback)(const knot_db_val_t *key, gc_record_info_t *info, void *ctx);
+
+int kr_gc_cache_iter(knot_db_t *knot_db, kr_gc_iter_callback callback, void *ctx);
+
+const uint16_t *kr_gc_key_consistent(knot_db_val_t key);
diff --git a/utils/kr_cache_gc/kr_cache_gc.c b/utils/kr_cache_gc/kr_cache_gc.c
index bbcd23f73fdd4dd6b16c7f824f60a0a3b63e7695..27f2a5feb24b64326dcaafe609329380fa43c4dc 100644
--- a/utils/kr_cache_gc/kr_cache_gc.c
+++ b/utils/kr_cache_gc/kr_cache_gc.c
@@ -3,7 +3,6 @@
 #include <limits.h>
 #include <stdio.h>
 #include <time.h>
-#include <sys/stat.h>
 
 // libknot includes
 #include <libknot/libknot.h>
@@ -16,8 +15,8 @@
 
 #include "kr_cache_gc.h"
 
-// TODO remove and use time(NULL) ! this is just for debug with pre-generated cache
-int64_t now = 1524301784;
+#include "categories.h"
+#include "db.h"
 
 // section: timer
 // TODO replace/move to contrib
@@ -46,63 +45,6 @@ static unsigned long gc_timer_usecs(gc_timer_t *t)
 	return ((end.tv_sec - start->tv_sec) * 1000000UL + (end.tv_nsec - start->tv_nsec) / 1000UL);
 }
 
-// section: function key_consistent
-
-static const uint16_t *key_consistent(knot_db_val_t key)
-{
-	const static uint16_t NSEC1 = KNOT_RRTYPE_NSEC;
-	uint8_t *p = key.data;
-	while(*p != 0) {
-		while(*p++ != 0) {
-			if (p - (uint8_t *)key.data >= key.len) {
-				return NULL;
-			}
-		}
-	}
-	if (p - (uint8_t *)key.data >= key.len) {
-		return NULL;
-	}
-	switch (*++p) {
-	case 'E':
-		return (p + 2 - (uint8_t *)key.data >= key.len ? NULL : (uint16_t *)(p + 1));
-	case '1':
-		return &NSEC1;
-	default:
-		return NULL;
-	}
-}
-
-// section: converting struct lmdb_env from resolver-format to libknot-format
-
-struct libknot_lmdb_env
-{
-	bool shared;
-	unsigned dbi;
-	void *env;
-	knot_mm_t *pool;
-};
-
-struct kres_lmdb_env
-{
-	size_t mapsize;
-	unsigned dbi;
-	void *env;
-	// sub-struct txn ommited
-};
-
-static knot_db_t *knot_db_t_kres2libknot(const knot_db_t *db)
-{
-	const struct kres_lmdb_env *kres_db = db; // this is struct lmdb_env as in resolver/cdb_lmdb.c
-	struct libknot_lmdb_env *libknot_db = malloc(sizeof(*libknot_db));
-	if (libknot_db != NULL) {
-		libknot_db->shared = false;
-		libknot_db->pool = NULL;
-		libknot_db->env = kres_db->env;
-		libknot_db->dbi = kres_db->dbi;
-	}
-	return libknot_db;
-}
-
 // section: dbval_copy
 
 static knot_db_val_t *dbval_copy(const knot_db_val_t *from)
@@ -145,126 +87,96 @@ static void rrtypelist_print(rrtype_dynarray_t *arr)
 	printf("\n");
 }
 
-// section: main
-
 dynarray_declare(entry, knot_db_val_t*, DYNARRAY_VISIBILITY_STATIC, 256);
 dynarray_define(entry, knot_db_val_t*, DYNARRAY_VISIBILITY_STATIC);
-
-
-int kr_cache_gc(kr_cache_gc_cfg_t *cfg)
+static void entry_dynarray_deep_free(entry_dynarray_t *d)
 {
-	char cache_data[strlen(cfg->cache_path) + 10];
-	snprintf(cache_data, sizeof(cache_data), "%s/data.mdb", cfg->cache_path);
-
-	struct stat st = { 0 };
-	if (stat(cfg->cache_path, &st) || !(st.st_mode & S_IFDIR) || stat(cache_data, &st)) {
-		printf("Error: %s does not exist or is not a LMDB.\n", cfg->cache_path);
-		return -ENOENT;
+	dynarray_foreach(entry, knot_db_val_t*, i, *d) {
+		free(*i);
 	}
+	entry_dynarray_free(d);
+}
 
-	size_t cache_size = st.st_size;
-
-	struct kr_cdb_opts opts = { cfg->cache_path, cache_size };
-	struct kr_cache krc = { 0 };
-
-open_kr_cache:
-	;
-	int ret = kr_cache_open(&krc, NULL, &opts, NULL);
-	if (ret || krc.db == NULL) {
-		printf("Error opening Resolver cache (%s).\n", kr_strerror(ret));
-		return -EINVAL;
-	}
+typedef struct {
+	size_t categories_sizes[CATEGORIES];
+} ctx_compute_categories_t;
 
-	entry_dynarray_t to_del = { 0 };
-	rrtype_dynarray_t cache_rrtypes = { 0 };
+int cb_compute_categories(const knot_db_val_t *key, gc_record_info_t *info, void *vctx)
+{
+	ctx_compute_categories_t *ctx = vctx;
+	category_t cat = kr_gc_categorize(info);
+	(void)key;
+	ctx->categories_sizes[cat] += info->entry_size;
+	return KNOT_EOK;
+}
 
-	gc_timer_t timer_analyze = { 0 }, timer_delete = { 0 }, timer_rw_txn = { 0 };
+typedef struct {
+	category_t limit_category;
+	entry_dynarray_t to_delete;
+	size_t cfg_temp_keys_space;
+	size_t used_space;
+	size_t oversize_records;
+} ctx_delete_categories_t;
 
-	const knot_db_api_t *api = knot_db_lmdb_api();
-	knot_db_txn_t txn = { 0 };
-	knot_db_iter_t *it = NULL;
-	knot_db_t *db = knot_db_t_kres2libknot(krc.db);
-	if (db == NULL) {
-		printf("Out of memory.\n");
-		ret = KNOT_ENOMEM;
-		goto fail;
+int cb_delete_categories(const knot_db_val_t *key, gc_record_info_t *info, void *vctx)
+{
+	ctx_delete_categories_t *ctx = vctx;
+	category_t cat = kr_gc_categorize(info);
+	if (cat >= ctx->limit_category) {
+		knot_db_val_t *todelete = dbval_copy(key);
+		size_t used = ctx->used_space + key->len + sizeof(*key);
+		if ((ctx->cfg_temp_keys_space > 0 &&
+		     used > ctx->cfg_temp_keys_space) ||
+		    todelete == NULL) {
+			ctx->oversize_records++;
+		} else {
+			entry_dynarray_add(&ctx->to_delete, &todelete);
+			ctx->used_space = used;
+		}
 	}
+	return KNOT_EOK;
+}
 
-	size_t real_size = knot_db_lmdb_get_mapsize(db), usage = knot_db_lmdb_get_usage(db);
-	double usage_perc = (double)usage / real_size * 100.0;
-	printf("Cache size: %zu, Usage: %zu (%.2lf%%)\n", real_size, usage, usage_perc);
+int kr_cache_gc(kr_cache_gc_cfg_t *cfg)
+{
+	struct kr_cache kres_db = { 0 };
+	knot_db_t *db = NULL;
+	double db_usage;
 
-	if (usage_perc > 90.0) {
-		free(db);
-		kr_cache_close(&krc);
-		cache_size += cache_size / 10;
-		opts.maxsize = cache_size;
-		goto open_kr_cache;
+	int ret = kr_gc_cache_open(cfg->cache_path, &kres_db, &db, &db_usage);
+	if (ret) {
+		return ret;
 	}
 
-	gc_timer_start(&timer_analyze);
+	gc_timer_t timer_analyze = { 0 }, timer_choose = { 0 }, timer_delete = { 0 }, timer_rw_txn = { 0 };
 
-	ret = api->txn_begin(db, &txn, KNOT_DB_RDONLY);
+	gc_timer_start(&timer_analyze);
+	ctx_compute_categories_t cats = { 0 };
+	ret = kr_gc_cache_iter(db, cb_compute_categories, &cats);
 	if (ret != KNOT_EOK) {
-		printf("Error starting DB transaction (%s).\n", knot_strerror(ret));
-		goto fail;
-	}
-
-	it = api->iter_begin(&txn, KNOT_DB_FIRST);
-	if (it == NULL) {
-		printf("Error iterating DB.\n");
-		ret = KNOT_ERROR;
-		goto fail;
-	}
-
-	size_t cache_records = 0, deleted_records = 0;
-	size_t oversize_records = 0, already_gone = 0;;
-	size_t used_space = 0, rw_txn_count = 1;
-	int64_t min_expire = INT64_MAX;
-
-	while (it != NULL) {
-		knot_db_val_t key = { 0 }, val = { 0 };
-		if ((ret = api->iter_key(it, &key)) != KNOT_EOK ||
-		    (ret = api->iter_val(it, &val)) != KNOT_EOK) {
-			printf("Warning: skipping a key due to error (%s).\n", knot_strerror(ret));
-		}
-		const uint16_t *entry_type = ret == KNOT_EOK ? key_consistent(key) : NULL;
-		if (entry_type != NULL) {
-			cache_records++;
-			rrtypelist_add(&cache_rrtypes, *entry_type);
-
-			struct entry_h *entry = entry_h_consistent(val, *entry_type);
-			int64_t over = entry->time + entry->ttl;
-			over -= now;
-			if (over < min_expire) {
-				min_expire = over;
-			}
-			if (over < 0) {
-				knot_db_val_t *todelete;
-				if ((cfg->temp_keys_space > 0 &&
-				     used_space + key.len + sizeof(key) > cfg->temp_keys_space) ||
-				    (todelete = dbval_copy(&key)) == NULL) {
-					oversize_records++;
-				} else {
-					used_space += todelete->len + sizeof(*todelete);
-					entry_dynarray_add(&to_del, &todelete);
-				}
-			}
-		}
-
-		it = api->iter_next(it);
+		kr_gc_cache_close(&kres_db, db);
+		return ret;
 	}
 
-	api->txn_abort(&txn);
+	category_t limit_category = 50; // TODO fix this computation
+	printf("Cache analyzed in %.2lf secs, limit category is %d.\n", gc_timer_end(&timer_analyze), limit_category);
 
-	printf("Cache analyzed in %.2lf secs, %zu records types", gc_timer_end(&timer_analyze), cache_records);
-	rrtypelist_print(&cache_rrtypes);
-	if (min_expire < INT64_MAX) {
-		printf("Minimum expire in %"PRId64" secs\n", min_expire);
+	gc_timer_start(&timer_choose);
+	ctx_delete_categories_t to_del = { 0 };
+	to_del.cfg_temp_keys_space = cfg->temp_keys_space;
+	to_del.limit_category = limit_category;
+	ret = kr_gc_cache_iter(db, cb_delete_categories, &to_del);
+	if (ret != KNOT_EOK) {
+		entry_dynarray_deep_free(&to_del.to_delete);
+		kr_gc_cache_close(&kres_db, db);
+		return ret;
 	}
 	printf("%zu records to be deleted using %.2lf MBytes of temporary memory, %zu records skipped due to memory limit.\n",
-	       to_del.size, ((double)used_space / 1048576.0), oversize_records);
-	rrtype_dynarray_free(&cache_rrtypes);
+	       to_del.to_delete.size, ((double)to_del.used_space / 1048576.0), to_del.oversize_records);
+
+	const knot_db_api_t *api = knot_db_lmdb_api();
+	knot_db_txn_t txn = { 0 };
+	size_t deleted_records = 0, already_gone = 0, rw_txn_count = 0;
 
 	gc_timer_start(&timer_delete);
 	gc_timer_start(&timer_rw_txn);
@@ -272,16 +184,18 @@ int kr_cache_gc(kr_cache_gc_cfg_t *cfg)
 
 	ret = api->txn_begin(db, &txn, 0);
 	if (ret != KNOT_EOK) {
-		printf("Error starting DB transaction (%s).\n", knot_strerror(ret));
-		goto fail;
+		printf("Error starting R/W DB transaction (%s).\n", knot_strerror(ret));
+		entry_dynarray_deep_free(&to_del.to_delete);
+		kr_gc_cache_close(&kres_db, db);
+		return ret;
 	}
 
-	dynarray_foreach(entry, knot_db_val_t*, i, to_del) {
+	dynarray_foreach(entry, knot_db_val_t*, i, to_del.to_delete) {
 		ret = api->del(&txn, *i);
 		switch (ret) {
 		case KNOT_EOK:
 			deleted_records++;
-			const uint16_t *entry_type = ret == KNOT_EOK ? key_consistent(**i) : NULL;
+			const uint16_t *entry_type = ret == KNOT_EOK ? kr_gc_key_consistent(**i) : NULL;
 			assert(entry_type != NULL);
 			rrtypelist_add(&deleted_rrtypes, *entry_type);
 			break;
@@ -304,33 +218,21 @@ int kr_cache_gc(kr_cache_gc_cfg_t *cfg)
 				ret = api->txn_begin(db, &txn, 0);
 			}
 			if (ret != KNOT_EOK) {
-				printf("Error restarting DB transaction (%s)\n", knot_strerror(ret));
-				goto fail;
+				break;
 			}
 		}
 	}
 
 	printf("Deleted %zu records (%zu already gone) types", deleted_records, already_gone);
 	rrtypelist_print(&deleted_rrtypes);
-	printf("It took %.2lf secs, %zu transactions \n", gc_timer_end(&timer_delete), rw_txn_count);
+	printf("It took %.2lf secs, %zu transactions (%s)\n", gc_timer_end(&timer_delete), rw_txn_count, knot_strerror(ret));
 
 	ret = api->txn_commit(&txn);
-	txn.txn = NULL;
 
-fail:
 	rrtype_dynarray_free(&deleted_rrtypes);
-	dynarray_foreach(entry, knot_db_val_t*, i, to_del) {
-		free(*i);
-	}
-	entry_dynarray_free(&to_del);
-
-	api->iter_finish(it);
-	if (txn.txn) {
-		api->txn_abort(&txn);
-	}
+	entry_dynarray_deep_free(&to_del.to_delete);
 
-	free(db);
-	kr_cache_close(&krc);
+	kr_gc_cache_close(&kres_db, db);
 
 	return ret;
 }
diff --git a/utils/kr_cache_gc/kr_cache_gc.h b/utils/kr_cache_gc/kr_cache_gc.h
index 8c2e3b2e4fe92c41639f177297428ac96855f334..8031131e749a16c0bc6df92faa448a21ecbb7b74 100644
--- a/utils/kr_cache_gc/kr_cache_gc.h
+++ b/utils/kr_cache_gc/kr_cache_gc.h
@@ -1,6 +1,15 @@
 #pragma once
 
 #include <stddef.h>
+#include <stdint.h>
+
+typedef struct {
+        int64_t expires_in;         // < 0 => already expired
+        uint16_t rrtype;
+        uint8_t no_labels;          // 0 == ., 1 == root zone member, 2 == TLD member ...
+        uint8_t rank;
+        size_t entry_size;          // amount of bytes occupied in cache by this record
+} gc_record_info_t;
 
 typedef struct {
         const char *cache_path;          // path to the LMDB with resolver cache
@@ -16,4 +25,4 @@ typedef struct {
 
 int kr_cache_gc(kr_cache_gc_cfg_t *cfg);
 
-#define KR_CACHE_GC_VERSION "0.1"
+#define KR_CACHE_GC_VERSION "0.2"