]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Several serve-stale improvements
authorKevin Chen <kchen@mit.edu>
Thu, 11 Mar 2021 14:45:44 +0000 (15:45 +0100)
committerEvan Hunt <each@isc.org>
Sun, 30 May 2021 18:45:35 +0000 (11:45 -0700)
Commit a83c8cb0afd88d54b9cf67239f2495c9b0391e97 updated masterdump so
that stale records in "rndc dumpdb" output no longer shows 0 TTLs.  In
this commit we change the name of the `rdataset->stale_ttl` field to
`rdataset->expired` to make its purpose clearer, and set it to zero in
cases where it's unused.

Add 'rbtdb->serve_stale_ttl' to various checks so that stale records
are not purged from the cache when they've been stale for RBTDB_VIRTUAL
(300) seconds.

Increment 'ns_statscounter_usedstale' when a stale answer is used.

Note: There was a question of whether 'overmem_purge' should be
purging ancient records, instead of stale ones.  It is left as purging
stale records, since stale records could take up the majority of the
cache.

This submission is copyrighted Akamai Technologies, Inc. and provided
under an MPL 2.0 license.

This commit was originally authored by Kevin Chen, and was updated by
Matthijs Mekking to match recent serve-stale developments.

lib/dns/include/dns/rdataset.h
lib/dns/masterdump.c
lib/dns/rbtdb.c
lib/ns/query.c

