]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
lib/nsrep: tuning of 'serve_stale' module
authorGrigorii Demidov <grigorii.demidov@nic.cz>
Mon, 19 Mar 2018 14:15:00 +0000 (15:15 +0100)
committerPetr Špaček <petr.spacek@nic.cz>
Wed, 28 Mar 2018 09:15:23 +0000 (11:15 +0200)
daemon/engine.c
lib/generic/lru.c
lib/generic/lru.h
lib/nsrep.c
lib/nsrep.h
lib/resolve.h
modules/serve_stale/serve_stale.lua

index 502bf046eef4e3da71e3eb91331e446f1a852866..4eb39946e8038360efa30ce54bea9df5e2a50ad5 100644 (file)
@@ -650,9 +650,10 @@ static int init_state(struct engine *engine)
 }
 
 static enum lru_apply_do update_stat_item(const char *key, uint len,
-                                               unsigned *rtt, void *baton)
+                                         kr_nsrep_rtt_lru_entry_t *rtt_cache_entry,
+                                         void *baton)
 {
-       return *rtt > KR_NS_LONG ? LRU_APPLY_DO_EVICT : LRU_APPLY_DO_NOTHING;
+       return rtt_cache_entry->score > KR_NS_LONG ? LRU_APPLY_DO_EVICT : LRU_APPLY_DO_NOTHING;
 }
 /** @internal Walk RTT table, clearing all entries with bad score
  *    to compensate for intermittent network issues or temporary bad behaviour. */
index 640fef0e7b43a21fad04ae8559e982d19aa269b9..c04f6f09fc49715fdbbe3fb9a2feb5407f191e1e 100644 (file)
@@ -132,11 +132,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.
- *       *res is only meaningful when return value isn't NULL,
- *      if return value is NULL, *res remains untouched.
+ *       *is_new is only meaningful when return value isn't NULL, contains
+ *      true when returned lru entry has been allocated right now
+ *      if return value is NULL, *is_new remains untouched.
  */
 KR_EXPORT void * lru_get_impl(struct lru *lru, const char *key, uint key_len,
-                             uint val_len, bool do_insert, bool *res)
+                             uint val_len, bool do_insert, bool *is_new)
 {
        bool ok = lru && (key || !key_len) && key_len <= UINT16_MAX
                   && (!do_insert || val_len <= UINT16_MAX);
@@ -212,8 +213,8 @@ insert: // insert into position i (incl. key)
 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;
+       if (is_new) {
+               *is_new = is_new_entry;
        }
        return item_val(g->items[i]);
 }
index 37b4946251f837f335313eabfd73d7029199299c..397e9bb4159ee83d6f7b5e74684fe0818373b8a4 100644 (file)
@@ -191,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, bool *res);
+                   uint val_len, bool do_insert, bool *is_new);
 void lru_apply_impl(struct lru *lru, lru_apply_fun f, void *baton);
 
 struct lru_item;
