From: Grigorii Demidov Date: Mon, 12 Mar 2018 11:02:18 +0000 (+0100) Subject: lib/nsrep: when timeout occurs and NS has no cached RTT yet, don't mark it as timeouted X-Git-Tag: v2.2.0~1^2~6 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ecdfbe7e99f43f2312018344a37bc58c7b287c22;p=thirdparty%2Fknot-resolver.git lib/nsrep: when timeout occurs and NS has no cached RTT yet, don't mark it as timeouted --- diff --git a/bench/bench_lru.c b/bench/bench_lru.c index 9c850dc74..63bbeebdb 100644 --- a/bench/bench_lru.c +++ b/bench/bench_lru.c @@ -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) diff --git a/daemon/worker.c b/daemon/worker.c index df97b39cc..f7e8d83dd 100644 --- a/daemon/worker.c +++ b/daemon/worker.c @@ -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; diff --git a/lib/cookies/lru_cache.c b/lib/cookies/lru_cache.c index 19b6e5a8b..8ea97aba0 100644 --- a/lib/cookies/lru_cache.c +++ b/lib/cookies/lru_cache.c @@ -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); } diff --git a/lib/generic/lru.c b/lib/generic/lru.c index 3717d2d4d..640fef0e7 100644 --- a/lib/generic/lru.c +++ b/lib/generic/lru.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2017 CZ.NIC, z.s.p.o. +/* Copyright (C) 2016-2018 CZ.NIC, z.s.p.o. 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]); } diff --git a/lib/generic/lru.h b/lib/generic/lru.h index 05a371115..37b494625 100644 --- a/lib/generic/lru.h +++ b/lib/generic/lru.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2017 CZ.NIC, z.s.p.o. +/* Copyright (C) 2016-2018 CZ.NIC, z.s.p.o. 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 @@ -118,7 +118,7 @@ */ #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). @@ -126,12 +126,14 @@ * @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; diff --git a/lib/nsrep.c b/lib/nsrep.c index 7bdabbbd0..b14c0d467 100644 --- a/lib/nsrep.c +++ b/lib/nsrep.c @@ -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; } diff --git a/lib/nsrep.h b/lib/nsrep.h index 26d9fdf89..5c62936d1 100644 --- a/lib/nsrep.h +++ b/lib/nsrep.h @@ -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. */ }; /** diff --git a/modules/stats/stats.c b/modules/stats/stats.c index 6b87137a7..7fd48edfd 100644 --- a/modules/stats/stats.c +++ b/modules/stats/stats.c @@ -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; } diff --git a/tests/test_lru.c b/tests/test_lru.c index 4f0d282a1..eaa15390d 100644 --- a/tests/test_lru.c +++ b/tests/test_lru.c @@ -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; }