]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
lib/nsrep: when timeout occurs and NS has no cached RTT yet, don't mark it as timeouted
authorGrigorii Demidov <grigorii.demidov@nic.cz>
Mon, 12 Mar 2018 11:02:18 +0000 (12:02 +0100)
committerPetr Špaček <petr.spacek@nic.cz>
Wed, 28 Mar 2018 09:15:23 +0000 (11:15 +0200)
bench/bench_lru.c
daemon/worker.c
lib/cookies/lru_cache.c
lib/generic/lru.c
lib/generic/lru.h
lib/nsrep.c
lib/nsrep.h
modules/stats/stats.c
tests/test_lru.c

index 9c850dc74a680b42f45875885f0f915442be0d75..63bbeebdbfa5568ebb836bc1a67c9672a45720b7 100644 (file)
@@ -212,7 +212,7 @@ int main(int argc, char ** argv)
        p_err("\nload everything:\t");
        time_get(&time);
        for (size_t i = 0, ki = key_count - 1; i < run_count; ++i, --ki) {
-               unsigned *r = lru_get_new(lru, keys[ki].chars, keys[ki].len);
+               unsigned *r = lru_get_new(lru, keys[ki].chars, keys[ki].len, NULL);
                if (!r || *r == 0)
                        ++miss;
                if (r)
index df97b39cc2c32f50fd057b20742a5fbb58f494f4..f7e8d83dd1a6b049b57eb744b3d7c21e57ebd42d 100644 (file)
@@ -1078,7 +1078,8 @@ static int session_tls_hs_cb(struct session *session, int status)
 
        if (status) {
                kr_nsrep_update_rtt(NULL, &peer->ip, KR_NS_DEAD,
-                                   worker->engine->resolver.cache_rtt, KR_NS_UPDATE);
+                                   worker->engine->resolver.cache_rtt,
+                                   KR_NS_UPDATE_NORESET);
        } else {
                if (deletion_res != 0) {
                        /* session isn't in list of waiting queries, *
@@ -1245,7 +1246,8 @@ static void on_tcp_connect_timeout(uv_timer_t *timer)
        }
 
        kr_nsrep_update_rtt(NULL, &peer->ip, KR_NS_DEAD,
-                           worker->engine->resolver.cache_rtt, KR_NS_UPDATE);
+                           worker->engine->resolver.cache_rtt,
+                           KR_NS_UPDATE_NORESET);
 
        while (session->waiting.len > 0) {
                struct qr_task *task = session->waiting.at[0];
@@ -1328,7 +1330,8 @@ static void on_udp_timeout(uv_timer_t *timer)
                                VERBOSE_MSG(qry, "=> server: '%s' flagged as 'bad'\n", addr_str);
                        }
                        kr_nsrep_update_rtt(&qry->ns, choice, KR_NS_DEAD,
-                                           worker->engine->resolver.cache_rtt, KR_NS_UPDATE);
+                                           worker->engine->resolver.cache_rtt,
+                                           KR_NS_UPDATE_NORESET);
                }
        }
        task->timeouts += 1;
index 19b6e5a8b87d7245c067cf8ef73c8c05fc0df83e..8ea97aba06641a6fe5ded50eb4f891cae32bc0c8 100644 (file)
@@ -61,7 +61,7 @@ int kr_cookie_lru_set(kr_cookie_lru_t *cache, const struct sockaddr *sa,
                return kr_error(EINVAL);
        }
 
-       struct cookie_opt_data *cached = lru_get_new(cache, addr, addr_len);
+       struct cookie_opt_data *cached = lru_get_new(cache, addr, addr_len, NULL);
        if (cached) {
                memcpy(cached->opt_data, opt, opt_size);
        }
index 3717d2d4d6ce62c0455aae74a7bb56f907b33999..640fef0e7b43a21fad04ae8559e982d19aa269b9 100644 (file)
@@ -1,4 +1,4 @@
-/*  Copyright (C) 2016-2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+/*  Copyright (C) 2016-2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
 
     This program is free software: you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -131,9 +131,12 @@ static void group_inc_count(lru_group_t *g, int i) {
 }
 
 /** @internal Implementation of both getting and insertion.
- * Note: val_len is only meaningful if do_insert. */
+ * Note: val_len is only meaningful if do_insert.
+ *       *res is only meaningful when return value isn't NULL,
+ *      if return value is NULL, *res remains untouched.
+ */
 KR_EXPORT void * lru_get_impl(struct lru *lru, const char *key, uint key_len,
-                               uint val_len, bool do_insert)
+                             uint val_len, bool do_insert, bool *res)
 {
        bool ok = lru && (key || !key_len) && key_len <= UINT16_MAX
                   && (!do_insert || val_len <= UINT16_MAX);
@@ -141,6 +144,7 @@ KR_EXPORT void * lru_get_impl(struct lru *lru, const char *key, uint key_len,
                assert(false);
                return NULL; // reasonable fallback when not debugging
        }
+       bool is_new_entry = false;
        // find the right group
        uint32_t khash = hash(key, key_len);
        uint16_t khash_top = khash >> 16;
@@ -204,9 +208,13 @@ insert: // insert into position i (incl. key)
                memcpy(it->data, key, key_len);
        }
        memset(item_val(it), 0, val_len); // clear the value
+       is_new_entry = true;
 found: // key and hash OK on g->items[i]; now update stamps
        assert(i < LRU_ASSOC);
        group_inc_count(g, i);
+       if (res) {
+               *res = is_new_entry;
+       }
        return item_val(g->items[i]);
 }
 