index b14c0d4672b6b1e5a55b8def20a3309ea75d4f9a..9be90e46a2e3df89d19cf33e3fa2c6556f4728dc 100644 (file)
@@ -82,8 +82,8 @@ static void update_nsrep_set(struct kr_nsrep *ns, const knot_dname_t *name, uint
 
 #undef ADDR_SET
 
-static unsigned eval_addr_set(pack_t *addr_set, kr_nsrep_lru_t *rttcache, unsigned score,
-                               uint8_t *addr[], struct kr_qflags opts)
+static unsigned eval_addr_set(pack_t *addr_set, kr_nsrep_rtt_lru_t *rtt_cache,
+                             unsigned score, uint8_t *addr[], struct kr_qflags opts)
 {
        /* Name server is better candidate if it has address record. */
        uint8_t *it = pack_head(*addr_set);
@@ -101,8 +101,24 @@ static unsigned eval_addr_set(pack_t *addr_set, kr_nsrep_lru_t *rttcache, unsign
                }
                /* Get RTT for this address (if known) */
                if (is_valid) {
-                       unsigned *cached = rttcache ? lru_get_try(rttcache, val, len) : NULL;
-                       unsigned addr_score = (cached) ? *cached : KR_NS_GLUED;
+                       kr_nsrep_rtt_lru_entry_t *cached = rtt_cache ?
+                                                          lru_get_try(rtt_cache, val, len) :
+                                                          NULL;
+                       unsigned addr_score = KR_NS_GLUED;
+                       if (cached) {
+                               uint64_t elapsed = kr_now() - cached->tout_timestamp;
+                               elapsed = elapsed > UINT_MAX ? UINT_MAX : elapsed;
+                               /* If NS once was marked as "timeouted",
+                                * it won't participate in NS elections
+                                * at least KR_NS_TIMEOUT_RETRY_INTERVAL milliseconds. */
+                               addr_score = cached->score;
+                               if (cached->score >= KR_NS_TIMEOUT &&
+                                   elapsed > KR_NS_TIMEOUT_RETRY_INTERVAL) {
+                                       addr_score = KR_NS_LONG - 1;
+                                       cached->score = addr_score;
+                                       cached->tout_timestamp = 0;
+                               }
+                       }
                        if (addr_score < score + favour) {
                                /* Shake down previous contenders */
                                for (size_t i = KR_NSREP_MAXADDR - 1; i > 0; --i)
@@ -128,7 +144,7 @@ static int eval_nsrep(const char *k, void *v, void *baton)
        /* Fetch NS reputation */
        if (ctx->cache_rep) {
                unsigned *cached = lru_get_try(ctx->cache_rep, k,
-                                       knot_dname_size((const uint8_t *)k));
+                                              knot_dname_size((const uint8_t *)k));
                if (cached) {
                        reputation = *cached;
                }
@@ -167,7 +183,7 @@ static int eval_nsrep(const char *k, void *v, void *baton)
        if (score >= KR_NS_TIMEOUT) {
                return kr_ok();
        } else if (score <= ns->score &&
-                  (score < KR_NS_LONG  || qry->flags.NO_THROTTLE)) {
+          (score < KR_NS_LONG  || qry->flags.NO_THROTTLE)) {
                update_nsrep_set(ns, (const knot_dname_t *)k, addr_choice, score);
                ns->reputation = reputation;
        } else if ((kr_rand_uint(100) < 10) &&
@@ -221,11 +237,11 @@ int kr_nsrep_set(struct kr_query *qry, size_t index, const struct sockaddr *sock
 
        /* Retrieve RTT from cache */
        struct kr_context *ctx = qry->ns.ctx;
-       unsigned *score = ctx
+       kr_nsrep_rtt_lru_entry_t *rtt_cache_entry = ctx
                ? lru_get_try(ctx->cache_rtt, kr_inaddr(sock), kr_family_len(sock->sa_family))
                : NULL;
-       if (score) {
-               qry->ns.score = MIN(qry->ns.score, *score);
+       if (rtt_cache_entry) {
+               qry->ns.score = MIN(qry->ns.score, rtt_cache_entry->score);
        }
 
        return kr_ok();
@@ -278,7 +294,7 @@ int kr_nsrep_elect_addr(struct kr_query *qry, struct kr_context *ctx)
 #undef ELECT_INIT
 
 int kr_nsrep_update_rtt(struct kr_nsrep *ns, const struct sockaddr *addr,
-                       unsigned score, kr_nsrep_lru_t *cache, int umode)
+                       unsigned score, kr_nsrep_rtt_lru_t *cache, int umode)
 {
        if (!cache || umode > KR_NS_MAX) {
                return kr_error(EINVAL);
@@ -306,7 +322,8 @@ int kr_nsrep_update_rtt(struct kr_nsrep *ns, const struct sockaddr *addr,
        assert(addr_in != NULL && addr_len > 0);
 
        bool is_new_entry = false;
-       unsigned *cur = lru_get_new(cache, addr_in, addr_len, (&is_new_entry));
+       kr_nsrep_rtt_lru_entry_t  *cur = lru_get_new(cache, addr_in, addr_len,
+                                                    (&is_new_entry));
        if (!cur) {
                return kr_ok();
        }
@@ -317,7 +334,7 @@ int kr_nsrep_update_rtt(struct kr_nsrep *ns, const struct sockaddr *addr,
        if (is_new_entry) {
                if (umode == KR_NS_UPDATE_NORESET) {
                        /* Zero initial value. */
-                       *cur = 0;
+                       cur->score = 0;
                } else {
                        /* Force KR_NS_RESET otherwise. */
                        umode = KR_NS_RESET;
@@ -328,17 +345,21 @@ int kr_nsrep_update_rtt(struct kr_nsrep *ns, const struct sockaddr *addr,
        switch (umode) {
        case KR_NS_UPDATE:
        case KR_NS_UPDATE_NORESET:
-               new_score = (*cur + score) / 2; break;
+               new_score = (cur->score + 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;
+       case KR_NS_ADD:    new_score = MIN(KR_NS_MAX_SCORE - 1, cur->score + score); break;
+       case KR_NS_MAX:    new_score = MAX(cur->score, score); break;
        default: break;
        }
        /* Score limits */
        if (new_score > KR_NS_MAX_SCORE) {
                new_score = KR_NS_MAX_SCORE;
        }
-       *cur = new_score;
+       if (new_score >= KR_NS_TIMEOUT && cur->score < KR_NS_TIMEOUT) {
+               /* Set the timestamp only when NS became "timeouted" */
+               cur->tout_timestamp = kr_now();
+       }
+       cur->score = new_score;
        return kr_ok();
 }
 
@@ -373,9 +394,9 @@ int kr_nsrep_copy_set(struct kr_nsrep *dst, const struct kr_nsrep *src)
        return kr_ok();
 }
 
-int kr_nsrep_sort(struct kr_nsrep *ns, kr_nsrep_lru_t *cache)
+int kr_nsrep_sort(struct kr_nsrep *ns, kr_nsrep_rtt_lru_t *rtt_cache)
 {
-       if (!ns || !cache) {
+       if (!ns || !rtt_cache) {
                assert(false);
                return kr_error(EINVAL);
        }
@@ -398,22 +419,24 @@ int kr_nsrep_sort(struct kr_nsrep *ns, kr_nsrep_lru_t *cache)
                if (sa->sa_family == AF_UNSPEC) {
                        break;
                }
-               unsigned *score = lru_get_try(cache, kr_inaddr(sa),
-                                               kr_family_len(sa->sa_family));
-               if (!score) {
+               kr_nsrep_rtt_lru_entry_t *rtt_cache_entry = lru_get_try(rtt_cache,
+                                                                       kr_inaddr(sa),
+                                                                       kr_family_len(sa->sa_family));
+               if (!rtt_cache_entry) {
                        scores[i] = 1; /* prefer unknown to probe RTT */
-               } else if ((kr_rand_uint(100) < 10)
-                               && (kr_rand_uint(KR_NS_MAX_SCORE) >= *score)) {
+               } else if ((kr_rand_uint(100) < 10) &&
+                          (kr_rand_uint(KR_NS_MAX_SCORE) >= rtt_cache_entry->score)) {
                        /* some probability to bump bad ones up for re-probe */
                        scores[i] = 1;
                } else {
-                       scores[i] = *score;
+                       scores[i] = rtt_cache_entry->score;
                }
                if (VERBOSE_STATUS) {
                        char sa_str[INET6_ADDRSTRLEN];
                        inet_ntop(sa->sa_family, kr_inaddr(sa), sa_str, sizeof(sa_str));
                        kr_log_verbose("[     ][nsre] score %d for %s;\t cached RTT: %d\n",
-                                       scores[i], sa_str, score ? *score : -1);
+                                       scores[i], sa_str,
+                                       rtt_cache_entry ? rtt_cache_entry->score : -1);
                }
        }
 
index 5c62936d16f732434ed6b94f9c7f3ed0091b1682..36dc6e8d23b702005a2ab0063eeaa8a5e5e6d2ee 100644 (file)
@@ -45,6 +45,10 @@ enum kr_ns_score {
  */
 #define KR_NS_DEAD (((KR_NS_TIMEOUT * 4) + 3) / 3)
 
+/* If once NS was marked as "timeouted", it won't participate in NS elections
+ * at least KR_NS_TIMEOUT_RETRY_INTERVAL milliseconds. */
+#define KR_NS_TIMEOUT_RETRY_INTERVAL 60000
+
 /**
  * NS QoS flags.
  */
@@ -69,8 +73,22 @@ enum kr_ns_update_mode {
        KR_NS_MAX             /**< Set to maximum of current/proposed value. */
 };
 
+struct kr_nsrep_rtt_lru_entry {
+       unsigned score;           /* combined rtt */
+       uint64_t tout_timestamp;  /* The time when score became
+                                  * greater or equal then KR_NS_TIMEOUT.
+                                  * Is meaningful only when score >= KR_NS_TIMEOUT */
+};
+
+typedef struct kr_nsrep_rtt_lru_entry kr_nsrep_rtt_lru_entry_t;
+
 /**
- * NS reputation/QoS tracking.
+ * NS QoS tracking.
+ */
+typedef lru_t(kr_nsrep_rtt_lru_entry_t) kr_nsrep_rtt_lru_t;
+
+/**
+ * NS reputation tracking.
  */
 typedef lru_t(unsigned) kr_nsrep_lru_t;
 
@@ -129,13 +147,13 @@ int kr_nsrep_elect_addr(struct kr_query *qry, struct kr_context *ctx);
  * @param  score        new score (i.e. RTT), see enum kr_ns_score
  *                      after two calls with score = KR_NS_DEAD and umode = KR_NS_UPDATE
  *                      server will be guaranteed to have KR_NS_TIMEOUTED score
- * @param  cache        LRU cache
+ * @param  cache        RTT LRU cache
  * @param  umode        update mode (KR_NS_UPDATE or KR_NS_RESET or KR_NS_ADD)
  * @return              0 on success, error code on failure
  */
 KR_EXPORT
 int kr_nsrep_update_rtt(struct kr_nsrep *ns, const struct sockaddr *addr,
-                       unsigned score, kr_nsrep_lru_t *cache, int umode);
+                       unsigned score, kr_nsrep_rtt_lru_t *cache, int umode);
 
 /**
  * Update NSSET reputation information.
@@ -159,11 +177,11 @@ int kr_nsrep_copy_set(struct kr_nsrep *dst, const struct kr_nsrep *src);
 /**
  * Sort addresses in the query nsrep list
  * @param  ns           updated kr_nsrep
- * @param  cache        RTT cache
+ * @param  rtt_cache    RTT LRU cache
  * @return              0 or an error code
  * @note   ns reputation is zeroed, as KR_NS_NOIP{4,6} flags are useless
- *             in STUB/FORWARD mode.
+ *        in STUB/FORWARD mode.
  */
 KR_EXPORT
-int kr_nsrep_sort(struct kr_nsrep *ns, kr_nsrep_lru_t *cache);
+int kr_nsrep_sort(struct kr_nsrep *ns, kr_nsrep_rtt_lru_t *rtt_cache);
 
index f973ea0cf362f61d1e69a40b4bd8f1ef745b73c7..5ff49273093f0c558d552f44b0fb2bc36eab9a3a 100644 (file)
@@ -162,7 +162,7 @@ struct kr_context
        map_t negative_anchors;
        struct kr_zonecut root_hints;
        struct kr_cache cache;
-       kr_nsrep_lru_t *cache_rtt;
+       kr_nsrep_rtt_lru_t *cache_rtt;
        kr_nsrep_lru_t *cache_rep;
        module_array_t *modules;
        /* The cookie context structure should not be held within the cookies
index 2c3971a8d630307d613b3cdda3cc91f6894180f8..dfe20a1ad15d3f429050319d5fe16846cdb1ff88 100644 (file)
@@ -27,7 +27,7 @@ M.layer = {
                local now = ffi.C.kr_now()
                local deadline = qry.creation_time_mono + M.timeout
                if now > deadline or qry.flags.NO_NS_FOUND then
-                       log('[     ][stal]   => deadline has passed')
+                       log('[     ][stal]   => no reachable NS, using stale data')
                        qry.stale_cb = M.callback
                        -- TODO: probably start the same request that doesn't stale-serve,
                        -- but first we need some detection of non-interactive / internal requests.