]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
reworked cache stats
authorPetr Špaček <petr.spacek@nic.cz>
Tue, 26 Feb 2019 16:06:24 +0000 (17:06 +0100)
committerPetr Špaček <petr.spacek@nic.cz>
Wed, 6 Mar 2019 12:03:34 +0000 (13:03 +0100)
All cache operations are now counted. These are internal cache
operations and do not map directly to number of queries or even number
of RRs.

Closes: !515
12 files changed:
daemon/bindings/cache.c
daemon/bindings/cache.rst
daemon/lua/kres-gen.lua
daemon/lua/kres-gen.sh
daemon/lua/kres.lua
lib/cache/api.c
lib/cache/api.h
lib/cache/cdb_api.h
lib/cache/cdb_lmdb.c
lib/cache/impl.h
tests/config/cache.test.lua
tests/deckard

index 2574a7cc099ee39565a19167cdcf1668b08ee103..0e0c04dda46a1a42dd3d317df7bfdcd9fb2afbe3 100644 (file)
@@ -51,7 +51,7 @@ static int cache_count(lua_State *L)
 {
        struct kr_cache *cache = cache_assert_open(L);
 
-       int count = cache->api->count(cache->db);
+       int count = cache->api->count(cache->db, &cache->stats);
        if (count >= 0) {
                /* First key is a version counter, omit it if nonempty. */
                lua_pushinteger(L, count ? count - 1 : 0);
@@ -90,14 +90,25 @@ static int cache_stats(lua_State *L)
 {
        struct kr_cache *cache = cache_assert_open(L);
        lua_newtable(L);
-       lua_pushnumber(L, cache->stats.hit);
-       lua_setfield(L, -2, "hit");
-       lua_pushnumber(L, cache->stats.miss);
-       lua_setfield(L, -2, "miss");
-       lua_pushnumber(L, cache->stats.insert);
-       lua_setfield(L, -2, "insert");
-       lua_pushnumber(L, cache->stats.delete);
-       lua_setfield(L, -2, "delete");
+#define add_stat(name) \
+       lua_pushinteger(L, (cache->stats.name)); \
+       lua_setfield(L, -2, #name)
+       add_stat(open);
+       add_stat(close);
+       add_stat(count);
+       add_stat(clear);
+       add_stat(commit);
+       add_stat(read);
+       add_stat(read_miss);
+       add_stat(write);
+       add_stat(remove);
+       add_stat(remove_miss);
+       add_stat(match);
+       add_stat(match_miss);
+       add_stat(read_leq);
+       add_stat(read_leq_miss);
+#undef add_stat
+
        return 1;
 }
 
index 918a012c1880973b3033e027c5aa0e3e72d6d944..ef297fbd160e44f6502e913be32350c51cb86539 100644 (file)
@@ -86,16 +86,34 @@ daemons or manipulated from other processes, making for example synchronized loa
 
 .. function:: cache.stats()
 
-  .. warning:: Cache statistics are being reworked. Do not rely on current behavior.
-
-   Return table of statistics, note that this tracks all operations over cache, not just which
-   queries were answered from cache or not.
+   Return table with low-level statistics for each internal cache operation.
+   This counts each access to cache and does not directly map to individual
+   DNS queries or resource records.
+   For query-level statistics see :ref:`stats module <mod-stats>`.
 
    Example:
 
    .. code-block:: lua
 
-       print('Insertions:', cache.stats().insert)
+       > cache.stats()
+       [read_leq_miss] => 4
+       [write] => 189
+       [read_leq] => 9
+       [read] => 4313
+       [read_miss] => 1143
+       [open] => 0
+       [close] => 0
+       [remove_miss] => 0
+       [commit] => 117
+       [match_miss] => 2
+       [match] => 21
+       [count] => 2
+       [clear] => 0
+       [remove] => 17
+
+   Cache operation `read_leq` (*read less or equal*, i.e. range search) was requested 9 times,
+   and 4 out of 9 operations were finished with *cache miss*.
+
 
 .. function:: cache.max_ttl([ttl])
 
index 994dd200259dbf90324a099a188c613cb7082f00..727d624612515c5c7b132ea9351f28a415d6bcd5 100644 (file)
@@ -200,15 +200,26 @@ struct kr_request {
        void *daemon_context;
 };
 enum kr_rank {KR_RANK_INITIAL, KR_RANK_OMIT, KR_RANK_TRY, KR_RANK_INDET = 4, KR_RANK_BOGUS, KR_RANK_MISMATCH, KR_RANK_MISSING, KR_RANK_INSECURE, KR_RANK_AUTH = 16, KR_RANK_SECURE = 32};
+struct kr_cdb_stats {
+       uint64_t open;
+       uint64_t close;
+       uint64_t count;
+       uint64_t clear;
+       uint64_t commit;
+       uint64_t read;
+       uint64_t read_miss;
+       uint64_t write;
+       uint64_t remove;
+       uint64_t remove_miss;
+       uint64_t match;
+       uint64_t match_miss;
+       uint64_t read_leq;
+       uint64_t read_leq_miss;
+};
 struct kr_cache {
        knot_db_t *db;
        const struct kr_cdb_api *api;
-       struct {
-               uint32_t hit;
-               uint32_t miss;
-               uint32_t insert;
-               uint32_t delete;
-       } stats;
+       struct kr_cdb_stats stats;
        uint32_t ttl_min;
        uint32_t ttl_max;
        struct timeval checkpoint_walltime;
index 2f8206db4d8d58175e37bf8c3b4a7277a101a754..b5a794f31afdf2479a6c6adf0c88e48d8b1f193b 100755 (executable)
@@ -77,6 +77,7 @@ genResType "knot_rrset_t" | sed 's/\<owner\>/_owner/; s/\<ttl\>/_ttl/'
        struct kr_request_qsource_flags
        struct kr_request
        enum kr_rank
+       struct kr_cdb_stats
        struct kr_cache
 EOF
 
index 448624c1e346d0cdb8cc8f7155b624111d73059f..7352a9942993bde527773ee9af2c2dc15d24392d 100644 (file)
@@ -840,7 +840,7 @@ ffi.metatype( kr_cache_t, {
                        if ret ~= 0 then return nil, knot_error_t(ret) end
                        return true
                end,
-               sync = function (self)
+               commit = function (self)
                        assert(ffi.istype(kr_cache_t, self))
                        local ret = C.kr_cache_commit(self)
                        if ret ~= 0 then return nil, knot_error_t(ret) end
index 31ef149c7b933165ef164e1b4fdc79c1f3688e4d..e15e5f4087ad1344a36e9b06825c067c86b61d72 100644 (file)
@@ -66,7 +66,6 @@ static int stash_rrset_precond(const knot_rrset_t *rr, const struct kr_query *qr
 /** @internal Removes all records from cache. */
 static inline int cache_clear(struct kr_cache *cache)
 {
-       cache->stats.delete += 1;
        return cache_op(cache, clear);
 }
 
@@ -121,11 +120,11 @@ int kr_cache_open(struct kr_cache *cache, const struct kr_cdb_api *api, struct k
                api = kr_cdb_lmdb();
        }
        cache->api = api;
-       int ret = cache->api->open(&cache->db, opts, mm);
+       memset(&cache->stats, 0, sizeof(cache->stats));
+       int ret = cache->api->open(&cache->db, &cache->stats, opts, mm);
        if (ret != 0) {
                return ret;
        }
-       memset(&cache->stats, 0, sizeof(cache->stats));
        cache->ttl_min = KR_CACHE_DEFAULT_TTL_MIN;
        cache->ttl_max = KR_CACHE_DEFAULT_TTL_MAX;
        /* Check cache ABI version */
@@ -561,9 +560,6 @@ static ssize_t stash_rrset(struct kr_cache *cache, const struct kr_query *qry,
        }
        #endif
 
-       /* Update metrics */
-       cache->stats.insert += 1;
-
        /* Verbose-log some not-too-common cases. */
        WITH_VERBOSE(qry) { if (kr_rank_test(rank, KR_RANK_AUTH)
                                || rr->type == KNOT_RRTYPE_NS) {
index 1fe3d081acad0e3bc75e9ecf7b2deb1a62d6ab4b..aa34eaa94f25cbdaee8a67590016aac243683169 100644 (file)
@@ -40,13 +40,7 @@ struct kr_cache
 {
        knot_db_t *db;                /**< Storage instance */
        const struct kr_cdb_api *api; /**< Storage engine */
-       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 */
-       } stats;
-
+       struct kr_cdb_stats stats;
        uint32_t ttl_min, ttl_max; /**< TTL limits */
 
        /* A pair of stamps for detection of real-time shifts during runtime. */
index 943256152163932d89fc0713d4652a006211f3a6..b22d34cb0936c3104334906e28f6984e140c548a 100644 (file)
@@ -16,6 +16,8 @@
 
 #pragma once
 
+#include <stdint.h>
+
 #include <libknot/db/db.h>
 
 /* Cache options. */
@@ -24,6 +26,24 @@ struct kr_cdb_opts {
        size_t maxsize;   /*!< Suggested cache size in bytes. */
 };
 
+struct kr_cdb_stats {
+       uint64_t open;
+       uint64_t close;
+       uint64_t count;
+       uint64_t clear;
+       uint64_t commit;
+       uint64_t read;
+       uint64_t read_miss;
+       uint64_t write;
+       uint64_t remove;
+       uint64_t remove_miss;
+       uint64_t match;
+       uint64_t match_miss;
+       uint64_t read_leq;
+       uint64_t read_leq_miss;
+};
+
+
 /*! Cache database API.
   * This is a simplified version of generic DB API from libknot,
   * that is tailored to caching purposes.
@@ -33,34 +53,37 @@ struct kr_cdb_api {
 
        /* Context operations */
 
-       int (*open)(knot_db_t **db, struct kr_cdb_opts *opts, knot_mm_t *mm);
-       void (*close)(knot_db_t *db);
-       int (*count)(knot_db_t *db);
-       int (*clear)(knot_db_t *db);
+       int (*open)(knot_db_t **db, struct kr_cdb_stats *stat, struct kr_cdb_opts *opts, knot_mm_t *mm);
+       void (*close)(knot_db_t *db, struct kr_cdb_stats *stat);
+       int (*count)(knot_db_t *db, struct kr_cdb_stats *stat);
+       int (*clear)(knot_db_t *db, struct kr_cdb_stats *stat);
 
        /** Run after a row of operations to release transaction/lock if needed. */
-       int (*commit)(knot_db_t *db);
+       int (*commit)(knot_db_t *db, struct kr_cdb_stats *stat);
 
        /* Data access */
 
-       int (*read)(knot_db_t *db, const knot_db_val_t *key, knot_db_val_t *val,
-                       int maxcount);
-       int (*write)(knot_db_t *db, const knot_db_val_t *key, knot_db_val_t *val,
-                       int maxcount);
+       int (*read)(knot_db_t *db, struct kr_cdb_stats *stat,
+                       const knot_db_val_t *key, knot_db_val_t *val, int maxcount);
+       int (*write)(knot_db_t *db, struct kr_cdb_stats *stat, const knot_db_val_t *key,
+                       knot_db_val_t *val, int maxcount);
 
        /** Remove maxcount keys.
         * \returns the number of succesfully removed keys or the first error code
         * It returns on first error, but ENOENT is not considered an error. */
-       int (*remove)(knot_db_t *db, knot_db_val_t keys[], int maxcount);
+       int (*remove)(knot_db_t *db, struct kr_cdb_stats *stat,
+                       knot_db_val_t keys[], int maxcount);
 
        /* Specialised operations */
 
        /** Find key-value pairs that are prefixed by the given key, limited by maxcount.
         * \return the number of pairs or negative error. */
-       int (*match)(knot_db_t *db, knot_db_val_t *key, knot_db_val_t keyval[][2], int maxcount);
+       int (*match)(knot_db_t *db, struct kr_cdb_stats *stat,
+                       knot_db_val_t *key, knot_db_val_t keyval[][2], int maxcount);
 
        /** Less-or-equal search (lexicographic ordering).
         * On successful return, key->data and val->data point to DB-owned data.
         * return: 0 for equality, > 0 for less, < 0 kr_error */
-       int (*read_leq)(knot_db_t *db, knot_db_val_t *key, knot_db_val_t *val);
+       int (*read_leq)(knot_db_t *db, struct kr_cdb_stats *stat,
+                       knot_db_val_t *key, knot_db_val_t *val);
 };
index 96a1fc1a6bd6432518aee14898a4708178ce2372..db929592e8156db71f8ded3074e681b772a3de83 100644 (file)
@@ -26,6 +26,7 @@
 
 #include "contrib/cleanup.h"
 #include "lib/cache/cdb_lmdb.h"
+#include "lib/cache/cdb_api.h"
 #include "lib/cache/api.h"
 #include "lib/utils.h"
 
@@ -185,11 +186,12 @@ static int txn_get(struct lmdb_env *env, MDB_txn **txn, bool rdonly)
        return kr_ok();
 }
 
-static int cdb_commit(knot_db_t *db)
+static int cdb_commit(knot_db_t *db, struct kr_cdb_stats *stats)
 {
        struct lmdb_env *env = db;
        int ret = kr_ok();
        if (env->txn.rw) {
+               stats->commit++;
                ret = lmdb_error(mdb_txn_commit(env->txn.rw));
                env->txn.rw = NULL; /* the transaction got freed even in case of errors */
        } else if (env->txn.ro && env->txn.ro_active) {
@@ -201,7 +203,7 @@ static int cdb_commit(knot_db_t *db)
 }
 
 /** Obtain a read-only cursor (and a read-only transaction). */
-static int txn_curs_get(struct lmdb_env *env, MDB_cursor **curs)
+static int txn_curs_get(struct lmdb_env *env, MDB_cursor **curs, struct kr_cdb_stats *stats)
 {
        assert(env && curs);
        if (env->txn.ro_curs_active) {
@@ -209,7 +211,7 @@ static int txn_curs_get(struct lmdb_env *env, MDB_cursor **curs)
        }
        /* Only in a read-only txn; TODO: it's a bit messy/coupled */
        if (env->txn.rw) {
-               int ret = cdb_commit(env);
+               int ret = cdb_commit(env, stats);
                if (ret) return ret;
        }
        MDB_txn *txn = NULL;
@@ -244,22 +246,23 @@ static void free_txn_ro(struct lmdb_env *env)
 }
 
 /*! \brief Close the database. */
-static void cdb_close_env(struct lmdb_env *env)
+static void cdb_close_env(struct lmdb_env *env, struct kr_cdb_stats *stats)
 {
        assert(env && env->env);
 
        /* Get rid of any transactions. */
-       cdb_commit(env);
+       cdb_commit(env, stats);
        free_txn_ro(env);
 
        mdb_env_sync(env->env, 1);
+       stats->close++;
        mdb_dbi_close(env->env, env->dbi);
        mdb_env_close(env->env);
        memset(env, 0, sizeof(*env));
 }
 
 /*! \brief Open database environment. */
-static int cdb_open_env(struct lmdb_env *env, unsigned flags, const char *path, size_t mapsize)
+static int cdb_open_env(struct lmdb_env *env, unsigned flags, const char *path, size_t mapsize, struct kr_cdb_stats *stats)
 {
        int ret = mkdir(path, LMDB_DIR_MODE);
        if (ret == -1 && errno != EEXIST) {
@@ -267,6 +270,7 @@ static int cdb_open_env(struct lmdb_env *env, unsigned flags, const char *path,
        }
 
        MDB_env *mdb_env = NULL;
+       stats->open++;
        ret = mdb_env_create(&mdb_env);
        if (ret != MDB_SUCCESS) {
                return lmdb_error(ret);
@@ -274,12 +278,14 @@ static int cdb_open_env(struct lmdb_env *env, unsigned flags, const char *path,
 
        ret = set_mapsize(mdb_env, mapsize);
        if (ret != 0) {
+               stats->close++;
                mdb_env_close(mdb_env);
                return ret;
        }
 
        ret = mdb_env_open(mdb_env, path, flags, LMDB_FILE_MODE);
        if (ret != MDB_SUCCESS) {
+               stats->close++;
                mdb_env_close(mdb_env);
                return lmdb_error(ret);
        }
@@ -290,12 +296,13 @@ static int cdb_open_env(struct lmdb_env *env, unsigned flags, const char *path,
        return 0;
 }
 
-static int cdb_open(struct lmdb_env *env, const char *path, size_t mapsize)
+static int cdb_open(struct lmdb_env *env, const char *path, size_t mapsize,
+               struct kr_cdb_stats *stats)
 {
        /* Cache doesn't require durability, we can be
         * loose with the requirements as a tradeoff for speed. */
        const unsigned flags = MDB_WRITEMAP | MDB_MAPASYNC | MDB_NOTLS;
-       int ret = cdb_open_env(env, flags, path, mapsize);
+       int ret = cdb_open_env(env, flags, path, mapsize, stats);
        if (ret != 0) {
                return ret;
        }
@@ -304,6 +311,7 @@ static int cdb_open(struct lmdb_env *env, const char *path, size_t mapsize)
        MDB_txn *txn = NULL;
        ret = mdb_txn_begin(env->env, NULL, 0, &txn);
        if (ret != MDB_SUCCESS) {
+               stats->close++;
                mdb_env_close(env->env);
                return lmdb_error(ret);
        }
@@ -311,12 +319,15 @@ static int cdb_open(struct lmdb_env *env, const char *path, size_t mapsize)
        ret = mdb_dbi_open(txn, NULL, 0, &env->dbi);
        if (ret != MDB_SUCCESS) {
                mdb_txn_abort(txn);
+               stats->close++;
                mdb_env_close(env->env);
                return lmdb_error(ret);
        }
 
+       stats->commit++;
        ret = mdb_txn_commit(txn);
        if (ret != MDB_SUCCESS) {
+               stats->close++;
                mdb_env_close(env->env);
                return lmdb_error(ret);
        }
@@ -324,9 +335,10 @@ static int cdb_open(struct lmdb_env *env, const char *path, size_t mapsize)
        return 0;
 }
 
-static int cdb_init(knot_db_t **db, struct kr_cdb_opts *opts, knot_mm_t *pool)
+static int cdb_init(knot_db_t **db, struct kr_cdb_stats *stats,
+               struct kr_cdb_opts *opts, knot_mm_t *pool)
 {
-       if (!db || !opts) {
+       if (!db || !stats || !opts) {
                return kr_error(EINVAL);
        }
 
@@ -348,7 +360,7 @@ static int cdb_init(knot_db_t **db, struct kr_cdb_opts *opts, knot_mm_t *pool)
        }
 
        /* Open the database. */
-       int ret = cdb_open(env, opts->path, opts->maxsize);
+       int ret = cdb_open(env, opts->path, opts->maxsize, stats);
        if (ret != 0) {
                free(env);
                return ret;
@@ -358,14 +370,14 @@ static int cdb_init(knot_db_t **db, struct kr_cdb_opts *opts, knot_mm_t *pool)
        return 0;
 }
 
-static void cdb_deinit(knot_db_t *db)
+static void cdb_deinit(knot_db_t *db, struct kr_cdb_stats *stats)
 {
        struct lmdb_env *env = db;
-       cdb_close_env(env);
+       cdb_close_env(env, stats);
        free(env);
 }
 
-static int cdb_count(knot_db_t *db)
+static int cdb_count(knot_db_t *db, struct kr_cdb_stats *stats)
 {
        struct lmdb_env *env = db;
        MDB_txn *txn = NULL;
@@ -375,14 +387,16 @@ static int cdb_count(knot_db_t *db)
        }
 
        MDB_stat stat;
+       stats->count++;
        ret = mdb_stat(txn, env->dbi, &stat);
 
        return (ret == MDB_SUCCESS) ? stat.ms_entries : lmdb_error(ret);
 }
 
-static int cdb_clear(knot_db_t *db)
+static int cdb_clear(knot_db_t *db, struct kr_cdb_stats *stats)
 {
        struct lmdb_env *env = db;
+       stats->clear++;
        /* First try mdb_drop() to clear the DB; this may fail with ENOSPC. */
        /* If we didn't do this, explicit cache.clear() ran on an instance
         * would lead to the instance detaching from the cache of others,
@@ -394,7 +408,7 @@ static int cdb_clear(knot_db_t *db)
                if (ret == kr_ok()) {
                        ret = lmdb_error(mdb_drop(txn, env->dbi, 0));
                        if (ret == kr_ok()) {
-                               ret = cdb_commit(db);
+                               ret = cdb_commit(db, stats);
                        }
                        if (ret == kr_ok()) {
                                return ret;
@@ -404,7 +418,7 @@ static int cdb_clear(knot_db_t *db)
        }
 
        /* We are about to switch to a different file, so end all txns, to be sure. */
-       (void) cdb_commit(db);
+       (void) cdb_commit(db, stats);
        free_txn_ro(db);
 
        /* Since there is no guarantee that there will be free
@@ -460,15 +474,15 @@ static int cdb_clear(knot_db_t *db)
        /* Keep copy as it points to current handle internals. */
        auto_free char *path_copy = strdup(path);
        size_t mapsize = env->mapsize;
-       cdb_close_env(env);
-       ret = cdb_open(env, path_copy, mapsize);
+       cdb_close_env(env, stats);
+       ret = cdb_open(env, path_copy, mapsize, stats);
        /* Environment updated, release lockfile. */
        unlink(lockfile);
        return ret;
 }
 
-static int cdb_readv(knot_db_t *db, const knot_db_val_t *key, knot_db_val_t *val,
-                    int maxcount)
+static int cdb_readv(knot_db_t *db, struct kr_cdb_stats *stats,
+               const knot_db_val_t *key, knot_db_val_t *val, int maxcount)
 {
        struct lmdb_env *env = db;
        MDB_txn *txn = NULL;
@@ -481,8 +495,11 @@ static int cdb_readv(knot_db_t *db, const knot_db_val_t *key, knot_db_val_t *val
                /* Convert key structs */
                MDB_val _key = val_knot2mdb(key[i]);
                MDB_val _val = val_knot2mdb(val[i]);
+               stats->read++;
                ret = mdb_get(txn, env->dbi, &_key, &_val);
                if (ret != MDB_SUCCESS) {
+                       if (ret == MDB_NOTFOUND)
+                               stats->read_miss++;
                        ret = lmdb_error(ret);
                        if (ret == kr_error(ENOSPC)) {
                                /* we're likely to be forced to cache clear anyway */
@@ -497,20 +514,23 @@ static int cdb_readv(knot_db_t *db, const knot_db_val_t *key, knot_db_val_t *val
 }
 
 static int cdb_write(struct lmdb_env *env, MDB_txn **txn, const knot_db_val_t *key,
-                       knot_db_val_t *val, unsigned flags)
+                       knot_db_val_t *val, unsigned flags,
+                       struct kr_cdb_stats *stats)
 {
        /* Convert key structs and write */
        MDB_val _key = val_knot2mdb(*key);
        MDB_val _val = val_knot2mdb(*val);
+       stats->write++;
        int ret = mdb_put(*txn, env->dbi, &_key, &_val, flags);
 
        /* Try to recover from doing too much writing in a single transaction. */
        if (ret == MDB_TXN_FULL) {
-               ret = cdb_commit(env);
+               ret = cdb_commit(env, stats);
                if (ret) {
                        ret = txn_get(env, txn, false);
                }
                if (ret) {
+                       stats->write++;
                        ret = mdb_put(*txn, env->dbi, &_key, &_val, flags);
                }
        }
@@ -524,8 +544,8 @@ static int cdb_write(struct lmdb_env *env, MDB_txn **txn, const knot_db_val_t *k
        return kr_ok();
 }
 
-static int cdb_writev(knot_db_t *db, const knot_db_val_t *key, knot_db_val_t *val,
-                       int maxcount)
+static int cdb_writev(knot_db_t *db, struct kr_cdb_stats *stats,
+               const knot_db_val_t *key, knot_db_val_t *val, int maxcount)
 {
        struct lmdb_env *env = db;
        MDB_txn *txn = NULL;
@@ -541,13 +561,14 @@ static int cdb_writev(knot_db_t *db, const knot_db_val_t *key, knot_db_val_t *va
                if (val[i].len > 0 && val[i].data == NULL) {
                        mdb_flags |= MDB_RESERVE;
                }
-               ret = cdb_write(env, &txn, &key[i], &val[i], mdb_flags);
+               ret = cdb_write(env, &txn, &key[i], &val[i], mdb_flags, stats);
        }
 
        return ret;
 }
 
-static int cdb_remove(knot_db_t *db, knot_db_val_t keys[], int maxcount)
+static int cdb_remove(knot_db_t *db, struct kr_cdb_stats *stats,
+               knot_db_val_t keys[], int maxcount)
 {
        struct lmdb_env *env = db;
        MDB_txn *txn = NULL;
@@ -557,17 +578,21 @@ static int cdb_remove(knot_db_t *db, knot_db_val_t keys[], int maxcount)
        for (int i = 0; ret == kr_ok() && i < maxcount; ++i) {
                MDB_val _key = val_knot2mdb(keys[i]);
                MDB_val val = { 0, NULL };
+               stats->remove++;
                ret = lmdb_error(mdb_del(txn, env->dbi, &_key, &val));
                if (ret == kr_ok())
                        deleted++;
-               else if (ret == KNOT_ENOENT)
+               else if (ret == KNOT_ENOENT) {
+                       stats->remove_miss++;
                        ret = kr_ok();  /* skip over non-existing entries */
+               }
        }
 
        return ret < 0 ? ret : deleted;
 }
 
-static int cdb_match(knot_db_t *db, knot_db_val_t *key, knot_db_val_t keyval[][2], int maxcount)
+static int cdb_match(knot_db_t *db, struct kr_cdb_stats *stats,
+               knot_db_val_t *key, knot_db_val_t keyval[][2], int maxcount)
 {
        struct lmdb_env *env = db;
        MDB_txn *txn = NULL;
@@ -585,6 +610,7 @@ static int cdb_match(knot_db_t *db, knot_db_val_t *key, knot_db_val_t keyval[][2
 
        MDB_val cur_key = val_knot2mdb(*key);
        MDB_val cur_val = { 0, NULL };
+       stats->match++;
        ret = mdb_cursor_get(cur, &cur_key, &cur_val, MDB_SET_RANGE);
        if (ret != MDB_SUCCESS) {
                mdb_cursor_close(cur);
@@ -605,34 +631,49 @@ static int cdb_match(knot_db_t *db, knot_db_val_t *key, knot_db_val_t keyval[][2
                } else {
                        break;
                }
+               stats->match++;
                ret = mdb_cursor_get(cur, &cur_key, &cur_val, MDB_NEXT);
        }
+       if (results == 0)
+               stats->match_miss++;
+
 
        mdb_cursor_close(cur);
        return results;
 }
 
 
-static int cdb_read_leq(knot_db_t *env, knot_db_val_t *key, knot_db_val_t *val)
+static int cdb_read_leq(knot_db_t *env, struct kr_cdb_stats *stats,
+               knot_db_val_t *key, knot_db_val_t *val)
 {
        assert(env && key && key->data && val);
        MDB_cursor *curs = NULL;
-       int ret = txn_curs_get(env, &curs);
+       int ret = txn_curs_get(env, &curs, stats);
        if (ret) return ret;
 
        MDB_val key2_m = val_knot2mdb(*key);
        MDB_val val2_m = { 0, NULL };
+       stats->read_leq++;
        ret = mdb_cursor_get(curs, &key2_m, &val2_m, MDB_SET_RANGE);
-       if (ret) return lmdb_error(ret);
+       if (ret) {
+               stats->read_leq_miss++;
+               return lmdb_error(ret);
+       }
        /* test for equality //:unlikely */
        if (key2_m.mv_size == key->len
            && memcmp(key2_m.mv_data, key->data, key->len) == 0) {
                ret = 0; /* equality */
                goto success;
        }
+       stats->read_leq_miss++;
+
        /* we must be greater than key; do one step to smaller */
+       stats->read_leq++;
        ret = mdb_cursor_get(curs, &key2_m, &val2_m, MDB_PREV);
-       if (ret) return lmdb_error(ret);
+       if (ret) {
+               stats->read_leq_miss++;
+               return lmdb_error(ret);
+       }
        ret = 1;
 success:
        /* finalize the output */
index a08f3553602df068c2d5265771659c6f98527607..d9dc4735f8e7df14d22b6cae396cfb685ff9bcf1 100644 (file)
@@ -394,7 +394,7 @@ int nsec3_src_synth(struct key *k, struct answer *ans, const knot_dname_t *clenc
 #define VERBOSE_MSG(qry, ...) QRVERBOSE((qry), "cach",  ## __VA_ARGS__)
 
 /** Shorthand for operations on cache backend */
-#define cache_op(cache, op, ...) (cache)->api->op((cache)->db, ## __VA_ARGS__)
+#define cache_op(cache, op, ...) (cache)->api->op((cache)->db, &(cache)->stats, ## __VA_ARGS__)
 
 
 static inline uint16_t get_uint16(const void *address)
index 6e6e7e563cce7a2bbff0223793c7ff7185a89a6f..45ea9edd9d81d9576bc3c6e2b2ecd3e262b2f95b 100644 (file)
@@ -25,7 +25,8 @@ local function test_stats()
        ok(cache.open(100 * MB), 'cache can be reopened')
        local s = cache.stats()
        is(type(s), 'table', 'stats returns a table')
-       same({s.hit, s.miss, s.insert, s.delete}, {0, 0, 0, 0}, 'stats returns correct fields')
+       -- Just checking the most useful fields
+       isnt(s.read and s.read_miss and s.write, nil, 'stats returns correct fields')
 end
 
 -- test if cache can be resized or shrunk
@@ -41,14 +42,15 @@ local function test_context_cache()
        local c = kres.context().cache
        is(type(c), 'cdata', 'context has a cache object')
        local s = c.stats
-       same({s.hit, s.miss, s.insert, s.delete}, {0, 0, 0, 0}, 'context cache stats works')
+       isnt(s.read and s.read_miss and s.write, 'context cache stats works')
        -- insert a record into cache
        local rdata = '\1\2\3\4'
        local rr = kres.rrset('\3com\0', kres.type.A, kres.class.IN, 66)
        rr:add_rdata(rdata, #rdata)
+       local s_write = s.write
        ok(c:insert(rr, nil, 0, 0), 'cache insertion works')
-       ok(c:sync(), 'cache sync works')
-       same(s.insert, 1, 'cache insertion increments counters')
+       ok(c:commit(), 'cache commit works')
+       isnt(s.write, s_write, 'cache insertion increments counters')
 end
 
 return {
index 2a9c7de5377ed62f2569dcdb250fee44035776f4..7ec9d93e05cf40fdeee58bc6f8bbdd3ddb216115 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 2a9c7de5377ed62f2569dcdb250fee44035776f4
+Subproject commit 7ec9d93e05cf40fdeee58bc6f8bbdd3ddb216115