index f12419bcac48616edf92bc3f0f67cfc222b628b1..906edd0aa3a01addd1a5244bb2438db9211bd50b 100644 (file)
@@ -95,7 +95,7 @@ typedef struct dns_rdatasetmethods {
  * rdataset implementations may change any of the fields.
  */
 struct dns_rdataset {
-       unsigned int           magic; /* XXX ? */
+       unsigned int           magic;
        dns_rdatasetmethods_t *methods;
        ISC_LINK(dns_rdataset_t) link;
 
@@ -107,11 +107,7 @@ struct dns_rdataset {
        dns_rdataclass_t rdclass;
        dns_rdatatype_t  type;
        dns_ttl_t        ttl;
-       /*
-        * Stale ttl is used to see how long this RRset can still be used
-        * to serve to clients, after the TTL has expired.
-        */
-       dns_ttl_t       stale_ttl;
+
        dns_trust_t     trust;
        dns_rdatatype_t covers;
 
@@ -134,6 +130,13 @@ struct dns_rdataset {
         */
        isc_stdtime_t resign;
 
+       /*
+        * When a cache rdataset's TTL has expired but it hasn't been
+        * cleaned up yet, it will have this value set so that the time
+        * it expired can be printed by dns_master_dump*().
+        */
+       isc_stdtime_t expired;
+
        /*@{*/
        /*%
         * These are for use by the rdataset implementation, and MUST NOT
index 75cd0d250988cbef32d0dd54d2c21c820ef0df97..74ec7972bafab08fd7eb9efb0d7e4d96a67b7151 100644 (file)
@@ -1109,12 +1109,12 @@ again:
                        isc_result_t result;
                        if (STALE(rds)) {
                                fprintf(f, "; stale\n");
-                       } else if (ANCIENT(rds)) {
+                       } else if (ANCIENT(rds) && rds->expired != 0) {
                                isc_buffer_t b;
                                char buf[sizeof("YYYYMMDDHHMMSS")];
                                memset(buf, 0, sizeof(buf));
                                isc_buffer_init(&b, buf, sizeof(buf) - 1);
-                               dns_time64_totext((uint64_t)rds->stale_ttl, &b);
+                               dns_time64_totext((uint64_t)rds->expired, &b);
                                fprintf(f,
                                        "; expired since %s "
                                        "(awaiting cleanup)\n",
index 98f88e29de91d5cbeb008a2bf3efcbd59da414bf..f1074d3fd4de23a8bf64a96f79567d27fbf50b3f 100644 (file)
@@ -3135,7 +3135,9 @@ bind_rdataset(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, rdatasetheader_t *header,
        rdataset->type = RBTDB_RDATATYPE_BASE(header->type);
        rdataset->covers = RBTDB_RDATATYPE_EXT(header->type);
        rdataset->ttl = header->rdh_ttl - now;
+       rdataset->expired = 0;
        rdataset->trust = header->trust;
+
        if (NEGATIVE(header)) {
                rdataset->attributes |= DNS_RDATASETATTR_NEGATIVE;
        }
@@ -3148,22 +3150,21 @@ bind_rdataset(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, rdatasetheader_t *header,
        if (PREFETCH(header)) {
                rdataset->attributes |= DNS_RDATASETATTR_PREFETCH;
        }
+
        if (stale && !ancient) {
                dns_ttl_t stale_ttl = header->rdh_ttl + rbtdb->serve_stale_ttl;
                if (stale_ttl > now) {
-                       stale_ttl = stale_ttl - now;
+                       rdataset->ttl = stale_ttl - now;
                } else {
-                       stale_ttl = 0;
+                       rdataset->ttl = 0;
                }
                if (STALE_WINDOW(header)) {
                        rdataset->attributes |= DNS_RDATASETATTR_STALE_WINDOW;
                }
                rdataset->attributes |= DNS_RDATASETATTR_STALE;
-               rdataset->stale_ttl = stale_ttl;
-               rdataset->ttl = stale_ttl;
        } else if (IS_CACHE(rbtdb) && !ACTIVE(header, now)) {
                rdataset->attributes |= DNS_RDATASETATTR_ANCIENT;
-               rdataset->stale_ttl = header->rdh_ttl;
+               rdataset->expired = header->rdh_ttl;
                rdataset->ttl = 0;
        }
 
@@ -5589,7 +5590,8 @@ expirenode(dns_db_t *db, dns_dbnode_t *node, isc_stdtime_t now) {
                  isc_rwlocktype_write);
 
        for (header = rbtnode->data; header != NULL; header = header->next) {
-               if (header->rdh_ttl <= now - RBTDB_VIRTUAL) {
+               if (header->rdh_ttl + rbtdb->serve_stale_ttl <=
+                   now - RBTDB_VIRTUAL) {
                        /*
                         * We don't check if refcurrent(rbtnode) == 0 and try
                         * to free like we do in cache_find(), because
@@ -5860,7 +5862,8 @@ cache_findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
        for (header = rbtnode->data; header != NULL; header = header_next) {
                header_next = header->next;
                if (!ACTIVE(header, now)) {
-                       if ((header->rdh_ttl < now - RBTDB_VIRTUAL) &&
+                       if ((header->rdh_ttl + rbtdb->serve_stale_ttl <
+                            now - RBTDB_VIRTUAL) &&
                            (locktype == isc_rwlocktype_write ||
                             NODE_TRYUPGRADE(lock) == ISC_R_SUCCESS))
                        {
@@ -6957,7 +6960,9 @@ addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
                }
 
                header = isc_heap_element(rbtdb->heaps[rbtnode->locknum], 1);
-               if (header && header->rdh_ttl < now - RBTDB_VIRTUAL) {
+               if (header != NULL && header->rdh_ttl + rbtdb->serve_stale_ttl <
+                                             now - RBTDB_VIRTUAL)
+               {
                        expire_header(rbtdb, header, tree_locked, expire_ttl);
                }
 
index 97c3be1dd047c1f8ca9a54fe23a452eadbca65cb..749c748704bb3b4bf6c6142d2ebff3bf44f558b5 100644 (file)
@@ -5875,6 +5875,7 @@ query_lookup(query_ctx_t *qctx) {
                {
                        qctx->rdataset->ttl = qctx->view->staleanswerttl;
                        stale_found = true;
+                       inc_stats(qctx->client, ns_statscounter_usedstale);
                } else {
                        stale_found = false;
                }