]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
add a metric about the maximum number of collisions in lrushah 826/head
authorSergey Kacheev <s.kacheev@gmail.com>
Fri, 13 Jan 2023 06:33:38 +0000 (13:33 +0700)
committerSergey Kacheev <s.kacheev@gmail.com>
Fri, 13 Jan 2023 06:33:38 +0000 (13:33 +0700)
daemon/remote.c
daemon/stats.c
libunbound/unbound.h
smallapp/unbound-control.c
testcode/unitlruhash.c
util/storage/lruhash.c
util/storage/lruhash.h
util/storage/slabhash.c
util/storage/slabhash.h

index 7c5a036f343d314c5ef68a189cb46de1cc34d998..309d46ae93292679a0a8a14e6572e8f7522187ac 100644 (file)
@@ -1065,6 +1065,11 @@ print_ext(RES* ssl, struct ub_stats_info* s, int inhibit_zero)
                (unsigned)s->svr.infra_cache_count)) return 0;
        if(!ssl_printf(ssl, "key.cache.count"SQ"%u\n",
                (unsigned)s->svr.key_cache_count)) return 0;
+       /* max collisions */
+       if(!ssl_printf(ssl, "msg.cache.max_collisions"SQ"%u\n",
+               (unsigned)s->svr.msg_cache_max_collisions)) return 0;
+       if(!ssl_printf(ssl, "rrset.cache.max_collisions"SQ"%u\n",
+               (unsigned)s->svr.rrset_cache_max_collisions)) return 0;
        /* applied RPZ actions */
        for(i=0; i<UB_STATS_RPZ_ACTION_NUM; i++) {
                if(i == RPZ_NO_OVERRIDE_ACTION)
index 6b3834977844d8b87e9e66e4f81e50f3e502270b..c00c16be395e352b2d473d0cf39826a14a01d32b 100644 (file)
@@ -293,8 +293,10 @@ server_stats_compile(struct worker* worker, struct ub_stats_info* s, int reset)
        s->svr.queries_ratelimited = (long long)get_queries_ratelimit(worker, reset);
 
        /* get cache sizes */
-       s->svr.msg_cache_count = (long long)count_slabhash_entries(worker->env.msg_cache);
-       s->svr.rrset_cache_count = (long long)count_slabhash_entries(&worker->env.rrset_cache->table);
+       get_slabhash_stats(worker->env.msg_cache,
+               &s->svr.msg_cache_count, &s->svr.msg_cache_max_collisions);
+       get_slabhash_stats(&worker->env.rrset_cache->table,
+               &s->svr.rrset_cache_count, &s->svr.rrset_cache_max_collisions);
        s->svr.infra_cache_count = (long long)count_slabhash_entries(worker->env.infra_cache->hosts);
        if(worker->env.key_cache)
                s->svr.key_cache_count = (long long)count_slabhash_entries(worker->env.key_cache->slab);
index c779d183e38561b02954a6bfe39d0c9b533c14cf..221ef7f9d4b76f9252e1adf016779ab898c36017 100644 (file)
@@ -788,6 +788,11 @@ struct ub_server_stats {
        /** number of key cache entries */
        long long key_cache_count;
 
+       /** maximum number of collisions in the msg cache */
+       long long msg_cache_max_collisions;
+       /** maximum number of collisions in the rrset cache */
+       long long rrset_cache_max_collisions;
+
        /** number of queries that used dnscrypt */
        long long num_query_dnscrypt_crypted;
        /** number of queries that queried dnscrypt certificates */
index 821c490c3e8f09f6f39fab7173d5be71c389e91e..bae8e4e7640d2242a44c6f2574a44dc40e7991d8 100644 (file)
@@ -403,6 +403,9 @@ static void print_extended(struct ub_stats_info* s, int inhibit_zero)
        PR_UL("rrset.cache.count", s->svr.rrset_cache_count);
        PR_UL("infra.cache.count", s->svr.infra_cache_count);
        PR_UL("key.cache.count", s->svr.key_cache_count);
+       /* max collisions */
+       PR_UL("msg.cache.max_collisions", s->svr.msg_cache_max_collisions);
+       PR_UL("rrset.cache.max_collisions", s->svr.rrset_cache_max_collisions);
        /* applied RPZ actions */
        for(i=0; i<UB_STATS_RPZ_ACTION_NUM; i++) {
                if(i == RPZ_NO_OVERRIDE_ACTION)
index e196f0b6321111f9a8f72e28ca266c63b2c43125..3c66d7583ed63b6183780842d3ec76c5977b3abb 100644 (file)
@@ -94,7 +94,7 @@ test_bin_find_entry(struct lruhash* table)
        bin_overflow_remove(&bin, &k->entry);
 
        /* find in empty list */
-       unit_assert( bin_find_entry(table, &bin, h, k) == NULL );
+       unit_assert( bin_find_entry(table, &bin, h, k, NULL) == NULL );
 
        /* insert */
        lock_quick_lock(&bin.lock);
@@ -102,20 +102,20 @@ test_bin_find_entry(struct lruhash* table)
        lock_quick_unlock(&bin.lock);
 
        /* find, hash not OK. */
-       unit_assert( bin_find_entry(table, &bin, myhash(13), k) == NULL );
+       unit_assert( bin_find_entry(table, &bin, myhash(13), k, NULL) == NULL );
 
        /* find, hash OK, but cmp not */
        unit_assert( k->entry.hash == k2->entry.hash );
-       unit_assert( bin_find_entry(table, &bin, h, k2) == NULL );
+       unit_assert( bin_find_entry(table, &bin, h, k2, NULL) == NULL );
 
        /* find, hash OK, and cmp too */
-       unit_assert( bin_find_entry(table, &bin, h, k) == &k->entry );
+       unit_assert( bin_find_entry(table, &bin, h, k, NULL) == &k->entry );
 
        /* remove the element */
        lock_quick_lock(&bin.lock);
        bin_overflow_remove(&bin, &k->entry);
        lock_quick_unlock(&bin.lock);
-       unit_assert( bin_find_entry(table, &bin, h, k) == NULL );
+       unit_assert( bin_find_entry(table, &bin, h, k, NULL) == NULL );
 
        /* prepend two different elements; so the list is long */
        /* one has the same hash, but different cmp */
@@ -127,28 +127,28 @@ test_bin_find_entry(struct lruhash* table)
        lock_quick_unlock(&bin.lock);
 
        /* find, hash not OK. */
-       unit_assert( bin_find_entry(table, &bin, myhash(13), k) == NULL );
+       unit_assert( bin_find_entry(table, &bin, myhash(13), k, NULL) == NULL );
 
        /* find, hash OK, but cmp not */
        unit_assert( k->entry.hash == k2->entry.hash );
-       unit_assert( bin_find_entry(table, &bin, h, k2) == NULL );
+       unit_assert( bin_find_entry(table, &bin, h, k2, NULL) == NULL );
 
        /* find, hash OK, and cmp too */
-       unit_assert( bin_find_entry(table, &bin, h, k) == &k->entry );
+       unit_assert( bin_find_entry(table, &bin, h, k, NULL) == &k->entry );
 
        /* remove middle element */
-       unit_assert( bin_find_entry(table, &bin, k4->entry.hash, k4
+       unit_assert( bin_find_entry(table, &bin, k4->entry.hash, k4, NULL)
                == &k4->entry );
        lock_quick_lock(&bin.lock);
        bin_overflow_remove(&bin, &k4->entry);
        lock_quick_unlock(&bin.lock);
-       unit_assert( bin_find_entry(table, &bin, k4->entry.hash, k4) == NULL);
+       unit_assert( bin_find_entry(table, &bin, k4->entry.hash, k4, NULL) == NULL);
 
        /* remove last element */
        lock_quick_lock(&bin.lock);
        bin_overflow_remove(&bin, &k->entry);
        lock_quick_unlock(&bin.lock);
-       unit_assert( bin_find_entry(table, &bin, h, k) == NULL );
+       unit_assert( bin_find_entry(table, &bin, h, k, NULL) == NULL );
 
        lock_quick_destroy(&bin.lock);
        delkey(k);
index 3500a4ef0fe894a1dfa6f421a9e523488c0e0c06..e17b180db8b8781a7c5ab3336499596895e409f3 100644 (file)
@@ -81,6 +81,7 @@ lruhash_create(size_t start_size, size_t maxmem,
        table->num = 0;
        table->space_used = 0;
        table->space_max = maxmem;
+       table->max_collisions = 0;
        table->array = calloc(table->size, sizeof(struct lruhash_bin));
        if(!table->array) {
                lock_quick_destroy(&table->lock);
@@ -216,15 +217,19 @@ reclaim_space(struct lruhash* table, struct lruhash_entry** list)
 
 struct lruhash_entry* 
 bin_find_entry(struct lruhash* table, 
-       struct lruhash_bin* bin, hashvalue_type hash, void* key)
+       struct lruhash_bin* bin, hashvalue_type hash, void* key, size_t* collisions)
 {
+       size_t c = 0;
        struct lruhash_entry* p = bin->overflow_list;
        while(p) {
                if(p->hash == hash && table->compfunc(p->key, key) == 0)
-                       return p;
+                       break;
+               c++;
                p = p->overflow_next;
        }
-       return NULL;
+       if (collisions != NULL)
+               *collisions = c;
+       return p;
 }
 
 void 
@@ -303,6 +308,7 @@ lruhash_insert(struct lruhash* table, hashvalue_type hash,
        struct lruhash_bin* bin;
        struct lruhash_entry* found, *reclaimlist=NULL;
        size_t need_size;
+       size_t collisions;
        fptr_ok(fptr_whitelist_hash_sizefunc(table->sizefunc));
        fptr_ok(fptr_whitelist_hash_delkeyfunc(table->delkeyfunc));
        fptr_ok(fptr_whitelist_hash_deldatafunc(table->deldatafunc));
@@ -317,12 +323,14 @@ lruhash_insert(struct lruhash* table, hashvalue_type hash,
        lock_quick_lock(&bin->lock);
 
        /* see if entry exists already */
-       if(!(found=bin_find_entry(table, bin, hash, entry->key))) {
+       if(!(found=bin_find_entry(table, bin, hash, entry->key, &collisions))) {
                /* if not: add to bin */
                entry->overflow_next = bin->overflow_list;
                bin->overflow_list = entry;
                lru_front(table, entry);
                table->num++;
+               if (table->max_collisions < collisions)
+                       table->max_collisions = collisions;
                table->space_used += need_size;
        } else {
                /* if so: update data - needs a writelock */
@@ -362,7 +370,7 @@ lruhash_lookup(struct lruhash* table, hashvalue_type hash, void* key, int wr)
        lock_quick_lock(&table->lock);
        bin = &table->array[hash & table->size_mask];
        lock_quick_lock(&bin->lock);
-       if((entry=bin_find_entry(table, bin, hash, key)))
+       if((entry=bin_find_entry(table, bin, hash, key, NULL)))
                lru_touch(table, entry);
        lock_quick_unlock(&table->lock);
 
@@ -389,7 +397,7 @@ lruhash_remove(struct lruhash* table, hashvalue_type hash, void* key)
        lock_quick_lock(&table->lock);
        bin = &table->array[hash & table->size_mask];
        lock_quick_lock(&bin->lock);
-       if((entry=bin_find_entry(table, bin, hash, key))) {
+       if((entry=bin_find_entry(table, bin, hash, key, NULL))) {
                bin_overflow_remove(bin, entry);
                lru_remove(table, entry);
        } else {
@@ -579,6 +587,7 @@ lruhash_insert_or_retrieve(struct lruhash* table, hashvalue_type hash,
        struct lruhash_bin* bin;
        struct lruhash_entry* found, *reclaimlist = NULL;
        size_t need_size;
+       size_t collisions;
        fptr_ok(fptr_whitelist_hash_sizefunc(table->sizefunc));
        fptr_ok(fptr_whitelist_hash_delkeyfunc(table->delkeyfunc));
        fptr_ok(fptr_whitelist_hash_deldatafunc(table->deldatafunc));
@@ -593,7 +602,7 @@ lruhash_insert_or_retrieve(struct lruhash* table, hashvalue_type hash,
        lock_quick_lock(&bin->lock);
 
        /* see if entry exists already */
-       if ((found = bin_find_entry(table, bin, hash, entry->key)) != NULL) {
+       if ((found = bin_find_entry(table, bin, hash, entry->key, &collisions)) != NULL) {
                /* if so: keep the existing data - acquire a writelock */
                lock_rw_wrlock(&found->lock);
        }
@@ -604,6 +613,8 @@ lruhash_insert_or_retrieve(struct lruhash* table, hashvalue_type hash,
                bin->overflow_list = entry;
                lru_front(table, entry);
                table->num++;
+               if (table->max_collisions < collisions)
+                       table->max_collisions = collisions;
                table->space_used += need_size;
                /* return the entry that was presented, and lock it */
                found = entry;
index 4759b5001231917e5c5e3cf443d53c946d97434a..2086e4dec93e6782c8555b79de93397afe319807 100644 (file)
@@ -178,6 +178,8 @@ struct lruhash {
        size_t space_used;
        /** the amount of space the hash table is maximally allowed to use. */
        size_t space_max;
+       /** the maximum collisions were detected during the lruhash_insert operations. */
+       size_t max_collisions;
 };
 
 /**
@@ -357,10 +359,11 @@ void bin_delete(struct lruhash* table, struct lruhash_bin* bin);
  * @param bin: hash bin to look into.
  * @param hash: hash value to look for.
  * @param key: key to look for.
+ * @param collisions: how many collisions were found during the search.
  * @return: the entry or NULL if not found.
  */
 struct lruhash_entry* bin_find_entry(struct lruhash* table, 
-       struct lruhash_bin* bin, hashvalue_type hash, void* key);
+       struct lruhash_bin* bin, hashvalue_type hash, void* key, size_t* collisions);
 
 /**
  * Remove entry from bin overflow chain.
index a6c3d0fa649097fac8ad8ba66ac080bf61c77bdc..7d376c4d684abb052300e4661107e327cb0fb6a5 100644 (file)
@@ -242,3 +242,21 @@ size_t count_slabhash_entries(struct slabhash* sh)
        }
        return cnt;
 }
+
+void get_slabhash_stats(struct slabhash* sh, long long* num, long long* collisions)
+{
+       size_t slab, cnt = 0, max_collisions = 0;
+
+       for(slab=0; slab<sh->size; slab++) {
+               lock_quick_lock(&sh->array[slab]->lock);
+               cnt += sh->array[slab]->num;
+               if (max_collisions < sh->array[slab]->max_collisions) {
+                       max_collisions = sh->array[slab]->max_collisions;
+               }
+               lock_quick_unlock(&sh->array[slab]->lock);
+       }
+       if (num != NULL)
+               *num = cnt;
+       if (collisions != NULL)
+               *collisions = max_collisions;
+}
index 4ecb604216783f2e8f35ff21e820889fe888b1cb..dc5fc3603294efe68a47c00286989c1abaa5d9d7 100644 (file)
@@ -200,6 +200,15 @@ void slabhash_traverse(struct slabhash* table, int wr,
  */
 size_t count_slabhash_entries(struct slabhash* table);
 
+/**
+ * Retrieves number of items in slabhash and the current max collision level
+ * @param table: slabbed hash table.
+ * @param entries_count: where to save the current number of elements.
+ * @param max_collisions: where to save the current max collisions level.
+ */
+void get_slabhash_stats(struct slabhash* table,
+       long long* entries_count, long long* max_collisions);
+
 /* --- test representation --- */
 /** test structure contains test key */
 struct slabhash_testkey {