index 05a371115bb3fa89a907c8c33311ae7c459390ff..37b4946251f837f335313eabfd73d7029199299c 100644 (file)
@@ -1,4 +1,4 @@
-/*  Copyright (C) 2016-2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+/*  Copyright (C) 2016-2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
 
     This program is free software: you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
  */
 #define lru_get_try(table, key_, len_) \
        (__typeof__((table)->pdata_t)) \
-               lru_get_impl(&(table)->lru, (key_), (len_), -1, false)
+               lru_get_impl(&(table)->lru, (key_), (len_), -1, false, NULL)
 
 /**
  * @brief Return pointer to value, inserting if needed (zeroed).
  * @param table pointer to LRU
  * @param key_ lookup key
  * @param len_ key lengthkeys
+ * @param res  pointer to bool to store result of operation
+ *             (true if entry is newly added, false otherwise; can be NULL).
  * @return pointer to data or NULL (can be even if memory could be allocated!)
  */
-#define lru_get_new(table, key_, len_) \
+#define lru_get_new(table, key_, len_, res) \
        (__typeof__((table)->pdata_t)) \
-               lru_get_impl(&(table)->lru, (key_), (len_), sizeof(*(table)->pdata_t), true)
-
+               lru_get_impl(&(table)->lru, (key_), (len_), \
+               sizeof(*(table)->pdata_t), true, res)
 
 /**
  * @brief Apply a function to every item in LRU.
@@ -189,7 +191,7 @@ struct lru;
 void lru_free_items_impl(struct lru *lru);
 struct lru * lru_create_impl(uint max_slots, knot_mm_t *mm_array, knot_mm_t *mm);
 void * lru_get_impl(struct lru *lru, const char *key, uint key_len,
-                       uint val_len, bool do_insert);
+                   uint val_len, bool do_insert, bool *res);
 void lru_apply_impl(struct lru *lru, lru_apply_fun f, void *baton);
 
 struct lru_item;
index 7bdabbbd0461efc203ae035802130ac6ac534d4c..b14c0d4672b6b1e5a55b8def20a3309ea75d4f9a 100644 (file)
@@ -305,21 +305,30 @@ int kr_nsrep_update_rtt(struct kr_nsrep *ns, const struct sockaddr *addr,
 
        assert(addr_in != NULL && addr_len > 0);
 
-       unsigned *cur = lru_get_new(cache, addr_in, addr_len);
+       bool is_new_entry = false;
+       unsigned *cur = lru_get_new(cache, addr_in, addr_len, (&is_new_entry));
        if (!cur) {
                return kr_ok();
        }
        if (score <= KR_NS_GLUED) {
                score = KR_NS_GLUED + 1;
        }
-       /* First update is always set. */
-       if (*cur == 0) {
-               umode = KR_NS_RESET;
+       /* First update is always set unless KR_NS_UPDATE_NORESET mode used. */
+       if (is_new_entry) {
+               if (umode == KR_NS_UPDATE_NORESET) {
+                       /* Zero initial value. */
+                       *cur = 0;
+               } else {
+                       /* Force KR_NS_RESET otherwise. */
+                       umode = KR_NS_RESET;
+               }
        }
        unsigned new_score = 0;
        /* Update score, by default smooth over last two measurements. */
        switch (umode) {
-       case KR_NS_UPDATE: new_score = (*cur + score) / 2; break;
+       case KR_NS_UPDATE:
+       case KR_NS_UPDATE_NORESET:
+               new_score = (*cur + score) / 2; break;
        case KR_NS_RESET:  new_score = score; break;
        case KR_NS_ADD:    new_score = MIN(KR_NS_MAX_SCORE - 1, *cur + score); break;
        case KR_NS_MAX:    new_score = MAX(*cur, score); break;
@@ -342,7 +351,8 @@ int kr_nsrep_update_rep(struct kr_nsrep *ns, unsigned reputation, kr_nsrep_lru_t
        /* Store in the struct */
        ns->reputation = reputation;
        /* Store reputation in the LRU cache */
-       unsigned *cur = lru_get_new(cache, (const char *)ns->name, knot_dname_size(ns->name));
+       unsigned *cur = lru_get_new(cache, (const char *)ns->name,
+                                   knot_dname_size(ns->name), NULL);
        if (cur) {
                *cur = reputation;
        }
index 26d9fdf894ce94f4a2c33674c25ca509ed27a0ea..5c62936d16f732434ed6b94f9c7f3ed0091b1682 100644 (file)
@@ -43,7 +43,7 @@ enum kr_ns_score {
 /**
  *  See kr_nsrep_update_rtt()
  */
-#define KR_NS_DEAD ((KR_NS_TIMEOUT * 4) / 3)
+#define KR_NS_DEAD (((KR_NS_TIMEOUT * 4) + 3) / 3)
 
 /**
  * NS QoS flags.
@@ -56,12 +56,17 @@ enum kr_ns_rep {
 
 /**
  * NS RTT update modes.
+ * First update is always KR_NS_RESET unless
+ * KR_NS_UPDATE_NORESET mode had choosen.
  */
 enum kr_ns_update_mode {
-       KR_NS_UPDATE = 0, /**< Update as smooth over last two measurements */
-       KR_NS_RESET,      /**< Set to given value */
-       KR_NS_ADD,        /**< Increment current value */
-       KR_NS_MAX         /**< Set to maximum of current/proposed value. */
+       KR_NS_UPDATE = 0,     /**< Update as smooth over last two measurements */
+       KR_NS_UPDATE_NORESET, /**< Same as KR_NS_UPDATE, but disable fallback to
+                              *   KR_NS_RESET on newly added entries.
+                              *   Zero is used as initial value. */
+       KR_NS_RESET,          /**< Set to given value */
+       KR_NS_ADD,            /**< Increment current value */
+       KR_NS_MAX             /**< Set to maximum of current/proposed value. */
 };
 
 /**
index 6b87137a779662e1d3e469d9618abdbfd5658a97..7fd48edfda974a0a6cb5cf4030a84aee236cec33 100644 (file)
@@ -146,7 +146,7 @@ static void collect_sample(struct stat_data *data, struct kr_rplan *rplan, knot_
                                assert(false);
                                continue;
                        }
-                       unsigned *count = lru_get_new(data->queries.frequent, key, key_len);
+                       unsigned *count = lru_get_new(data->queries.frequent, key, key_len, NULL);
                        if (count)
                                *count += 1;
                }
index 4f0d282a1c16dd8f00ec1110148f49343d155e1f..eaa15390d3dc8cf299af5f316ebce1e21d4d8084 100644 (file)
@@ -61,7 +61,7 @@ static void test_insert(void **state)
        int i;
 
        for (i = 0; i < dict_size; i++) {
-               int *data = lru_get_new(lru, dict[i], KEY_LEN(dict[i]));
+               int *data = lru_get_new(lru, dict[i], KEY_LEN(dict[i]), NULL);
                if (!data) {
                        continue;
                }
@@ -83,7 +83,7 @@ static void test_eviction(void **state)
        char key[16];
        for (unsigned i = 0; i < HASH_SIZE; ++i) {
                test_randstr(key, sizeof(key));
-               int *data = lru_get_new(lru, key, sizeof(key));
+               int *data = lru_get_new(lru, key, sizeof(key), NULL);
                if (!data) {
                        continue;
                }