Verified Commit ecdfbe7e authored by Grigorii Demidov's avatar Grigorii Demidov Committed by Petr Špaček

lib/nsrep: when timeout occurs and NS has no cached RTT yet, don't mark it as timeouted

parent 26587875
......@@ -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)
......
......@@ -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;
......
......@@ -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);
}
......
/* 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 @@ KR_EXPORT void * lru_get_impl(struct lru *lru, const char *key, uint key_len,
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]);
}
/* 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
......@@ -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;
......
......@@ -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;
}
......
......@@ -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. */
};
/**
......
......@@ -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;
}
......
......@@ -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;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment