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)
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, *
}
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];
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;
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
}
/** @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);
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;
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
*/
#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.
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;
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;
/* 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;
}
/**
* 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.
/**
* 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. */
};
/**
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;
}
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;
}
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;
}