From: Lukáš Ježek Date: Fri, 10 Jul 2020 13:08:13 +0000 (+0200) Subject: cache: add percentage usage to cache stats X-Git-Tag: v5.1.3~24^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=510f61ea0c2237f8266efd66cd40560152692a34;p=thirdparty%2Fknot-resolver.git cache: add percentage usage to cache stats --- diff --git a/NEWS b/NEWS index 91464668a..a3dfd3b11 100644 --- a/NEWS +++ b/NEWS @@ -4,6 +4,7 @@ Knot Resolver 5.2.0 (2020-0m-dd) Improvements ------------ - capabilities are no longer constrained when running as root (!1012) +- cache: add percentage usage to cache.stats() (!1025) Bugfixes -------- diff --git a/daemon/bindings/cache.c b/daemon/bindings/cache.c index 170282e5f..bf944b90f 100644 --- a/daemon/bindings/cache.c +++ b/daemon/bindings/cache.c @@ -3,6 +3,7 @@ */ #include "daemon/bindings/impl.h" +#include "lib/cache/cdb_lmdb.h" #include "daemon/worker.h" #include "daemon/zimport.h" @@ -93,6 +94,12 @@ static int cache_stats(lua_State *L) add_stat(match_miss); add_stat(read_leq); add_stat(read_leq_miss); + /* usage_percent statistics special case - double */ + struct libknot_lmdb_env *libknot_db = knot_db_t_kres2libknot(cache->db); + cache->stats.usage_percent = cache->api->usage_percent(libknot_db); + lua_pushnumber(L, cache->stats.usage_percent); + lua_setfield(L, -2, "usage_percent"); + free(libknot_db); #undef add_stat return 1; diff --git a/daemon/cache.test/clear.test.lua b/daemon/cache.test/clear.test.lua index 37bd8ab27..8185ae524 100644 --- a/daemon/cache.test/clear.test.lua +++ b/daemon/cache.test/clear.test.lua @@ -186,17 +186,29 @@ local function test_complete_flush() is(cache.count(), 0, 'cache is empty after full clear') end +local function test_cache_used(lower, upper) + return function() + local usage = cache.stats().usage_percent + ok(usage >= lower and usage <= upper, string.format('cache percentage usage is between <%d, %d>', lower, upper)) + end +end + return { + test_cache_used(0, 1), import_zone, + test_cache_used(11, 12), test_exact_match_qtype, test_exact_match_qname, test_callback, import_zone, test_subtree, + test_cache_used(10, 11), test_subtree_limit, + test_cache_used(5, 6), test_apex, import_zone, test_root, import_zone, test_complete_flush, + test_cache_used(0, 1), } diff --git a/daemon/lua/kres-gen.lua b/daemon/lua/kres-gen.lua index 4977ef1b1..c77ffc0eb 100644 --- a/daemon/lua/kres-gen.lua +++ b/daemon/lua/kres-gen.lua @@ -210,6 +210,7 @@ struct kr_cdb_stats { uint64_t match_miss; uint64_t read_leq; uint64_t read_leq_miss; + double usage_percent; }; struct kr_cache { knot_db_t *db; diff --git a/lib/cache/cdb_api.h b/lib/cache/cdb_api.h index 23d9a7c59..c04cce533 100644 --- a/lib/cache/cdb_api.h +++ b/lib/cache/cdb_api.h @@ -29,6 +29,7 @@ struct kr_cdb_stats { uint64_t match_miss; uint64_t read_leq; uint64_t read_leq_miss; + double usage_percent; }; @@ -74,4 +75,6 @@ struct kr_cdb_api { * return: 0 for equality, > 0 for less, < 0 kr_error */ int (*read_leq)(knot_db_t *db, struct kr_cdb_stats *stat, knot_db_val_t *key, knot_db_val_t *val); + + double (*usage_percent)(knot_db_t *db); }; diff --git a/lib/cache/cdb_lmdb.c b/lib/cache/cdb_lmdb.c index d009f1d1b..9e970d5d8 100644 --- a/lib/cache/cdb_lmdb.c +++ b/lib/cache/cdb_lmdb.c @@ -17,6 +17,7 @@ #include "lib/cache/cdb_lmdb.h" #include "lib/cache/cdb_api.h" #include "lib/cache/api.h" +#include #include "lib/utils.h" @@ -24,6 +25,8 @@ #define LMDB_DIR_MODE 0770 #define LMDB_FILE_MODE 0660 +/* TODO: we rely on mirrors of these two structs not changing layout + * in libknot and knot resolver! */ struct lmdb_env { size_t mapsize; @@ -43,6 +46,14 @@ struct lmdb_env } txn; }; +struct libknot_lmdb_env { + bool shared; + unsigned dbi; + void *env; + knot_mm_t *pool; +}; + + /** @brief Convert LMDB error code. */ static int lmdb_error(int error) { @@ -77,7 +88,6 @@ static inline MDB_val val_knot2mdb(knot_db_val_t v) return (MDB_val){ .mv_size = v.len, .mv_data = v.data }; } - /*! \brief Set the environment map size. * \note This also sets the maximum database size, see \fn mdb_env_set_mapsize */ @@ -704,6 +714,30 @@ success: return ret; } +static double cdb_usage(knot_db_t *db) +{ + const size_t db_size = knot_db_lmdb_get_mapsize(db); + const size_t db_usage_abs = knot_db_lmdb_get_usage(db); + const double db_usage = (double)db_usage_abs / db_size * 100.0; + + return db_usage; +} + + +/** Conversion between knot and lmdb structs. */ +knot_db_t *knot_db_t_kres2libknot(const knot_db_t * db) +{ + /* this is struct lmdb_env as in resolver/cdb_lmdb.c */ + const struct lmdb_env *kres_db = db; + 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; +} const struct kr_cdb_api *kr_cdb_lmdb(void) { @@ -712,7 +746,8 @@ const struct kr_cdb_api *kr_cdb_lmdb(void) cdb_init, cdb_deinit, cdb_count, cdb_clear, cdb_commit, cdb_readv, cdb_writev, cdb_remove, cdb_match, - cdb_read_leq + cdb_read_leq, + cdb_usage, }; return &api; diff --git a/lib/cache/cdb_lmdb.h b/lib/cache/cdb_lmdb.h index 114adca44..020e05690 100644 --- a/lib/cache/cdb_lmdb.h +++ b/lib/cache/cdb_lmdb.h @@ -9,3 +9,6 @@ KR_EXPORT KR_CONST const struct kr_cdb_api *kr_cdb_lmdb(void); + +KR_EXPORT +knot_db_t *knot_db_t_kres2libknot(const knot_db_t * db); diff --git a/utils/cache_gc/db.c b/utils/cache_gc/db.c index 7dbccd31d..2fd0ed172 100644 --- a/utils/cache_gc/db.c +++ b/utils/cache_gc/db.c @@ -3,6 +3,7 @@ #include "db.h" +#include "lib/cache/cdb_lmdb.h" #include //#include @@ -10,34 +11,6 @@ #include #include -//TODO: we rely on mirrors of these two structs not changing layout in knot-dns and knot-resolver! -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) { diff --git a/utils/cache_gc/kr_cache_gc.c b/utils/cache_gc/kr_cache_gc.c index 38bf21ed6..ca76eb1e9 100644 --- a/utils/cache_gc/kr_cache_gc.c +++ b/utils/cache_gc/kr_cache_gc.c @@ -13,6 +13,7 @@ #include #include #include +#include "lib/cache/cdb_lmdb.h" #include "kr_cache_gc.h" @@ -176,9 +177,8 @@ int kr_cache_gc(kr_cache_gc_cfg_t *cfg, kr_cache_gc_state_t **state) } knot_db_t *const db = (*state)->db; // frequently used shortcut - const size_t db_size = knot_db_lmdb_get_mapsize(db); - const size_t db_usage_abs = knot_db_lmdb_get_usage(db); - const double db_usage = (double)db_usage_abs / db_size * 100.0; + const struct kr_cdb_api *cache_api = kr_cdb_lmdb(); + const double db_usage = cache_api->usage_percent(db); #if 0 // Probably not worth it, better reduce the risk by checking more often. if (db_usage > 90.0) { free(*libknot_db); @@ -190,11 +190,7 @@ int kr_cache_gc(kr_cache_gc_cfg_t *cfg, kr_cache_gc_state_t **state) #endif const bool large_usage = db_usage >= cfg->cache_max_usage; if (cfg->dry_run || large_usage) { // don't print this on every size check - const size_t MiB = 1024 * 1024; - #define MiB_round(n) (((n) + MiB/2) / MiB) - printf("Usage: %.2lf%% (%zu / %zu MiB)\n", - db_usage, MiB_round(db_usage_abs), MiB_round(db_size)); - #undef MiB_round + printf("Usage: %.2lf%%\n", db_usage); } if (cfg->dry_run || !large_usage) { return KNOT_EOK;