]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
commit lruttl to the mainline. A tag was set called skan_lruttl-mainline-base, and...
authorMichael Graff <mgraff@isc.org>
Fri, 19 Oct 2007 17:15:53 +0000 (17:15 +0000)
committerMichael Graff <mgraff@isc.org>
Fri, 19 Oct 2007 17:15:53 +0000 (17:15 +0000)
12 files changed:
CHANGES
bin/named/config.c
bin/named/named.conf.docbook
doc/arm/Bv9ARM-book.xml
doc/misc/options
lib/dns/adb.c
lib/dns/cache.c
lib/dns/include/dns/rbt.h
lib/dns/rbt.c
lib/dns/rbtdb.c
lib/dns/resolver.c
lib/isc/heap.c

diff --git a/CHANGES b/CHANGES
index eef76e23ae69daff823a018cd65b2009dc8609f1..07a8e66346cb021435b7795cf5d6db8880f8ef6b 100644 (file)
--- a/CHANGES
+++ b/CHANGES
 
        --- 9.5.0a6 released ---
 
+2213.  [func]          "max-cache-size" defaults to 32M.
+                       "max-acache-size" defaults to 16M.
+
 2206.  [security]      "allow-query-cache" and "allow-recursion" now
                        cross inherit from each other.
 
index aaac8e5bc09c242ab43a8b1a8bcf6773f0def3ff..3931da8fc8ea60a18ecc9d5ce04a57ca2296568f 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: config.c,v 1.81 2007/09/18 00:22:30 marka Exp $ */
+/* $Id: config.c,v 1.82 2007/10/19 17:15:53 explorer Exp $ */
 
 /*! \file */
 
@@ -129,14 +129,14 @@ options {\n\
        max-ncache-ttl 10800; /* 3 hours */\n\
        max-cache-ttl 604800; /* 1 week */\n\
        transfer-format many-answers;\n\
-       max-cache-size 0;\n\
+       max-cache-size 32M;\n\
        check-names master fail;\n\
        check-names slave warn;\n\
        check-names response ignore;\n\
        check-mx warn;\n\
        acache-enable no;\n\
        acache-cleaning-interval 60;\n\
-       max-acache-size 0;\n\
+       max-acache-size 16M;\n\
        dnssec-enable yes;\n\
        dnssec-validation no; /* Make yes for 9.5. */ \n\
        dnssec-accept-expired no;\n\
index 0981fcbaf69b3304399837ad0a7e7bea8d5fda2d..6b6db6d0e1ce2651b2b126be0ac12253d9e9befa 100644 (file)
@@ -17,7 +17,7 @@
  - PERFORMANCE OF THIS SOFTWARE.
 -->
 
-<!-- $Id: named.conf.docbook,v 1.33 2007/09/18 00:22:30 marka Exp $ -->
+<!-- $Id: named.conf.docbook,v 1.34 2007/10/19 17:15:53 explorer Exp $ -->
 <refentry>
   <refentryinfo>
     <date>Aug 13, 2004</date>
@@ -245,8 +245,8 @@ options {
        max-ncache-ttl <replaceable>integer</replaceable>;
        max-cache-ttl <replaceable>integer</replaceable>;
        transfer-format ( many-answers | one-answer );
-       max-cache-size <replaceable>size_no_default</replaceable>;
-       max-acache-size <replaceable>size_no_default</replaceable>;
+       max-cache-size <replaceable>size</replaceable>;
+       max-acache-size <replaceable>size</replaceable>;
        clients-per-query <replaceable>number</replaceable>;
        max-clients-per-query <replaceable>number</replaceable>;
        check-names ( master | slave | response )
@@ -402,8 +402,8 @@ view <replaceable>string</replaceable> <replaceable>optional_class</replaceable>
        max-ncache-ttl <replaceable>integer</replaceable>;
        max-cache-ttl <replaceable>integer</replaceable>;
        transfer-format ( many-answers | one-answer );
-       max-cache-size <replaceable>size_no_default</replaceable>;
-       max-acache-size <replaceable>size_no_default</replaceable>;
+       max-cache-size <replaceable>size</replaceable>;
+       max-acache-size <replaceable>size</replaceable>;
        clients-per-query <replaceable>number</replaceable>;
        max-clients-per-query <replaceable>number</replaceable>;
        check-names ( master | slave | response )
index 4b26a1846ab5a2a01ba8001fda7b8edb93e68d36..497dda13e3e8f212b6ce10d5337fcb2fa1334796 100644 (file)
@@ -18,7 +18,7 @@
  - PERFORMANCE OF THIS SOFTWARE.
 -->
 
-<!-- File: $Id: Bv9ARM-book.xml,v 1.338 2007/09/26 03:22:44 marka Exp $ -->
+<!-- File: $Id: Bv9ARM-book.xml,v 1.339 2007/10/19 17:15:53 explorer Exp $ -->
 <book xmlns:xi="http://www.w3.org/2001/XInclude">
   <title>BIND 9 Administrator Reference Manual</title>
 
@@ -6812,9 +6812,7 @@ query-source-v6 address * port *;
                   with
                   multiple views, the limit applies separately to the cache of
                   each
-                  view.  The default is <literal>unlimited</literal>, meaning that
-                  records are purged from the cache only when their TTLs
-                  expire.
+                  view.  The default is <literal>32M</literal>.
                 </para>
               </listitem>
             </varlistentry>
@@ -7858,10 +7856,7 @@ query-source-v6 address * port *;
                   In a server with multiple views, the limit applies
                   separately to the
                   acache of each view.
-                  The default is <literal>unlimited</literal>,
-                  meaning that
-                  entries are purged from the acache only at the
-                  periodic cleaning time.
+                  The default is <literal>16M</literal>.
                 </para>
               </listitem>
             </varlistentry>
index 6c38c289222e14628228bb43f712fedbbf7e3077..23e48e6718dec30a9ebcb23f90ee13c6aa789c65 100644 (file)
@@ -1,5 +1,5 @@
 
-This is a summary of the named.conf options supported by 
+This is a summary of the named.conf options supported by
 this version of BIND 9.
 
 acl <string> { <address_match_element>; ... };
@@ -122,8 +122,8 @@ options {
         maintain-ixfr-base <boolean>; // obsolete
         masterfile-format ( text | raw );
         match-mapped-addresses <boolean>;
-        max-acache-size <size_no_default>;
-        max-cache-size <size_no_default>;
+        max-acache-size <size>;
+        max-cache-size <size>;
         max-cache-ttl <integer>;
         max-clients-per-query <integer>;
         max-ixfr-log-size <size>; // obsolete
@@ -292,8 +292,8 @@ view <string> <optional_class> {
         match-clients { <address_match_element>; ... };
         match-destinations { <address_match_element>; ... };
         match-recursive-only <boolean>;
-        max-acache-size <size_no_default>;
-        max-cache-size <size_no_default>;
+        max-acache-size <size>;
+        max-cache-size <size>;
         max-cache-ttl <integer>;
         max-clients-per-query <integer>;
         max-ixfr-log-size <size>; // obsolete
index fb584cdc96f5e7aa47aa9201055cd5c97bbf2a5c..182f1c538685d359eb414d01d4ab1e43bb6adcdd 100644 (file)
@@ -15,9 +15,9 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: adb.c,v 1.232 2007/09/11 02:18:38 marka Exp $ */
+/* $Id: adb.c,v 1.233 2007/10/19 17:15:53 explorer Exp $ */
 
-/*! \file 
+/*! \file
  *
  * \note
  * In finds, if task == NULL, no events will be generated, and no events
@@ -40,7 +40,7 @@
 #include <isc/mutexblock.h>
 #include <isc/netaddr.h>
 #include <isc/random.h>
-#include <isc/string.h>                /* Required for HP/UX (and others?) */
+#include <isc/string.h>         /* Required for HP/UX (and others?) */
 #include <isc/task.h>
 #include <isc/timer.h>
 #include <isc/util.h>
 #include <dns/resolver.h>
 #include <dns/result.h>
 
-#define DNS_ADB_MAGIC            ISC_MAGIC('D', 'a', 'd', 'b')
-#define DNS_ADB_VALID(x)         ISC_MAGIC_VALID(x, DNS_ADB_MAGIC)
-#define DNS_ADBNAME_MAGIC        ISC_MAGIC('a', 'd', 'b', 'N')
-#define DNS_ADBNAME_VALID(x)     ISC_MAGIC_VALID(x, DNS_ADBNAME_MAGIC)
-#define DNS_ADBNAMEHOOK_MAGIC    ISC_MAGIC('a', 'd', 'N', 'H')
+#define DNS_ADB_MAGIC             ISC_MAGIC('D', 'a', 'd', 'b')
+#define DNS_ADB_VALID(x)          ISC_MAGIC_VALID(x, DNS_ADB_MAGIC)
+#define DNS_ADBNAME_MAGIC         ISC_MAGIC('a', 'd', 'b', 'N')
+#define DNS_ADBNAME_VALID(x)      ISC_MAGIC_VALID(x, DNS_ADBNAME_MAGIC)
+#define DNS_ADBNAMEHOOK_MAGIC     ISC_MAGIC('a', 'd', 'N', 'H')
 #define DNS_ADBNAMEHOOK_VALID(x)  ISC_MAGIC_VALID(x, DNS_ADBNAMEHOOK_MAGIC)
-#define DNS_ADBLAMEINFO_MAGIC    ISC_MAGIC('a', 'd', 'b', 'Z')
+#define DNS_ADBLAMEINFO_MAGIC     ISC_MAGIC('a', 'd', 'b', 'Z')
 #define DNS_ADBLAMEINFO_VALID(x)  ISC_MAGIC_VALID(x, DNS_ADBLAMEINFO_MAGIC)
-#define DNS_ADBENTRY_MAGIC       ISC_MAGIC('a', 'd', 'b', 'E')
-#define DNS_ADBENTRY_VALID(x)    ISC_MAGIC_VALID(x, DNS_ADBENTRY_MAGIC)
-#define DNS_ADBFETCH_MAGIC       ISC_MAGIC('a', 'd', 'F', '4')
-#define DNS_ADBFETCH_VALID(x)    ISC_MAGIC_VALID(x, DNS_ADBFETCH_MAGIC)
-#define DNS_ADBFETCH6_MAGIC      ISC_MAGIC('a', 'd', 'F', '6')
-#define DNS_ADBFETCH6_VALID(x)   ISC_MAGIC_VALID(x, DNS_ADBFETCH6_MAGIC)
-
-/*! 
+#define DNS_ADBENTRY_MAGIC        ISC_MAGIC('a', 'd', 'b', 'E')
+#define DNS_ADBENTRY_VALID(x)     ISC_MAGIC_VALID(x, DNS_ADBENTRY_MAGIC)
+#define DNS_ADBFETCH_MAGIC        ISC_MAGIC('a', 'd', 'F', '4')
+#define DNS_ADBFETCH_VALID(x)     ISC_MAGIC_VALID(x, DNS_ADBFETCH_MAGIC)
+#define DNS_ADBFETCH6_MAGIC       ISC_MAGIC('a', 'd', 'F', '6')
+#define DNS_ADBFETCH6_VALID(x)    ISC_MAGIC_VALID(x, DNS_ADBFETCH6_MAGIC)
+
+/*!
  * The number of buckets needs to be a prime (for good hashing).
  *
  * XXXRTH  How many buckets do we need?
  */
-#define NBUCKETS              1009     /*%< how many buckets for names/addrs */
+#define NBUCKETS               1009     /*%< how many buckets for names/addrs */
 
 /*!
  * For type 3 negative cache entries, we will remember that the address is
  * The intent is to keep us from constantly asking about A/AAAA records
  * if the zone has extremely low TTLs.
  */
-#define ADB_CACHE_MINIMUM      10      /*%< seconds */
-#define ADB_CACHE_MAXIMUM      86400   /*%< seconds (86400 = 24 hours) */
-#define ADB_ENTRY_WINDOW       1800    /*%< seconds */
+#define ADB_CACHE_MINIMUM       10      /*%< seconds */
+#define ADB_CACHE_MAXIMUM       86400   /*%< seconds (86400 = 24 hours) */
+#define ADB_ENTRY_WINDOW        1800    /*%< seconds */
 
 /*%
  * Wake up every CLEAN_SECONDS and clean CLEAN_BUCKETS buckets, so that all
  * buckets are cleaned in CLEAN_PERIOD seconds.
  */
-#define CLEAN_PERIOD           3600
+#define CLEAN_PERIOD            3600
 /*% See #CLEAN_PERIOD */
-#define CLEAN_SECONDS          30
+#define CLEAN_SECONDS           30
 /*% See #CLEAN_PERIOD */
-#define CLEAN_BUCKETS          ((NBUCKETS * CLEAN_SECONDS) / CLEAN_PERIOD)
+#define CLEAN_BUCKETS           ((NBUCKETS * CLEAN_SECONDS) / CLEAN_PERIOD)
+
+/*%
+ * The period in seconds after which an ADB name entry is regarded as stale
+ * and forced to be cleaned up.
+ * TODO: This should probably be configurable at run-time.
+ */
+#ifndef ADB_STALE_MARGIN
+#define ADB_STALE_MARGIN        1800
+#endif
 
-#define FREE_ITEMS             64      /*%< free count for memory pools */
-#define FILL_COUNT             16      /*%< fill count for memory pools */
+#define FREE_ITEMS              64      /*%< free count for memory pools */
+#define FILL_COUNT              16      /*%< fill count for memory pools */
 
-#define DNS_ADB_INVALIDBUCKET (-1)     /*%< invalid bucket address */
+#define DNS_ADB_INVALIDBUCKET (-1)      /*%< invalid bucket address */
 
-#define DNS_ADB_MINADBSIZE     (1024*1024)     /*%< 1 Megabyte */
+#define DNS_ADB_MINADBSIZE      (1024*1024)     /*%< 1 Megabyte */
 
 typedef ISC_LIST(dns_adbname_t) dns_adbnamelist_t;
 typedef struct dns_adbnamehook dns_adbnamehook_t;
@@ -115,60 +124,78 @@ typedef struct dns_adbfetch6 dns_adbfetch6_t;
 
 /*% dns adb structure */
 struct dns_adb {
-       unsigned int                    magic;
-
-       isc_mutex_t                     lock;
-       isc_mutex_t                     reflock; /*%< Covers irefcnt, erefcnt */
-       isc_mem_t                      *mctx;
-       dns_view_t                     *view;
-       isc_timermgr_t                 *timermgr;
-       isc_timer_t                    *timer;
-       isc_taskmgr_t                  *taskmgr;
-       isc_task_t                     *task;
-       isc_boolean_t                   overmem;
-
-       isc_interval_t                  tick_interval;
-       int                             next_cleanbucket;
-
-       unsigned int                    irefcnt;
-       unsigned int                    erefcnt;
-
-       isc_mutex_t                     mplock;
-       isc_mempool_t                  *nmp;    /*%< dns_adbname_t */
-       isc_mempool_t                  *nhmp;   /*%< dns_adbnamehook_t */
-       isc_mempool_t                  *limp;   /*%< dns_adblameinfo_t */
-       isc_mempool_t                  *emp;    /*%< dns_adbentry_t */
-       isc_mempool_t                  *ahmp;   /*%< dns_adbfind_t */
-       isc_mempool_t                  *aimp;   /*%< dns_adbaddrinfo_t */
-       isc_mempool_t                  *afmp;   /*%< dns_adbfetch_t */
-
-       /*!
-        * Bucketized locks and lists for names.
-        *
-        * XXXRTH  Have a per-bucket structure that contains all of these?
-        */
-       dns_adbnamelist_t               names[NBUCKETS];
-       /*% See dns_adbnamelist_t */
-       isc_mutex_t                     namelocks[NBUCKETS];
-       /*% See dns_adbnamelist_t */
-       isc_boolean_t                   name_sd[NBUCKETS];
-       /*% See dns_adbnamelist_t */
-       unsigned int                    name_refcnt[NBUCKETS];
-
-       /*!
-        * Bucketized locks for entries.
-        *
-        * XXXRTH  Have a per-bucket structure that contains all of these?
-        */
-       dns_adbentrylist_t              entries[NBUCKETS];
-       isc_mutex_t                     entrylocks[NBUCKETS];
-       isc_boolean_t                   entry_sd[NBUCKETS]; /*%< shutting down */
-       unsigned int                    entry_refcnt[NBUCKETS];
-
-       isc_event_t                     cevent;
-       isc_boolean_t                   cevent_sent;
-       isc_boolean_t                   shutting_down;
-       isc_eventlist_t                 whenshutdown;
+        unsigned int                    magic;
+
+        isc_mutex_t                     lock;
+        isc_mutex_t                     reflock; /*%< Covers irefcnt, erefcnt */
+        isc_mem_t                      *mctx;
+        dns_view_t                     *view;
+        isc_timermgr_t                 *timermgr;
+        isc_timer_t                    *timer;
+
+#ifdef LRU_DEBUG
+        isc_timer_t                    *dump_timer; /* for test */
+        isc_time_t                      dump_time; /* for test */
+#define DUMP_INTERVAL 30        /* seconds */
+#endif
+
+        isc_taskmgr_t                  *taskmgr;
+        isc_task_t                     *task;
+        isc_boolean_t                   overmem;
+
+        isc_interval_t                  tick_interval;
+        int                             next_cleanbucket;
+
+        unsigned int                    irefcnt;
+        unsigned int                    erefcnt;
+
+        isc_mutex_t                     mplock;
+        isc_mempool_t                  *nmp;    /*%< dns_adbname_t */
+        isc_mempool_t                  *nhmp;   /*%< dns_adbnamehook_t */
+        isc_mempool_t                  *limp;   /*%< dns_adblameinfo_t */
+        isc_mempool_t                  *emp;    /*%< dns_adbentry_t */
+        isc_mempool_t                  *ahmp;   /*%< dns_adbfind_t */
+        isc_mempool_t                  *aimp;   /*%< dns_adbaddrinfo_t */
+        isc_mempool_t                  *afmp;   /*%< dns_adbfetch_t */
+
+        /*!
+         * Bucketized locks and lists for names.
+         *
+         * XXXRTH  Have a per-bucket structure that contains all of these?
+         */
+        dns_adbnamelist_t               names[NBUCKETS];
+        /*% See dns_adbnamelist_t */
+        isc_mutex_t                     namelocks[NBUCKETS];
+        /*% See dns_adbnamelist_t */
+        isc_boolean_t                   name_sd[NBUCKETS];
+        /*% See dns_adbnamelist_t */
+        unsigned int                    name_refcnt[NBUCKETS];
+
+        /*!
+         * Bucketized locks for entries.
+         *
+         * XXXRTH  Have a per-bucket structure that contains all of these?
+         */
+        dns_adbentrylist_t              entries[NBUCKETS];
+        isc_mutex_t                     entrylocks[NBUCKETS];
+        isc_boolean_t                   entry_sd[NBUCKETS]; /*%< shutting down */
+        unsigned int                    entry_refcnt[NBUCKETS];
+
+        isc_event_t                     cevent;
+        isc_boolean_t                   cevent_sent;
+        isc_boolean_t                   shutting_down;
+        isc_eventlist_t                 whenshutdown;
+
+#ifdef LRU_DEBUG
+        unsigned int                    stale_purge;
+        unsigned int                    stale_scan;
+        unsigned int                    stale_expire;
+        unsigned int                    stale_lru;
+
+        unsigned int                    nname, nname_total;
+        unsigned int                    nentry, nentry_total;
+        unsigned int                    nameuses, entryuses;
+#endif
 };
 
 /*
@@ -177,34 +204,37 @@ struct dns_adb {
 
 /*% dns_adbname structure */
 struct dns_adbname {
-       unsigned int                    magic;
-       dns_name_t                      name;
-       dns_adb_t                      *adb;
-       unsigned int                    partial_result;
-       unsigned int                    flags;
-       int                             lock_bucket;
-       dns_name_t                      target;
-       isc_stdtime_t                   expire_target;
-       isc_stdtime_t                   expire_v4;
-       isc_stdtime_t                   expire_v6;
-       unsigned int                    chains;
-       dns_adbnamehooklist_t           v4;
-       dns_adbnamehooklist_t           v6;
-       dns_adbfetch_t                 *fetch_a;
-       dns_adbfetch_t                 *fetch_aaaa;
-       unsigned int                    fetch_err;
-       unsigned int                    fetch6_err;
-       dns_adbfindlist_t               finds;
-       ISC_LINK(dns_adbname_t)         plink;
+        unsigned int                    magic;
+        dns_name_t                      name;
+        dns_adb_t                      *adb;
+        unsigned int                    partial_result;
+        unsigned int                    flags;
+        int                             lock_bucket;
+        dns_name_t                      target;
+        isc_stdtime_t                   expire_target;
+        isc_stdtime_t                   expire_v4;
+        isc_stdtime_t                   expire_v6;
+        unsigned int                    chains;
+        dns_adbnamehooklist_t           v4;
+        dns_adbnamehooklist_t           v6;
+        dns_adbfetch_t                 *fetch_a;
+        dns_adbfetch_t                 *fetch_aaaa;
+        unsigned int                    fetch_err;
+        unsigned int                    fetch6_err;
+        dns_adbfindlist_t               finds;
+        /* for LRU-based management */
+        isc_stdtime_t                   last_used;
+
+        ISC_LINK(dns_adbname_t)         plink;
 };
 
 /*% The adbfetch structure */
 struct dns_adbfetch {
-       unsigned int                    magic;
-       dns_adbnamehook_t              *namehook;
-       dns_adbentry_t                 *entry;
-       dns_fetch_t                    *fetch;
-       dns_rdataset_t                  rdataset;
+        unsigned int                    magic;
+        dns_adbnamehook_t              *namehook;
+        dns_adbentry_t                 *entry;
+        dns_fetch_t                    *fetch;
+        dns_rdataset_t                  rdataset;
 };
 
 /*%
@@ -213,9 +243,9 @@ struct dns_adbfetch {
  * namehook that will contain the next address this host has.
  */
 struct dns_adbnamehook {
-       unsigned int                    magic;
-       dns_adbentry_t                 *entry;
-       ISC_LINK(dns_adbnamehook_t)     plink;
+        unsigned int                    magic;
+        dns_adbentry_t                 *entry;
+        ISC_LINK(dns_adbnamehook_t)     plink;
 };
 
 /*%
@@ -224,13 +254,13 @@ struct dns_adbnamehook {
  * extended to other types of information about zones.
  */
 struct dns_adblameinfo {
-       unsigned int                    magic;
+        unsigned int                    magic;
 
-       dns_name_t                      qname;
-       dns_rdatatype_t                 qtype;
-       isc_stdtime_t                   lame_timer;
+        dns_name_t                      qname;
+        dns_rdatatype_t                 qtype;
+        isc_stdtime_t                   lame_timer;
 
-       ISC_LINK(dns_adblameinfo_t)     plink;
+        ISC_LINK(dns_adblameinfo_t)     plink;
 };
 
 /*%
@@ -239,26 +269,26 @@ struct dns_adblameinfo {
  * the host.
  */
 struct dns_adbentry {
-       unsigned int                    magic;
-
-       int                             lock_bucket;
-       unsigned int                    refcnt;
-
-       unsigned int                    flags;
-       unsigned int                    srtt;
-       isc_sockaddr_t                  sockaddr;
-
-       isc_stdtime_t                   expires;
-       /*%<
-        * A nonzero 'expires' field indicates that the entry should
-        * persist until that time.  This allows entries found
-        * using dns_adb_findaddrinfo() to persist for a limited time
-        * even though they are not necessarily associated with a
-        * name.
-        */
-
-       ISC_LIST(dns_adblameinfo_t)     lameinfo;
-       ISC_LINK(dns_adbentry_t)        plink;
+        unsigned int                    magic;
+
+        int                             lock_bucket;
+        unsigned int                    refcnt;
+
+        unsigned int                    flags;
+        unsigned int                    srtt;
+        isc_sockaddr_t                  sockaddr;
+
+        isc_stdtime_t                   expires;
+        /*%<
+         * A nonzero 'expires' field indicates that the entry should
+         * persist until that time.  This allows entries found
+         * using dns_adb_findaddrinfo() to persist for a limited time
+         * even though they are not necessarily associated with a
+         * name.
+         */
+
+        ISC_LIST(dns_adblameinfo_t)     lameinfo;
+        ISC_LINK(dns_adbentry_t)        plink;
 };
 
 /*
@@ -267,50 +297,50 @@ struct dns_adbentry {
 static inline dns_adbname_t *new_adbname(dns_adb_t *, dns_name_t *);
 static inline void free_adbname(dns_adb_t *, dns_adbname_t **);
 static inline dns_adbnamehook_t *new_adbnamehook(dns_adb_t *,
-                                                dns_adbentry_t *);
+                                                 dns_adbentry_t *);
 static inline void free_adbnamehook(dns_adb_t *, dns_adbnamehook_t **);
 static inline dns_adblameinfo_t *new_adblameinfo(dns_adb_t *, dns_name_t *,
-                                                dns_rdatatype_t);
+                                                 dns_rdatatype_t);
 static inline void free_adblameinfo(dns_adb_t *, dns_adblameinfo_t **);
 static inline dns_adbentry_t *new_adbentry(dns_adb_t *);
 static inline void free_adbentry(dns_adb_t *, dns_adbentry_t **);
 static inline dns_adbfind_t *new_adbfind(dns_adb_t *);
 static inline isc_boolean_t free_adbfind(dns_adb_t *, dns_adbfind_t **);
 static inline dns_adbaddrinfo_t *new_adbaddrinfo(dns_adb_t *, dns_adbentry_t *,
-                                                in_port_t);
+                                                 in_port_t);
 static inline dns_adbfetch_t *new_adbfetch(dns_adb_t *);
 static inline void free_adbfetch(dns_adb_t *, dns_adbfetch_t **);
 static inline dns_adbname_t *find_name_and_lock(dns_adb_t *, dns_name_t *,
-                                               unsigned int, int *);
+                                                unsigned int, int *);
 static inline dns_adbentry_t *find_entry_and_lock(dns_adb_t *,
-                                                 isc_sockaddr_t *, int *);
+                                                  isc_sockaddr_t *, int *);
 static void dump_adb(dns_adb_t *, FILE *, isc_boolean_t debug, isc_stdtime_t);
 static void print_dns_name(FILE *, dns_name_t *);
 static void print_namehook_list(FILE *, const char *legend,
-                               dns_adbnamehooklist_t *list,
-                               isc_boolean_t debug,
-                               isc_stdtime_t now);
+                                dns_adbnamehooklist_t *list,
+                                isc_boolean_t debug,
+                                isc_stdtime_t now);
 static void print_find_list(FILE *, dns_adbname_t *);
 static void print_fetch_list(FILE *, dns_adbname_t *);
 static inline isc_boolean_t dec_adb_irefcnt(dns_adb_t *);
 static inline void inc_adb_irefcnt(dns_adb_t *);
 static inline void inc_adb_erefcnt(dns_adb_t *);
 static inline void inc_entry_refcnt(dns_adb_t *, dns_adbentry_t *,
-                                   isc_boolean_t);
+                                    isc_boolean_t);
 static inline isc_boolean_t dec_entry_refcnt(dns_adb_t *, dns_adbentry_t *,
-                                            isc_boolean_t);
+                                             isc_boolean_t);
 static inline void violate_locking_hierarchy(isc_mutex_t *, isc_mutex_t *);
-static isc_boolean_t clean_namehooks(dns_adb_t *, dns_adbnamehooklist_t *);
+static isc_boolean_t clean_namehooks(dns_adb_t *, dns_adbnamehooklist_t *,
+                                     isc_boolean_t);
 static void clean_target(dns_adb_t *, dns_name_t *);
 static void clean_finds_at_name(dns_adbname_t *, isc_eventtype_t,
-                               unsigned int);
-static isc_boolean_t check_expire_namehooks(dns_adbname_t *, isc_stdtime_t,
-                                           isc_boolean_t);
+                                unsigned int);
+static isc_boolean_t check_expire_namehooks(dns_adbname_t *, isc_stdtime_t);
 static void cancel_fetches_at_name(dns_adbname_t *);
 static isc_result_t dbfind_name(dns_adbname_t *, isc_stdtime_t,
-                               dns_rdatatype_t);
+                                dns_rdatatype_t);
 static isc_result_t fetch_name(dns_adbname_t *, isc_boolean_t,
-                              dns_rdatatype_t);
+                               dns_rdatatype_t);
 static inline void check_exit(dns_adb_t *);
 static void timer_cleanup(isc_task_t *, isc_event_t *);
 static void destroy(dns_adb_t *);
@@ -320,35 +350,40 @@ static inline void link_name(dns_adb_t *, int, dns_adbname_t *);
 static inline isc_boolean_t unlink_name(dns_adb_t *, dns_adbname_t *);
 static inline void link_entry(dns_adb_t *, int, dns_adbentry_t *);
 static inline isc_boolean_t unlink_entry(dns_adb_t *, dns_adbentry_t *);
-static isc_boolean_t kill_name(dns_adbname_t **, isc_eventtype_t);
+static isc_boolean_t kill_name(dns_adbname_t **, isc_eventtype_t,
+                               isc_boolean_t);
 static void water(void *, int);
 static void dump_entry(FILE *, dns_adbentry_t *, isc_boolean_t, isc_stdtime_t);
 
+#ifdef LRU_DEBUG
+static void timer_dump(isc_task_t *, isc_event_t *);
+#endif
+
 /*
  * MUST NOT overlap DNS_ADBFIND_* flags!
  */
-#define FIND_EVENT_SENT                0x40000000
-#define FIND_EVENT_FREED       0x80000000
-#define FIND_EVENTSENT(h)      (((h)->flags & FIND_EVENT_SENT) != 0)
-#define FIND_EVENTFREED(h)     (((h)->flags & FIND_EVENT_FREED) != 0)
-
-#define NAME_NEEDS_POKE                0x80000000
-#define NAME_IS_DEAD           0x40000000
-#define NAME_HINT_OK           DNS_ADBFIND_HINTOK
-#define NAME_GLUE_OK           DNS_ADBFIND_GLUEOK
-#define NAME_STARTATZONE       DNS_ADBFIND_STARTATZONE
-#define NAME_DEAD(n)           (((n)->flags & NAME_IS_DEAD) != 0)
-#define NAME_NEEDSPOKE(n)      (((n)->flags & NAME_NEEDS_POKE) != 0)
-#define NAME_GLUEOK(n)         (((n)->flags & NAME_GLUE_OK) != 0)
-#define NAME_HINTOK(n)         (((n)->flags & NAME_HINT_OK) != 0)
+#define FIND_EVENT_SENT         0x40000000
+#define FIND_EVENT_FREED        0x80000000
+#define FIND_EVENTSENT(h)       (((h)->flags & FIND_EVENT_SENT) != 0)
+#define FIND_EVENTFREED(h)      (((h)->flags & FIND_EVENT_FREED) != 0)
+
+#define NAME_NEEDS_POKE         0x80000000
+#define NAME_IS_DEAD            0x40000000
+#define NAME_HINT_OK            DNS_ADBFIND_HINTOK
+#define NAME_GLUE_OK            DNS_ADBFIND_GLUEOK
+#define NAME_STARTATZONE        DNS_ADBFIND_STARTATZONE
+#define NAME_DEAD(n)            (((n)->flags & NAME_IS_DEAD) != 0)
+#define NAME_NEEDSPOKE(n)       (((n)->flags & NAME_NEEDS_POKE) != 0)
+#define NAME_GLUEOK(n)          (((n)->flags & NAME_GLUE_OK) != 0)
+#define NAME_HINTOK(n)          (((n)->flags & NAME_HINT_OK) != 0)
 
 /*
  * To the name, address classes are all that really exist.  If it has a
  * V6 address it doesn't care if it came from a AAAA query.
  */
-#define NAME_HAS_V4(n)         (!ISC_LIST_EMPTY((n)->v4))
-#define NAME_HAS_V6(n)         (!ISC_LIST_EMPTY((n)->v6))
-#define NAME_HAS_ADDRS(n)      (NAME_HAS_V4(n) || NAME_HAS_V6(n))
+#define NAME_HAS_V4(n)          (!ISC_LIST_EMPTY((n)->v4))
+#define NAME_HAS_V6(n)          (!ISC_LIST_EMPTY((n)->v6))
+#define NAME_HAS_ADDRS(n)       (NAME_HAS_V4(n) || NAME_HAS_V6(n))
 
 /*
  * Fetches are broken out into A and AAAA types.  In some cases,
@@ -357,34 +392,34 @@ static void dump_entry(FILE *, dns_adbentry_t *, isc_boolean_t, isc_stdtime_t);
  * Note: since we have removed the support of A6 in adb, FETCH_A and FETCH_AAAA
  * are now equal to FETCH_V4 and FETCH_V6, respectively.
  */
-#define NAME_FETCH_A(n)                ((n)->fetch_a != NULL)
-#define NAME_FETCH_AAAA(n)     ((n)->fetch_aaaa != NULL)
-#define NAME_FETCH_V4(n)       (NAME_FETCH_A(n))
-#define NAME_FETCH_V6(n)       (NAME_FETCH_AAAA(n))
-#define NAME_FETCH(n)          (NAME_FETCH_V4(n) || NAME_FETCH_V6(n))
+#define NAME_FETCH_A(n)         ((n)->fetch_a != NULL)
+#define NAME_FETCH_AAAA(n)      ((n)->fetch_aaaa != NULL)
+#define NAME_FETCH_V4(n)        (NAME_FETCH_A(n))
+#define NAME_FETCH_V6(n)        (NAME_FETCH_AAAA(n))
+#define NAME_FETCH(n)           (NAME_FETCH_V4(n) || NAME_FETCH_V6(n))
 
 /*
  * Find options and tests to see if there are addresses on the list.
  */
-#define FIND_WANTEVENT(fn)     (((fn)->options & DNS_ADBFIND_WANTEVENT) != 0)
-#define FIND_WANTEMPTYEVENT(fn)        (((fn)->options & DNS_ADBFIND_EMPTYEVENT) != 0)
-#define FIND_AVOIDFETCHES(fn)  (((fn)->options & DNS_ADBFIND_AVOIDFETCHES) \
-                                != 0)
-#define FIND_STARTATZONE(fn)   (((fn)->options & DNS_ADBFIND_STARTATZONE) \
-                                != 0)
-#define FIND_HINTOK(fn)                (((fn)->options & DNS_ADBFIND_HINTOK) != 0)
-#define FIND_GLUEOK(fn)                (((fn)->options & DNS_ADBFIND_GLUEOK) != 0)
-#define FIND_HAS_ADDRS(fn)     (!ISC_LIST_EMPTY((fn)->list))
-#define FIND_RETURNLAME(fn)    (((fn)->options & DNS_ADBFIND_RETURNLAME) != 0)
+#define FIND_WANTEVENT(fn)      (((fn)->options & DNS_ADBFIND_WANTEVENT) != 0)
+#define FIND_WANTEMPTYEVENT(fn) (((fn)->options & DNS_ADBFIND_EMPTYEVENT) != 0)
+#define FIND_AVOIDFETCHES(fn)   (((fn)->options & DNS_ADBFIND_AVOIDFETCHES) \
+                                 != 0)
+#define FIND_STARTATZONE(fn)    (((fn)->options & DNS_ADBFIND_STARTATZONE) \
+                                 != 0)
+#define FIND_HINTOK(fn)         (((fn)->options & DNS_ADBFIND_HINTOK) != 0)
+#define FIND_GLUEOK(fn)         (((fn)->options & DNS_ADBFIND_GLUEOK) != 0)
+#define FIND_HAS_ADDRS(fn)      (!ISC_LIST_EMPTY((fn)->list))
+#define FIND_RETURNLAME(fn)     (((fn)->options & DNS_ADBFIND_RETURNLAME) != 0)
 
 /*
  * These are currently used on simple unsigned ints, so they are
  * not really associated with any particular type.
  */
-#define WANT_INET(x)           (((x) & DNS_ADBFIND_INET) != 0)
-#define WANT_INET6(x)          (((x) & DNS_ADBFIND_INET6) != 0)
+#define WANT_INET(x)            (((x) & DNS_ADBFIND_INET) != 0)
+#define WANT_INET6(x)           (((x) & DNS_ADBFIND_INET6) != 0)
 
-#define EXPIRE_OK(exp, now)    ((exp == INT_MAX) || (exp < now))
+#define EXPIRE_OK(exp, now)     ((exp == INT_MAX) || (exp < now))
 
 /*
  * Find out if the flags on a name (nf) indicate if it is a hint or
@@ -395,57 +430,57 @@ static void dump_entry(FILE *, dns_adbentry_t *, isc_boolean_t, isc_stdtime_t);
 #define HINT_OK(nf, o) (!NAME_HINTOK(nf) || (((o) & DNS_ADBFIND_HINTOK) != 0))
 #define GLUEHINT_OK(nf, o) (GLUE_OK(nf, o) || HINT_OK(nf, o))
 #define STARTATZONE_MATCHES(nf, o) (((nf)->flags & NAME_STARTATZONE) == \
-                                   ((o) & DNS_ADBFIND_STARTATZONE))
-
-#define ENTER_LEVEL            ISC_LOG_DEBUG(50)
-#define EXIT_LEVEL             ENTER_LEVEL
-#define CLEAN_LEVEL            ISC_LOG_DEBUG(100)
-#define DEF_LEVEL              ISC_LOG_DEBUG(5)
-#define NCACHE_LEVEL           ISC_LOG_DEBUG(20)
-
-#define NCACHE_RESULT(r)       ((r) == DNS_R_NCACHENXDOMAIN || \
-                                (r) == DNS_R_NCACHENXRRSET)
-#define AUTH_NX(r)             ((r) == DNS_R_NXDOMAIN || \
-                                (r) == DNS_R_NXRRSET)
-#define NXDOMAIN_RESULT(r)     ((r) == DNS_R_NXDOMAIN || \
-                                (r) == DNS_R_NCACHENXDOMAIN)
-#define NXRRSET_RESULT(r)      ((r) == DNS_R_NCACHENXRRSET || \
-                                (r) == DNS_R_NXRRSET || \
-                                (r) == DNS_R_HINTNXRRSET)
+                                    ((o) & DNS_ADBFIND_STARTATZONE))
+
+#define ENTER_LEVEL             ISC_LOG_DEBUG(50)
+#define EXIT_LEVEL              ENTER_LEVEL
+#define CLEAN_LEVEL             ISC_LOG_DEBUG(100)
+#define DEF_LEVEL               ISC_LOG_DEBUG(5)
+#define NCACHE_LEVEL            ISC_LOG_DEBUG(20)
+
+#define NCACHE_RESULT(r)        ((r) == DNS_R_NCACHENXDOMAIN || \
+                                 (r) == DNS_R_NCACHENXRRSET)
+#define AUTH_NX(r)              ((r) == DNS_R_NXDOMAIN || \
+                                 (r) == DNS_R_NXRRSET)
+#define NXDOMAIN_RESULT(r)      ((r) == DNS_R_NXDOMAIN || \
+                                 (r) == DNS_R_NCACHENXDOMAIN)
+#define NXRRSET_RESULT(r)       ((r) == DNS_R_NCACHENXRRSET || \
+                                 (r) == DNS_R_NXRRSET || \
+                                 (r) == DNS_R_HINTNXRRSET)
 
 /*
  * Error state rankings.
  */
 
-#define FIND_ERR_SUCCESS               0  /* highest rank */
-#define FIND_ERR_CANCELED              1
-#define FIND_ERR_FAILURE               2
-#define FIND_ERR_NXDOMAIN              3
-#define FIND_ERR_NXRRSET               4
-#define FIND_ERR_UNEXPECTED            5
-#define FIND_ERR_NOTFOUND              6
-#define FIND_ERR_MAX                   7
+#define FIND_ERR_SUCCESS                0  /* highest rank */
+#define FIND_ERR_CANCELED               1
+#define FIND_ERR_FAILURE                2
+#define FIND_ERR_NXDOMAIN               3
+#define FIND_ERR_NXRRSET                4
+#define FIND_ERR_UNEXPECTED             5
+#define FIND_ERR_NOTFOUND               6
+#define FIND_ERR_MAX                    7
 
 static const char *errnames[] = {
-       "success",
-       "canceled",
-       "failure",
-       "nxdomain",
-       "nxrrset",
-       "unexpected",
-       "not_found"
+        "success",
+        "canceled",
+        "failure",
+        "nxdomain",
+        "nxrrset",
+        "unexpected",
+        "not_found"
 };
 
-#define NEWERR(old, new)       (ISC_MIN((old), (new)))
+#define NEWERR(old, new)        (ISC_MIN((old), (new)))
 
 static isc_result_t find_err_map[FIND_ERR_MAX] = {
-       ISC_R_SUCCESS,
-       ISC_R_CANCELED,
-       ISC_R_FAILURE,
-       DNS_R_NXDOMAIN,
-       DNS_R_NXRRSET,
-       ISC_R_UNEXPECTED,
-       ISC_R_NOTFOUND          /* not YET found */
+        ISC_R_SUCCESS,
+        ISC_R_CANCELED,
+        ISC_R_FAILURE,
+        DNS_R_NXDOMAIN,
+        DNS_R_NXRRSET,
+        ISC_R_UNEXPECTED,
+        ISC_R_NOTFOUND          /* not YET found */
 };
 
 static void
@@ -453,23 +488,23 @@ DP(int level, const char *format, ...) ISC_FORMAT_PRINTF(2, 3);
 
 static void
 DP(int level, const char *format, ...) {
-       va_list args;
+        va_list args;
 
-       va_start(args, format);
-       isc_log_vwrite(dns_lctx,
-                      DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_ADB,
-                      level, format, args);
-       va_end(args);
+        va_start(args, format);
+        isc_log_vwrite(dns_lctx,
+                       DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_ADB,
+                       level, format, args);
+        va_end(args);
 }
 
 static inline dns_ttl_t
 ttlclamp(dns_ttl_t ttl) {
-       if (ttl < ADB_CACHE_MINIMUM)
-               ttl = ADB_CACHE_MINIMUM;
-       if (ttl > ADB_CACHE_MAXIMUM)
-               ttl = ADB_CACHE_MAXIMUM;
+        if (ttl < ADB_CACHE_MINIMUM)
+                ttl = ADB_CACHE_MINIMUM;
+        if (ttl > ADB_CACHE_MAXIMUM)
+                ttl = ADB_CACHE_MAXIMUM;
 
-       return (ttl);
+        return (ttl);
 }
 
 /*
@@ -479,255 +514,241 @@ ttlclamp(dns_ttl_t ttl) {
  */
 static isc_result_t
 import_rdataset(dns_adbname_t *adbname, dns_rdataset_t *rdataset,
-               isc_stdtime_t now)
+                isc_stdtime_t now)
 {
-       isc_result_t result;
-       dns_adb_t *adb;
-       dns_adbnamehook_t *nh;
-       dns_adbnamehook_t *anh;
-       dns_rdata_t rdata = DNS_RDATA_INIT;
-       struct in_addr ina;
-       struct in6_addr in6a;
-       isc_sockaddr_t sockaddr;
-       dns_adbentry_t *foundentry;  /* NO CLEAN UP! */
-       int addr_bucket;
-       isc_boolean_t new_addresses_added;
-       dns_rdatatype_t rdtype;
-       unsigned int findoptions;
-
-       INSIST(DNS_ADBNAME_VALID(adbname));
-       adb = adbname->adb;
-       INSIST(DNS_ADB_VALID(adb));
-
-       rdtype = rdataset->type;
-       INSIST((rdtype == dns_rdatatype_a) || (rdtype == dns_rdatatype_aaaa));
-       if (rdtype == dns_rdatatype_a)
-               findoptions = DNS_ADBFIND_INET;
-       else
-               findoptions = DNS_ADBFIND_INET6;
-
-       addr_bucket = DNS_ADB_INVALIDBUCKET;
-       new_addresses_added = ISC_FALSE;
-
-       nh = NULL;
-       result = dns_rdataset_first(rdataset);
-       while (result == ISC_R_SUCCESS) {
-               dns_rdata_reset(&rdata);
-               dns_rdataset_current(rdataset, &rdata);
-               if (rdtype == dns_rdatatype_a) {
-                       INSIST(rdata.length == 4);
-                       memcpy(&ina.s_addr, rdata.data, 4);
-                       isc_sockaddr_fromin(&sockaddr, &ina, 0);
-               } else {
-                       INSIST(rdata.length == 16);
-                       memcpy(in6a.s6_addr, rdata.data, 16);
-                       isc_sockaddr_fromin6(&sockaddr, &in6a, 0);
-               }
-
-               INSIST(nh == NULL);
-               nh = new_adbnamehook(adb, NULL);
-               if (nh == NULL) {
-                       adbname->partial_result |= findoptions;
-                       result = ISC_R_NOMEMORY;
-                       goto fail;
-               }
-
-               foundentry = find_entry_and_lock(adb, &sockaddr, &addr_bucket);
-               if (foundentry == NULL) {
-                       dns_adbentry_t *entry;
-
-                       entry = new_adbentry(adb);
-                       if (entry == NULL) {
-                               adbname->partial_result |= findoptions;
-                               result = ISC_R_NOMEMORY;
-                               goto fail;
-                       }
-
-                       entry->sockaddr = sockaddr;
-                       entry->refcnt = 1;
-
-                       nh->entry = entry;
-
-                       link_entry(adb, addr_bucket, entry);
-               } else {
-                       for (anh = ISC_LIST_HEAD(adbname->v4);
-                            anh != NULL;
-                            anh = ISC_LIST_NEXT(anh, plink))
-                               if (anh->entry == foundentry)
-                                       break;
-                       if (anh == NULL) {
-                               foundentry->refcnt++;
-                               nh->entry = foundentry;
-                       } else
-                               free_adbnamehook(adb, &nh);
-               }
-
-               new_addresses_added = ISC_TRUE;
-               if (nh != NULL) {
-                       if (rdtype == dns_rdatatype_a)
-                               ISC_LIST_APPEND(adbname->v4, nh, plink);
-                       else
-                               ISC_LIST_APPEND(adbname->v6, nh, plink);
-               }
-               nh = NULL;
-               result = dns_rdataset_next(rdataset);
-       }
+        isc_result_t result;
+        dns_adb_t *adb;
+        dns_adbnamehook_t *nh;
+        dns_adbnamehook_t *anh;
+        dns_rdata_t rdata = DNS_RDATA_INIT;
+        struct in_addr ina;
+        struct in6_addr in6a;
+        isc_sockaddr_t sockaddr;
+        dns_adbentry_t *foundentry;  /* NO CLEAN UP! */
+        int addr_bucket;
+        isc_boolean_t new_addresses_added;
+        dns_rdatatype_t rdtype;
+        unsigned int findoptions;
+
+        INSIST(DNS_ADBNAME_VALID(adbname));
+        adb = adbname->adb;
+        INSIST(DNS_ADB_VALID(adb));
+
+        rdtype = rdataset->type;
+        INSIST((rdtype == dns_rdatatype_a) || (rdtype == dns_rdatatype_aaaa));
+        if (rdtype == dns_rdatatype_a)
+                findoptions = DNS_ADBFIND_INET;
+        else
+                findoptions = DNS_ADBFIND_INET6;
+
+        addr_bucket = DNS_ADB_INVALIDBUCKET;
+        new_addresses_added = ISC_FALSE;
+
+        nh = NULL;
+        result = dns_rdataset_first(rdataset);
+        while (result == ISC_R_SUCCESS) {
+                dns_rdata_reset(&rdata);
+                dns_rdataset_current(rdataset, &rdata);
+                if (rdtype == dns_rdatatype_a) {
+                        INSIST(rdata.length == 4);
+                        memcpy(&ina.s_addr, rdata.data, 4);
+                        isc_sockaddr_fromin(&sockaddr, &ina, 0);
+                } else {
+                        INSIST(rdata.length == 16);
+                        memcpy(in6a.s6_addr, rdata.data, 16);
+                        isc_sockaddr_fromin6(&sockaddr, &in6a, 0);
+                }
+
+                INSIST(nh == NULL);
+                nh = new_adbnamehook(adb, NULL);
+                if (nh == NULL) {
+                        adbname->partial_result |= findoptions;
+                        result = ISC_R_NOMEMORY;
+                        goto fail;
+                }
+
+                foundentry = find_entry_and_lock(adb, &sockaddr, &addr_bucket);
+                if (foundentry == NULL) {
+                        dns_adbentry_t *entry;
+
+                        entry = new_adbentry(adb);
+                        if (entry == NULL) {
+                                adbname->partial_result |= findoptions;
+                                result = ISC_R_NOMEMORY;
+                                goto fail;
+                        }
+
+                        entry->sockaddr = sockaddr;
+                        entry->refcnt = 1;
+
+                        nh->entry = entry;
+
+                        link_entry(adb, addr_bucket, entry);
+                } else {
+                        for (anh = ISC_LIST_HEAD(adbname->v4);
+                             anh != NULL;
+                             anh = ISC_LIST_NEXT(anh, plink))
+                                if (anh->entry == foundentry)
+                                        break;
+                        if (anh == NULL) {
+                                foundentry->refcnt++;
+                                nh->entry = foundentry;
+                        } else
+                                free_adbnamehook(adb, &nh);
+                }
+
+                new_addresses_added = ISC_TRUE;
+                if (nh != NULL) {
+                        if (rdtype == dns_rdatatype_a)
+                                ISC_LIST_APPEND(adbname->v4, nh, plink);
+                        else
+                                ISC_LIST_APPEND(adbname->v6, nh, plink);
+                }
+                nh = NULL;
+                result = dns_rdataset_next(rdataset);
+        }
 
  fail:
-       if (nh != NULL)
-               free_adbnamehook(adb, &nh);
-
-       if (addr_bucket != DNS_ADB_INVALIDBUCKET)
-               UNLOCK(&adb->entrylocks[addr_bucket]);
-
-       if (rdataset->trust == dns_trust_glue ||
-           rdataset->trust == dns_trust_additional)
-               rdataset->ttl = ADB_CACHE_MINIMUM;
-       else
-               rdataset->ttl = ttlclamp(rdataset->ttl);
-
-       if (rdtype == dns_rdatatype_a) {
-               DP(NCACHE_LEVEL, "expire_v4 set to MIN(%u,%u) import_rdataset",
-                  adbname->expire_v4, now + rdataset->ttl);
-               adbname->expire_v4 = ISC_MIN(adbname->expire_v4,
-                                            now + rdataset->ttl);
-       } else {
-               DP(NCACHE_LEVEL, "expire_v6 set to MIN(%u,%u) import_rdataset",
-                  adbname->expire_v6, now + rdataset->ttl);
-               adbname->expire_v6 = ISC_MIN(adbname->expire_v6,
-                                            now + rdataset->ttl);
-       }
-
-       if (new_addresses_added) {
-               /*
-                * Lie a little here.  This is more or less so code that cares
-                * can find out if any new information was added or not.
-                */
-               return (ISC_R_SUCCESS);
-       }
-
-       return (result);
+        if (nh != NULL)
+                free_adbnamehook(adb, &nh);
+
+        if (addr_bucket != DNS_ADB_INVALIDBUCKET)
+                UNLOCK(&adb->entrylocks[addr_bucket]);
+
+        if (rdataset->trust == dns_trust_glue ||
+            rdataset->trust == dns_trust_additional)
+                rdataset->ttl = ADB_CACHE_MINIMUM;
+        else
+                rdataset->ttl = ttlclamp(rdataset->ttl);
+
+        if (rdtype == dns_rdatatype_a) {
+                DP(NCACHE_LEVEL, "expire_v4 set to MIN(%u,%u) import_rdataset",
+                   adbname->expire_v4, now + rdataset->ttl);
+                adbname->expire_v4 = ISC_MIN(adbname->expire_v4,
+                                             now + rdataset->ttl);
+        } else {
+                DP(NCACHE_LEVEL, "expire_v6 set to MIN(%u,%u) import_rdataset",
+                   adbname->expire_v6, now + rdataset->ttl);
+                adbname->expire_v6 = ISC_MIN(adbname->expire_v6,
+                                             now + rdataset->ttl);
+        }
+
+        if (new_addresses_added) {
+                /*
+                 * Lie a little here.  This is more or less so code that cares
+                 * can find out if any new information was added or not.
+                 */
+                return (ISC_R_SUCCESS);
+        }
+
+        return (result);
 }
 
 /*
  * Requires the name's bucket be locked.
  */
 static isc_boolean_t
-kill_name(dns_adbname_t **n, isc_eventtype_t ev) {
-       dns_adbname_t *name;
-       isc_boolean_t result = ISC_FALSE;
-       isc_boolean_t result4, result6;
-       dns_adb_t *adb;
-
-       INSIST(n != NULL);
-       name = *n;
-       *n = NULL;
-       INSIST(DNS_ADBNAME_VALID(name));
-       adb = name->adb;
-       INSIST(DNS_ADB_VALID(adb));
-
-       DP(DEF_LEVEL, "killing name %p", name);
-
-       /*
-        * If we're dead already, just check to see if we should go
-        * away now or not.
-        */
-       if (NAME_DEAD(name) && !NAME_FETCH(name)) {
-               result = unlink_name(adb, name);
-               free_adbname(adb, &name);
-               if (result)
-                       result = dec_adb_irefcnt(adb);
-               return (result);
-       }
-
-       /*
-        * Clean up the name's various lists.  These two are destructive
-        * in that they will always empty the list.
-        */
-       clean_finds_at_name(name, ev, DNS_ADBFIND_ADDRESSMASK);
-       result4 = clean_namehooks(adb, &name->v4);
-       result6 = clean_namehooks(adb, &name->v6);
-       clean_target(adb, &name->target);
-       result = ISC_TF(result4 || result6);
-
-       /*
-        * If fetches are running, cancel them.  If none are running, we can
-        * just kill the name here.
-        */
-       if (!NAME_FETCH(name)) {
-               INSIST(result == ISC_FALSE);
-               result = unlink_name(adb, name);
-               free_adbname(adb, &name);
-               if (result)
-                       result = dec_adb_irefcnt(adb);
-       } else {
-               name->flags |= NAME_IS_DEAD;
-               cancel_fetches_at_name(name);
-       }
-       return (result);
+kill_name(dns_adbname_t **n, isc_eventtype_t ev, isc_boolean_t is_purge) {
+        dns_adbname_t *name;
+        isc_boolean_t result = ISC_FALSE;
+        isc_boolean_t result4, result6;
+        dns_adb_t *adb;
+
+        INSIST(n != NULL);
+        name = *n;
+        *n = NULL;
+        INSIST(DNS_ADBNAME_VALID(name));
+        adb = name->adb;
+        INSIST(DNS_ADB_VALID(adb));
+
+        DP(DEF_LEVEL, "killing name %p", name);
+
+        /*
+         * If we're dead already, just check to see if we should go
+         * away now or not.
+         */
+        if (NAME_DEAD(name) && !NAME_FETCH(name)) {
+                result = unlink_name(adb, name);
+                free_adbname(adb, &name);
+                if (result)
+                        result = dec_adb_irefcnt(adb);
+                return (result);
+        }
+
+        /*
+         * Clean up the name's various lists.  These two are destructive
+         * in that they will always empty the list.
+         */
+        clean_finds_at_name(name, ev, DNS_ADBFIND_ADDRESSMASK);
+        result4 = clean_namehooks(adb, &name->v4, is_purge);
+        result6 = clean_namehooks(adb, &name->v6, is_purge);
+        clean_target(adb, &name->target);
+        result = ISC_TF(result4 || result6);
+
+        /*
+         * If fetches are running, cancel them.  If none are running, we can
+         * just kill the name here.
+         */
+        if (!NAME_FETCH(name)) {
+                INSIST(result == ISC_FALSE);
+                result = unlink_name(adb, name);
+                free_adbname(adb, &name);
+                if (result)
+                        result = dec_adb_irefcnt(adb);
+        } else {
+                name->flags |= NAME_IS_DEAD;
+                cancel_fetches_at_name(name);
+        }
+        return (result);
 }
 
 /*
  * Requires the name's bucket be locked and no entry buckets be locked.
  */
 static isc_boolean_t
-check_expire_namehooks(dns_adbname_t *name, isc_stdtime_t now,
-                      isc_boolean_t overmem)
-{
-       dns_adb_t *adb;
-       isc_boolean_t expire;
-       isc_boolean_t result4 = ISC_FALSE;
-       isc_boolean_t result6 = ISC_FALSE;
-
-       INSIST(DNS_ADBNAME_VALID(name));
-       adb = name->adb;
-       INSIST(DNS_ADB_VALID(adb));
-
-       if (overmem) {
-               isc_uint32_t val;
-
-               isc_random_get(&val);
-
-               expire = ISC_TF((val % 4) == 0);
-       } else
-               expire = ISC_FALSE;
-
-       /*
-        * Check to see if we need to remove the v4 addresses
-        */
-       if (!NAME_FETCH_V4(name) &&
-           (expire || EXPIRE_OK(name->expire_v4, now))) {
-               if (NAME_HAS_V4(name)) {
-                       DP(DEF_LEVEL, "expiring v4 for name %p", name);
-                       result4 = clean_namehooks(adb, &name->v4);
-                       name->partial_result &= ~DNS_ADBFIND_INET;
-               }
-               name->expire_v4 = INT_MAX;
-               name->fetch_err = FIND_ERR_UNEXPECTED;
-       }
-
-       /*
-        * Check to see if we need to remove the v6 addresses
-        */
-       if (!NAME_FETCH_V6(name) &&
-           (expire || EXPIRE_OK(name->expire_v6, now))) {
-               if (NAME_HAS_V6(name)) {
-                       DP(DEF_LEVEL, "expiring v6 for name %p", name);
-                       result6 = clean_namehooks(adb, &name->v6);
-                       name->partial_result &= ~DNS_ADBFIND_INET6;
-               }
-               name->expire_v6 = INT_MAX;
-               name->fetch6_err = FIND_ERR_UNEXPECTED;
-       }
-
-       /*
-        * Check to see if we need to remove the alias target.
-        */
-       if (expire || EXPIRE_OK(name->expire_target, now)) {
-               clean_target(adb, &name->target);
-               name->expire_target = INT_MAX;
-       }
-       return (ISC_TF(result4 || result6));
+check_expire_namehooks(dns_adbname_t *name, isc_stdtime_t now) {
+        dns_adb_t *adb;
+        isc_boolean_t result4 = ISC_FALSE;
+        isc_boolean_t result6 = ISC_FALSE;
+
+        INSIST(DNS_ADBNAME_VALID(name));
+        adb = name->adb;
+        INSIST(DNS_ADB_VALID(adb));
+
+        /*
+         * Check to see if we need to remove the v4 addresses
+         */
+        if (!NAME_FETCH_V4(name) && EXPIRE_OK(name->expire_v4, now)) {
+                if (NAME_HAS_V4(name)) {
+                        DP(DEF_LEVEL, "expiring v4 for name %p", name);
+                        result4 = clean_namehooks(adb, &name->v4, ISC_FALSE);
+                        name->partial_result &= ~DNS_ADBFIND_INET;
+                }
+                name->expire_v4 = INT_MAX;
+                name->fetch_err = FIND_ERR_UNEXPECTED;
+        }
+
+        /*
+         * Check to see if we need to remove the v6 addresses
+         */
+        if (!NAME_FETCH_V6(name) && EXPIRE_OK(name->expire_v6, now)) {
+                if (NAME_HAS_V6(name)) {
+                        DP(DEF_LEVEL, "expiring v6 for name %p", name);
+                        result6 = clean_namehooks(adb, &name->v6, ISC_FALSE);
+                        name->partial_result &= ~DNS_ADBFIND_INET6;
+                }
+                name->expire_v6 = INT_MAX;
+                name->fetch6_err = FIND_ERR_UNEXPECTED;
+        }
+
+        /*
+         * Check to see if we need to remove the alias target.
+         */
+        if (EXPIRE_OK(name->expire_target, now)) {
+                clean_target(adb, &name->target);
+                name->expire_target = INT_MAX;
+        }
+        return (ISC_TF(result4 || result6));
 }
 
 /*
@@ -735,11 +756,11 @@ check_expire_namehooks(dns_adbname_t *name, isc_stdtime_t now,
  */
 static inline void
 link_name(dns_adb_t *adb, int bucket, dns_adbname_t *name) {
-       INSIST(name->lock_bucket == DNS_ADB_INVALIDBUCKET);
+        INSIST(name->lock_bucket == DNS_ADB_INVALIDBUCKET);
 
-       ISC_LIST_PREPEND(adb->names[bucket], name, plink);
-       name->lock_bucket = bucket;
-       adb->name_refcnt[bucket]++;
+        ISC_LIST_PREPEND(adb->names[bucket], name, plink);
+        name->lock_bucket = bucket;
+        adb->name_refcnt[bucket]++;
 }
 
 /*
@@ -747,19 +768,19 @@ link_name(dns_adb_t *adb, int bucket, dns_adbname_t *name) {
  */
 static inline isc_boolean_t
 unlink_name(dns_adb_t *adb, dns_adbname_t *name) {
-       int bucket;
-       isc_boolean_t result = ISC_FALSE;
+        int bucket;
+        isc_boolean_t result = ISC_FALSE;
 
-       bucket = name->lock_bucket;
-       INSIST(bucket != DNS_ADB_INVALIDBUCKET);
+        bucket = name->lock_bucket;
+        INSIST(bucket != DNS_ADB_INVALIDBUCKET);
 
-       ISC_LIST_UNLINK(adb->names[bucket], name, plink);
-       name->lock_bucket = DNS_ADB_INVALIDBUCKET;
-       INSIST(adb->name_refcnt[bucket] > 0);
-       adb->name_refcnt[bucket]--;
-       if (adb->name_sd[bucket] && adb->name_refcnt[bucket] == 0)
-               result = ISC_TRUE;
-       return (result);
+        ISC_LIST_UNLINK(adb->names[bucket], name, plink);
+        name->lock_bucket = DNS_ADB_INVALIDBUCKET;
+        INSIST(adb->name_refcnt[bucket] > 0);
+        adb->name_refcnt[bucket]--;
+        if (adb->name_sd[bucket] && adb->name_refcnt[bucket] == 0)
+                result = ISC_TRUE;
+        return (result);
 }
 
 /*
@@ -767,9 +788,9 @@ unlink_name(dns_adb_t *adb, dns_adbname_t *name) {
  */
 static inline void
 link_entry(dns_adb_t *adb, int bucket, dns_adbentry_t *entry) {
-       ISC_LIST_PREPEND(adb->entries[bucket], entry, plink);
-       entry->lock_bucket = bucket;
-       adb->entry_refcnt[bucket]++;
+        ISC_LIST_PREPEND(adb->entries[bucket], entry, plink);
+        entry->lock_bucket = bucket;
+        adb->entry_refcnt[bucket]++;
 }
 
 /*
@@ -777,28 +798,28 @@ link_entry(dns_adb_t *adb, int bucket, dns_adbentry_t *entry) {
  */
 static inline isc_boolean_t
 unlink_entry(dns_adb_t *adb, dns_adbentry_t *entry) {
-       int bucket;
-       isc_boolean_t result = ISC_FALSE;
+        int bucket;
+        isc_boolean_t result = ISC_FALSE;
 
-       bucket = entry->lock_bucket;
-       INSIST(bucket != DNS_ADB_INVALIDBUCKET);
+        bucket = entry->lock_bucket;
+        INSIST(bucket != DNS_ADB_INVALIDBUCKET);
 
-       ISC_LIST_UNLINK(adb->entries[bucket], entry, plink);
-       entry->lock_bucket = DNS_ADB_INVALIDBUCKET;
-       INSIST(adb->entry_refcnt[bucket] > 0);
-       adb->entry_refcnt[bucket]--;
-       if (adb->entry_sd[bucket] && adb->entry_refcnt[bucket] == 0)
-               result = ISC_TRUE;
-       return (result);
+        ISC_LIST_UNLINK(adb->entries[bucket], entry, plink);
+        entry->lock_bucket = DNS_ADB_INVALIDBUCKET;
+        INSIST(adb->entry_refcnt[bucket] > 0);
+        adb->entry_refcnt[bucket]--;
+        if (adb->entry_sd[bucket] && adb->entry_refcnt[bucket] == 0)
+                result = ISC_TRUE;
+        return (result);
 }
 
 static inline void
 violate_locking_hierarchy(isc_mutex_t *have, isc_mutex_t *want) {
-       if (isc_mutex_trylock(want) != ISC_R_SUCCESS) {
-               UNLOCK(have);
-               LOCK(want);
-               LOCK(have);
-       }
+        if (isc_mutex_trylock(want) != ISC_R_SUCCESS) {
+                UNLOCK(have);
+                LOCK(want);
+                LOCK(have);
+        }
 }
 
 /*
@@ -807,43 +828,44 @@ violate_locking_hierarchy(isc_mutex_t *have, isc_mutex_t *want) {
  */
 static isc_boolean_t
 shutdown_names(dns_adb_t *adb) {
-       int bucket;
-       isc_boolean_t result = ISC_FALSE;
-       dns_adbname_t *name;
-       dns_adbname_t *next_name;
-
-       for (bucket = 0; bucket < NBUCKETS; bucket++) {
-               LOCK(&adb->namelocks[bucket]);
-               adb->name_sd[bucket] = ISC_TRUE;
-
-               name = ISC_LIST_HEAD(adb->names[bucket]);
-               if (name == NULL) {
-                       /*
-                        * This bucket has no names.  We must decrement the
-                        * irefcnt ourselves, since it will not be
-                        * automatically triggered by a name being unlinked.
-                        */
-                       INSIST(result == ISC_FALSE);
-                       result = dec_adb_irefcnt(adb);
-               } else {
-                       /*
-                        * Run through the list.  For each name, clean up finds
-                        * found there, and cancel any fetches running.  When
-                        * all the fetches are canceled, the name will destroy
-                        * itself.
-                        */
-                       while (name != NULL) {
-                               next_name = ISC_LIST_NEXT(name, plink);
-                               INSIST(result == ISC_FALSE);
-                               result = kill_name(&name,
-                                                  DNS_EVENT_ADBSHUTDOWN);
-                               name = next_name;
-                       }
-               }
-
-               UNLOCK(&adb->namelocks[bucket]);
-       }
-       return (result);
+        int bucket;
+        isc_boolean_t result = ISC_FALSE;
+        dns_adbname_t *name;
+        dns_adbname_t *next_name;
+
+        for (bucket = 0; bucket < NBUCKETS; bucket++) {
+                LOCK(&adb->namelocks[bucket]);
+                adb->name_sd[bucket] = ISC_TRUE;
+
+                name = ISC_LIST_HEAD(adb->names[bucket]);
+                if (name == NULL) {
+                        /*
+                         * This bucket has no names.  We must decrement the
+                         * irefcnt ourselves, since it will not be
+                         * automatically triggered by a name being unlinked.
+                         */
+                        INSIST(result == ISC_FALSE);
+                        result = dec_adb_irefcnt(adb);
+                } else {
+                        /*
+                         * Run through the list.  For each name, clean up finds
+                         * found there, and cancel any fetches running.  When
+                         * all the fetches are canceled, the name will destroy
+                         * itself.
+                         */
+                        while (name != NULL) {
+                                next_name = ISC_LIST_NEXT(name, plink);
+                                INSIST(result == ISC_FALSE);
+                                result = kill_name(&name,
+                                                   DNS_EVENT_ADBSHUTDOWN,
+                                                   ISC_FALSE);
+                                name = next_name;
+                        }
+                }
+
+                UNLOCK(&adb->namelocks[bucket]);
+        }
+        return (result);
 }
 
 /*
@@ -852,44 +874,44 @@ shutdown_names(dns_adb_t *adb) {
  */
 static isc_boolean_t
 shutdown_entries(dns_adb_t *adb) {
-       int bucket;
-       isc_boolean_t result = ISC_FALSE;
-       dns_adbentry_t *entry;
-       dns_adbentry_t *next_entry;
-
-       for (bucket = 0; bucket < NBUCKETS; bucket++) {
-               LOCK(&adb->entrylocks[bucket]);
-               adb->entry_sd[bucket] = ISC_TRUE;
-
-               entry = ISC_LIST_HEAD(adb->entries[bucket]);
-               if (entry == NULL) {
-                       /*
-                        * This bucket has no entries.  We must decrement the
-                        * irefcnt ourselves, since it will not be
-                        * automatically triggered by an entry being unlinked.
-                        */
-                       result = dec_adb_irefcnt(adb);
-               } else {
-                       /*
-                        * Run through the list.  Cleanup any entries not
-                        * associated with names, and which are not in use.
-                        */
-                       while (entry != NULL) {
-                               next_entry = ISC_LIST_NEXT(entry, plink);
-                               if (entry->refcnt == 0 &&
-                                   entry->expires != 0) {
-                                       result = unlink_entry(adb, entry);
-                                       free_adbentry(adb, &entry);
-                                       if (result)
-                                               result = dec_adb_irefcnt(adb);
-                               }
-                               entry = next_entry;
-                       }
-               }
-
-               UNLOCK(&adb->entrylocks[bucket]);
-       }
-       return (result);
+        int bucket;
+        isc_boolean_t result = ISC_FALSE;
+        dns_adbentry_t *entry;
+        dns_adbentry_t *next_entry;
+
+        for (bucket = 0; bucket < NBUCKETS; bucket++) {
+                LOCK(&adb->entrylocks[bucket]);
+                adb->entry_sd[bucket] = ISC_TRUE;
+
+                entry = ISC_LIST_HEAD(adb->entries[bucket]);
+                if (entry == NULL) {
+                        /*
+                         * This bucket has no entries.  We must decrement the
+                         * irefcnt ourselves, since it will not be
+                         * automatically triggered by an entry being unlinked.
+                         */
+                        result = dec_adb_irefcnt(adb);
+                } else {
+                        /*
+                         * Run through the list.  Cleanup any entries not
+                         * associated with names, and which are not in use.
+                         */
+                        while (entry != NULL) {
+                                next_entry = ISC_LIST_NEXT(entry, plink);
+                                if (entry->refcnt == 0 &&
+                                    entry->expires != 0) {
+                                        result = unlink_entry(adb, entry);
+                                        free_adbentry(adb, &entry);
+                                        if (result)
+                                                result = dec_adb_irefcnt(adb);
+                                }
+                                entry = next_entry;
+                        }
+                }
+
+                UNLOCK(&adb->entrylocks[bucket]);
+        }
+        return (result);
 }
 
 /*
@@ -897,134 +919,143 @@ shutdown_entries(dns_adb_t *adb) {
  */
 static void
 cancel_fetches_at_name(dns_adbname_t *name) {
-       if (NAME_FETCH_A(name))
-           dns_resolver_cancelfetch(name->fetch_a->fetch);
+        if (NAME_FETCH_A(name))
+            dns_resolver_cancelfetch(name->fetch_a->fetch);
 
-       if (NAME_FETCH_AAAA(name))
-           dns_resolver_cancelfetch(name->fetch_aaaa->fetch);
+        if (NAME_FETCH_AAAA(name))
+            dns_resolver_cancelfetch(name->fetch_aaaa->fetch);
 }
 
 /*
  * Assumes the name bucket is locked.
  */
 static isc_boolean_t
-clean_namehooks(dns_adb_t *adb, dns_adbnamehooklist_t *namehooks) {
-       dns_adbentry_t *entry;
-       dns_adbnamehook_t *namehook;
-       int addr_bucket;
-       isc_boolean_t result = ISC_FALSE;
-
-       addr_bucket = DNS_ADB_INVALIDBUCKET;
-       namehook = ISC_LIST_HEAD(*namehooks);
-       while (namehook != NULL) {
-               INSIST(DNS_ADBNAMEHOOK_VALID(namehook));
-
-               /*
-                * Clean up the entry if needed.
-                */
-               entry = namehook->entry;
-               if (entry != NULL) {
-                       INSIST(DNS_ADBENTRY_VALID(entry));
-
-                       if (addr_bucket != entry->lock_bucket) {
-                               if (addr_bucket != DNS_ADB_INVALIDBUCKET)
-                                       UNLOCK(&adb->entrylocks[addr_bucket]);
-                               addr_bucket = entry->lock_bucket;
-                               LOCK(&adb->entrylocks[addr_bucket]);
-                       }
-
-                       result = dec_entry_refcnt(adb, entry, ISC_FALSE);
-               }
-
-               /*
-                * Free the namehook
-                */
-               namehook->entry = NULL;
-               ISC_LIST_UNLINK(*namehooks, namehook, plink);
-               free_adbnamehook(adb, &namehook);
-
-               namehook = ISC_LIST_HEAD(*namehooks);
-       }
-
-       if (addr_bucket != DNS_ADB_INVALIDBUCKET)
-               UNLOCK(&adb->entrylocks[addr_bucket]);
-       return (result);
+clean_namehooks(dns_adb_t *adb, dns_adbnamehooklist_t *namehooks,
+                isc_boolean_t is_purge)
+{
+        dns_adbentry_t *entry;
+        dns_adbnamehook_t *namehook;
+        int addr_bucket;
+        isc_boolean_t result = ISC_FALSE;
+
+        addr_bucket = DNS_ADB_INVALIDBUCKET;
+        namehook = ISC_LIST_HEAD(*namehooks);
+        while (namehook != NULL) {
+                INSIST(DNS_ADBNAMEHOOK_VALID(namehook));
+
+                /*
+                 * Clean up the entry if needed.
+                 */
+                entry = namehook->entry;
+                if (entry != NULL) {
+                        INSIST(DNS_ADBENTRY_VALID(entry));
+
+                        if (addr_bucket != entry->lock_bucket) {
+                                if (addr_bucket != DNS_ADB_INVALIDBUCKET)
+                                        UNLOCK(&adb->entrylocks[addr_bucket]);
+                                addr_bucket = entry->lock_bucket;
+                                LOCK(&adb->entrylocks[addr_bucket]);
+                        }
+
+                        /*
+                         * If we are in an overmem situation, force expiration
+                         * so that # of names and # of entries are well
+                         * balanced.
+                         */
+                        if (is_purge)
+                                entry->expires = 0;
+                        result = dec_entry_refcnt(adb, entry, ISC_FALSE);
+                }
+
+                /*
+                 * Free the namehook
+                 */
+                namehook->entry = NULL;
+                ISC_LIST_UNLINK(*namehooks, namehook, plink);
+                free_adbnamehook(adb, &namehook);
+
+                namehook = ISC_LIST_HEAD(*namehooks);
+        }
+
+        if (addr_bucket != DNS_ADB_INVALIDBUCKET)
+                UNLOCK(&adb->entrylocks[addr_bucket]);
+        return (result);
 }
 
 static void
 clean_target(dns_adb_t *adb, dns_name_t *target) {
-       if (dns_name_countlabels(target) > 0) {
-               dns_name_free(target, adb->mctx);
-               dns_name_init(target, NULL);
-       }
+        if (dns_name_countlabels(target) > 0) {
+                dns_name_free(target, adb->mctx);
+                dns_name_init(target, NULL);
+        }
 }
 
 static isc_result_t
 set_target(dns_adb_t *adb, dns_name_t *name, dns_name_t *fname,
-          dns_rdataset_t *rdataset, dns_name_t *target)
+           dns_rdataset_t *rdataset, dns_name_t *target)
 {
-       isc_result_t result;
-       dns_namereln_t namereln;
-       unsigned int nlabels;
-       int order;
-       dns_rdata_t rdata = DNS_RDATA_INIT;
-       dns_fixedname_t fixed1, fixed2;
-       dns_name_t *prefix, *new_target;
-
-       REQUIRE(dns_name_countlabels(target) == 0);
-
-       if (rdataset->type == dns_rdatatype_cname) {
-               dns_rdata_cname_t cname;
-
-               /*
-                * Copy the CNAME's target into the target name.
-                */
-               result = dns_rdataset_first(rdataset);
-               if (result != ISC_R_SUCCESS)
-                       return (result);
-               dns_rdataset_current(rdataset, &rdata);
-               result = dns_rdata_tostruct(&rdata, &cname, NULL);
-               if (result != ISC_R_SUCCESS)
-                       return (result);
-               result = dns_name_dup(&cname.cname, adb->mctx, target);
-               dns_rdata_freestruct(&cname);
-               if (result != ISC_R_SUCCESS)
-                       return (result);
-       } else {
-               dns_rdata_dname_t dname;
-
-               INSIST(rdataset->type == dns_rdatatype_dname);
-               namereln = dns_name_fullcompare(name, fname, &order, &nlabels);
-               INSIST(namereln == dns_namereln_subdomain);
-               /*
-                * Get the target name of the DNAME.
-                */
-               result = dns_rdataset_first(rdataset);
-               if (result != ISC_R_SUCCESS)
-                       return (result);
-               dns_rdataset_current(rdataset, &rdata);
-               result = dns_rdata_tostruct(&rdata, &dname, NULL);
-               if (result != ISC_R_SUCCESS)
-                       return (result);
-               /*
-                * Construct the new target name.
-                */
-               dns_fixedname_init(&fixed1);
-               prefix = dns_fixedname_name(&fixed1);
-               dns_fixedname_init(&fixed2);
-               new_target = dns_fixedname_name(&fixed2);
-               dns_name_split(name, nlabels, prefix, NULL);
-               result = dns_name_concatenate(prefix, &dname.dname, new_target,
-                                             NULL);
-               dns_rdata_freestruct(&dname);
-               if (result != ISC_R_SUCCESS)
-                       return (result);
-               result = dns_name_dup(new_target, adb->mctx, target);
-               if (result != ISC_R_SUCCESS)
-                       return (result);
-       }
-
-       return (ISC_R_SUCCESS);
+        isc_result_t result;
+        dns_namereln_t namereln;
+        unsigned int nlabels;
+        int order;
+        dns_rdata_t rdata = DNS_RDATA_INIT;
+        dns_fixedname_t fixed1, fixed2;
+        dns_name_t *prefix, *new_target;
+
+        REQUIRE(dns_name_countlabels(target) == 0);
+
+        if (rdataset->type == dns_rdatatype_cname) {
+                dns_rdata_cname_t cname;
+
+                /*
+                 * Copy the CNAME's target into the target name.
+                 */
+                result = dns_rdataset_first(rdataset);
+                if (result != ISC_R_SUCCESS)
+                        return (result);
+                dns_rdataset_current(rdataset, &rdata);
+                result = dns_rdata_tostruct(&rdata, &cname, NULL);
+                if (result != ISC_R_SUCCESS)
+                        return (result);
+                result = dns_name_dup(&cname.cname, adb->mctx, target);
+                dns_rdata_freestruct(&cname);
+                if (result != ISC_R_SUCCESS)
+                        return (result);
+        } else {
+                dns_rdata_dname_t dname;
+
+                INSIST(rdataset->type == dns_rdatatype_dname);
+                namereln = dns_name_fullcompare(name, fname, &order, &nlabels);
+                INSIST(namereln == dns_namereln_subdomain);
+                /*
+                 * Get the target name of the DNAME.
+                 */
+                result = dns_rdataset_first(rdataset);
+                if (result != ISC_R_SUCCESS)
+                        return (result);
+                dns_rdataset_current(rdataset, &rdata);
+                result = dns_rdata_tostruct(&rdata, &dname, NULL);
+                if (result != ISC_R_SUCCESS)
+                        return (result);
+                /*
+                 * Construct the new target name.
+                 */
+                dns_fixedname_init(&fixed1);
+                prefix = dns_fixedname_name(&fixed1);
+                dns_fixedname_init(&fixed2);
+                new_target = dns_fixedname_name(&fixed2);
+                dns_name_split(name, nlabels, prefix, NULL);
+                result = dns_name_concatenate(prefix, &dname.dname, new_target,
+                                              NULL);
+                dns_rdata_freestruct(&dname);
+                if (result != ISC_R_SUCCESS)
+                        return (result);
+                result = dns_name_dup(new_target, adb->mctx, target);
+                if (result != ISC_R_SUCCESS)
+                        return (result);
+        }
+
+        return (ISC_R_SUCCESS);
 }
 
 /*
@@ -1032,16 +1063,16 @@ set_target(dns_adb_t *adb, dns_name_t *name, dns_name_t *fname,
  */
 static void
 event_free(isc_event_t *event) {
-       dns_adbfind_t *find;
+        dns_adbfind_t *find;
 
-       INSIST(event != NULL);
-       find = event->ev_destroy_arg;
-       INSIST(DNS_ADBFIND_VALID(find));
+        INSIST(event != NULL);
+        find = event->ev_destroy_arg;
+        INSIST(DNS_ADBFIND_VALID(find));
 
-       LOCK(&find->lock);
-       find->flags |= FIND_EVENT_FREED;
-       event->ev_destroy_arg = NULL;
-       UNLOCK(&find->lock);
+        LOCK(&find->lock);
+        find->flags |= FIND_EVENT_FREED;
+        event->ev_destroy_arg = NULL;
+        UNLOCK(&find->lock);
 }
 
 /*
@@ -1049,487 +1080,502 @@ event_free(isc_event_t *event) {
  */
 static void
 clean_finds_at_name(dns_adbname_t *name, isc_eventtype_t evtype,
-                   unsigned int addrs)
+                    unsigned int addrs)
 {
-       isc_event_t *ev;
-       isc_task_t *task;
-       dns_adbfind_t *find;
-       dns_adbfind_t *next_find;
-       isc_boolean_t process;
-       unsigned int wanted, notify;
-
-       DP(ENTER_LEVEL,
-          "ENTER clean_finds_at_name, name %p, evtype %08x, addrs %08x",
-          name, evtype, addrs);
-
-       find = ISC_LIST_HEAD(name->finds);
-       while (find != NULL) {
-               LOCK(&find->lock);
-               next_find = ISC_LIST_NEXT(find, plink);
-
-               process = ISC_FALSE;
-               wanted = find->flags & DNS_ADBFIND_ADDRESSMASK;
-               notify = wanted & addrs;
-
-               switch (evtype) {
-               case DNS_EVENT_ADBMOREADDRESSES:
-                       DP(ISC_LOG_DEBUG(3), "DNS_EVENT_ADBMOREADDRESSES");
-                       if ((notify) != 0) {
-                               find->flags &= ~addrs;
-                               process = ISC_TRUE;
-                       }
-                       break;
-               case DNS_EVENT_ADBNOMOREADDRESSES:
-                       DP(ISC_LOG_DEBUG(3), "DNS_EVENT_ADBNOMOREADDRESSES");
-                       find->flags &= ~addrs;
-                       wanted = find->flags & DNS_ADBFIND_ADDRESSMASK;
-                       if (wanted == 0)
-                               process = ISC_TRUE;
-                       break;
-               default:
-                       find->flags &= ~addrs;
-                       process = ISC_TRUE;
-               }
-
-               if (process) {
-                       DP(DEF_LEVEL, "cfan: processing find %p", find);
-                       /*
-                        * Unlink the find from the name, letting the caller
-                        * call dns_adb_destroyfind() on it to clean it up
-                        * later.
-                        */
-                       ISC_LIST_UNLINK(name->finds, find, plink);
-                       find->adbname = NULL;
-                       find->name_bucket = DNS_ADB_INVALIDBUCKET;
-
-                       INSIST(!FIND_EVENTSENT(find));
-
-                       ev = &find->event;
-                       task = ev->ev_sender;
-                       ev->ev_sender = find;
-                       find->result_v4 = find_err_map[name->fetch_err];
-                       find->result_v6 = find_err_map[name->fetch6_err];
-                       ev->ev_type = evtype;
-                       ev->ev_destroy = event_free;
-                       ev->ev_destroy_arg = find;
-
-                       DP(DEF_LEVEL,
-                          "sending event %p to task %p for find %p",
-                          ev, task, find);
-
-                       isc_task_sendanddetach(&task, (isc_event_t **)&ev);
-               } else {
-                       DP(DEF_LEVEL, "cfan: skipping find %p", find);
-               }
-
-               UNLOCK(&find->lock);
-               find = next_find;
-       }
-
-       DP(ENTER_LEVEL, "EXIT clean_finds_at_name, name %p", name);
+        isc_event_t *ev;
+        isc_task_t *task;
+        dns_adbfind_t *find;
+        dns_adbfind_t *next_find;
+        isc_boolean_t process;
+        unsigned int wanted, notify;
+
+        DP(ENTER_LEVEL,
+           "ENTER clean_finds_at_name, name %p, evtype %08x, addrs %08x",
+           name, evtype, addrs);
+
+        find = ISC_LIST_HEAD(name->finds);
+        while (find != NULL) {
+                LOCK(&find->lock);
+                next_find = ISC_LIST_NEXT(find, plink);
+
+                process = ISC_FALSE;
+                wanted = find->flags & DNS_ADBFIND_ADDRESSMASK;
+                notify = wanted & addrs;
+
+                switch (evtype) {
+                case DNS_EVENT_ADBMOREADDRESSES:
+                        DP(ISC_LOG_DEBUG(3), "DNS_EVENT_ADBMOREADDRESSES");
+                        if ((notify) != 0) {
+                                find->flags &= ~addrs;
+                                process = ISC_TRUE;
+                        }
+                        break;
+                case DNS_EVENT_ADBNOMOREADDRESSES:
+                        DP(ISC_LOG_DEBUG(3), "DNS_EVENT_ADBNOMOREADDRESSES");
+                        find->flags &= ~addrs;
+                        wanted = find->flags & DNS_ADBFIND_ADDRESSMASK;
+                        if (wanted == 0)
+                                process = ISC_TRUE;
+                        break;
+                default:
+                        find->flags &= ~addrs;
+                        process = ISC_TRUE;
+                }
+
+                if (process) {
+                        DP(DEF_LEVEL, "cfan: processing find %p", find);
+                        /*
+                         * Unlink the find from the name, letting the caller
+                         * call dns_adb_destroyfind() on it to clean it up
+                         * later.
+                         */
+                        ISC_LIST_UNLINK(name->finds, find, plink);
+                        find->adbname = NULL;
+                        find->name_bucket = DNS_ADB_INVALIDBUCKET;
+
+                        INSIST(!FIND_EVENTSENT(find));
+
+                        ev = &find->event;
+                        task = ev->ev_sender;
+                        ev->ev_sender = find;
+                        find->result_v4 = find_err_map[name->fetch_err];
+                        find->result_v6 = find_err_map[name->fetch6_err];
+                        ev->ev_type = evtype;
+                        ev->ev_destroy = event_free;
+                        ev->ev_destroy_arg = find;
+
+                        DP(DEF_LEVEL,
+                           "sending event %p to task %p for find %p",
+                           ev, task, find);
+
+                        isc_task_sendanddetach(&task, (isc_event_t **)&ev);
+                } else {
+                        DP(DEF_LEVEL, "cfan: skipping find %p", find);
+                }
+
+                UNLOCK(&find->lock);
+                find = next_find;
+        }
+
+        DP(ENTER_LEVEL, "EXIT clean_finds_at_name, name %p", name);
 }
 
 static inline void
 check_exit(dns_adb_t *adb) {
-       isc_event_t *event;
-       /*
-        * The caller must be holding the adb lock.
-        */
-       if (adb->shutting_down) {
-               /*
-                * If there aren't any external references either, we're
-                * done.  Send the control event to initiate shutdown.
-                */
-               INSIST(!adb->cevent_sent);      /* Sanity check. */
-               event = &adb->cevent;
-               isc_task_send(adb->task, &event);
-               adb->cevent_sent = ISC_TRUE;
-       }
+        isc_event_t *event;
+        /*
+         * The caller must be holding the adb lock.
+         */
+        if (adb->shutting_down) {
+                /*
+                 * If there aren't any external references either, we're
+                 * done.  Send the control event to initiate shutdown.
+                 */
+                INSIST(!adb->cevent_sent);      /* Sanity check. */
+                event = &adb->cevent;
+                isc_task_send(adb->task, &event);
+                adb->cevent_sent = ISC_TRUE;
+        }
 }
 
 static inline isc_boolean_t
 dec_adb_irefcnt(dns_adb_t *adb) {
-       isc_event_t *event;
-       isc_task_t *etask;
-       isc_boolean_t result = ISC_FALSE;
+        isc_event_t *event;
+        isc_task_t *etask;
+        isc_boolean_t result = ISC_FALSE;
 
-       LOCK(&adb->reflock);
+        LOCK(&adb->reflock);
 
-       INSIST(adb->irefcnt > 0);
-       adb->irefcnt--;
+        INSIST(adb->irefcnt > 0);
+        adb->irefcnt--;
 
-       if (adb->irefcnt == 0) {
-               event = ISC_LIST_HEAD(adb->whenshutdown);
-               while (event != NULL) {
-                       ISC_LIST_UNLINK(adb->whenshutdown, event, ev_link);
-                       etask = event->ev_sender;
-                       event->ev_sender = adb;
-                       isc_task_sendanddetach(&etask, &event);
-                       event = ISC_LIST_HEAD(adb->whenshutdown);
-               }
-       }
+        if (adb->irefcnt == 0) {
+                event = ISC_LIST_HEAD(adb->whenshutdown);
+                while (event != NULL) {
+                        ISC_LIST_UNLINK(adb->whenshutdown, event, ev_link);
+                        etask = event->ev_sender;
+                        event->ev_sender = adb;
+                        isc_task_sendanddetach(&etask, &event);
+                        event = ISC_LIST_HEAD(adb->whenshutdown);
+                }
+        }
 
-       if (adb->irefcnt == 0 && adb->erefcnt == 0)
-               result = ISC_TRUE;
-       UNLOCK(&adb->reflock);
-       return (result);
+        if (adb->irefcnt == 0 && adb->erefcnt == 0)
+                result = ISC_TRUE;
+        UNLOCK(&adb->reflock);
+        return (result);
 }
 
 static inline void
 inc_adb_irefcnt(dns_adb_t *adb) {
-       LOCK(&adb->reflock);
-       adb->irefcnt++;
-       UNLOCK(&adb->reflock);
+        LOCK(&adb->reflock);
+        adb->irefcnt++;
+        UNLOCK(&adb->reflock);
 }
 
 static inline void
 inc_adb_erefcnt(dns_adb_t *adb) {
-       LOCK(&adb->reflock);
-       adb->erefcnt++;
-       UNLOCK(&adb->reflock);
+        LOCK(&adb->reflock);
+        adb->erefcnt++;
+        UNLOCK(&adb->reflock);
 }
 
 static inline void
 inc_entry_refcnt(dns_adb_t *adb, dns_adbentry_t *entry, isc_boolean_t lock) {
-       int bucket;
+        int bucket;
 
-       bucket = entry->lock_bucket;
+        bucket = entry->lock_bucket;
 
-       if (lock)
-               LOCK(&adb->entrylocks[bucket]);
+        if (lock)
+                LOCK(&adb->entrylocks[bucket]);
 
-       entry->refcnt++;
+        entry->refcnt++;
 
-       if (lock)
-               UNLOCK(&adb->entrylocks[bucket]);
+        if (lock)
+                UNLOCK(&adb->entrylocks[bucket]);
 }
 
 static inline isc_boolean_t
 dec_entry_refcnt(dns_adb_t *adb, dns_adbentry_t *entry, isc_boolean_t lock) {
-       int bucket;
-       isc_boolean_t destroy_entry;
-       isc_boolean_t result = ISC_FALSE;
+        int bucket;
+        isc_boolean_t destroy_entry;
+        isc_boolean_t result = ISC_FALSE;
 
-       bucket = entry->lock_bucket;
+        bucket = entry->lock_bucket;
 
-       if (lock)
-               LOCK(&adb->entrylocks[bucket]);
+        if (lock)
+                LOCK(&adb->entrylocks[bucket]);
 
-       INSIST(entry->refcnt > 0);
-       entry->refcnt--;
+        INSIST(entry->refcnt > 0);
+        entry->refcnt--;
 
-       destroy_entry = ISC_FALSE;
-       if (entry->refcnt == 0 &&
-           (adb->entry_sd[bucket] || entry->expires == 0)) {
-               destroy_entry = ISC_TRUE;
-               result = unlink_entry(adb, entry);
-       }
+        destroy_entry = ISC_FALSE;
+        if (entry->refcnt == 0 &&
+            (adb->entry_sd[bucket] || entry->expires == 0)) {
+                destroy_entry = ISC_TRUE;
+                result = unlink_entry(adb, entry);
+        }
 
-       if (lock)
-               UNLOCK(&adb->entrylocks[bucket]);
+        if (lock)
+                UNLOCK(&adb->entrylocks[bucket]);
 
-       if (!destroy_entry)
-               return (result);
+        if (!destroy_entry)
+                return (result);
 
-       entry->lock_bucket = DNS_ADB_INVALIDBUCKET;
+        entry->lock_bucket = DNS_ADB_INVALIDBUCKET;
 
-       free_adbentry(adb, &entry);
-       if (result)
-               result =dec_adb_irefcnt(adb);
+        free_adbentry(adb, &entry);
+        if (result)
+                result =dec_adb_irefcnt(adb);
 
-       return (result);
+        return (result);
 }
 
 static inline dns_adbname_t *
 new_adbname(dns_adb_t *adb, dns_name_t *dnsname) {
-       dns_adbname_t *name;
-
-       name = isc_mempool_get(adb->nmp);
-       if (name == NULL)
-               return (NULL);
-
-       dns_name_init(&name->name, NULL);
-       if (dns_name_dup(dnsname, adb->mctx, &name->name) != ISC_R_SUCCESS) {
-               isc_mempool_put(adb->nmp, name);
-               return (NULL);
-       }
-       dns_name_init(&name->target, NULL);
-       name->magic = DNS_ADBNAME_MAGIC;
-       name->adb = adb;
-       name->partial_result = 0;
-       name->flags = 0;
-       name->expire_v4 = INT_MAX;
-       name->expire_v6 = INT_MAX;
-       name->expire_target = INT_MAX;
-       name->chains = 0;
-       name->lock_bucket = DNS_ADB_INVALIDBUCKET;
-       ISC_LIST_INIT(name->v4);
-       ISC_LIST_INIT(name->v6);
-       name->fetch_a = NULL;
-       name->fetch_aaaa = NULL;
-       name->fetch_err = FIND_ERR_UNEXPECTED;
-       name->fetch6_err = FIND_ERR_UNEXPECTED;
-       ISC_LIST_INIT(name->finds);
-       ISC_LINK_INIT(name, plink);
-
-       return (name);
+        dns_adbname_t *name;
+
+        name = isc_mempool_get(adb->nmp);
+        if (name == NULL)
+                return (NULL);
+
+        dns_name_init(&name->name, NULL);
+        if (dns_name_dup(dnsname, adb->mctx, &name->name) != ISC_R_SUCCESS) {
+                isc_mempool_put(adb->nmp, name);
+                return (NULL);
+        }
+        dns_name_init(&name->target, NULL);
+        name->magic = DNS_ADBNAME_MAGIC;
+        name->adb = adb;
+        name->partial_result = 0;
+        name->flags = 0;
+        name->expire_v4 = INT_MAX;
+        name->expire_v6 = INT_MAX;
+        name->expire_target = INT_MAX;
+        name->chains = 0;
+        name->lock_bucket = DNS_ADB_INVALIDBUCKET;
+        ISC_LIST_INIT(name->v4);
+        ISC_LIST_INIT(name->v6);
+        name->fetch_a = NULL;
+        name->fetch_aaaa = NULL;
+        name->fetch_err = FIND_ERR_UNEXPECTED;
+        name->fetch6_err = FIND_ERR_UNEXPECTED;
+        ISC_LIST_INIT(name->finds);
+        ISC_LINK_INIT(name, plink);
+
+        return (name);
 }
 
 static inline void
 free_adbname(dns_adb_t *adb, dns_adbname_t **name) {
-       dns_adbname_t *n;
-
-       INSIST(name != NULL && DNS_ADBNAME_VALID(*name));
-       n = *name;
-       *name = NULL;
-
-       INSIST(!NAME_HAS_V4(n));
-       INSIST(!NAME_HAS_V6(n));
-       INSIST(!NAME_FETCH(n));
-       INSIST(ISC_LIST_EMPTY(n->finds));
-       INSIST(!ISC_LINK_LINKED(n, plink));
-       INSIST(n->lock_bucket == DNS_ADB_INVALIDBUCKET);
-       INSIST(n->adb == adb);
+        dns_adbname_t *n;
+
+        INSIST(name != NULL && DNS_ADBNAME_VALID(*name));
+        n = *name;
+        *name = NULL;
+
+        INSIST(!NAME_HAS_V4(n));
+        INSIST(!NAME_HAS_V6(n));
+        INSIST(!NAME_FETCH(n));
+        INSIST(ISC_LIST_EMPTY(n->finds));
+        INSIST(!ISC_LINK_LINKED(n, plink));
+        INSIST(n->lock_bucket == DNS_ADB_INVALIDBUCKET);
+        INSIST(n->adb == adb);
+
+#ifdef LRU_DEBUG
+        adb->nname--;           /* XXX: omit ADB lock for brevity */
+        INSIST((int)adb->nname >= 0);
+#endif
 
-       n->magic = 0;
-       dns_name_free(&n->name, adb->mctx);
+        n->magic = 0;
+        dns_name_free(&n->name, adb->mctx);
 
-       isc_mempool_put(adb->nmp, n);
+        isc_mempool_put(adb->nmp, n);
 }
 
 static inline dns_adbnamehook_t *
 new_adbnamehook(dns_adb_t *adb, dns_adbentry_t *entry) {
-       dns_adbnamehook_t *nh;
+        dns_adbnamehook_t *nh;
 
-       nh = isc_mempool_get(adb->nhmp);
-       if (nh == NULL)
-               return (NULL);
+        nh = isc_mempool_get(adb->nhmp);
+        if (nh == NULL)
+                return (NULL);
 
-       nh->magic = DNS_ADBNAMEHOOK_MAGIC;
-       nh->entry = entry;
-       ISC_LINK_INIT(nh, plink);
+        nh->magic = DNS_ADBNAMEHOOK_MAGIC;
+        nh->entry = entry;
+        ISC_LINK_INIT(nh, plink);
 
-       return (nh);
+        return (nh);
 }
 
 static inline void
 free_adbnamehook(dns_adb_t *adb, dns_adbnamehook_t **namehook) {
-       dns_adbnamehook_t *nh;
+        dns_adbnamehook_t *nh;
 
-       INSIST(namehook != NULL && DNS_ADBNAMEHOOK_VALID(*namehook));
-       nh = *namehook;
-       *namehook = NULL;
+        INSIST(namehook != NULL && DNS_ADBNAMEHOOK_VALID(*namehook));
+        nh = *namehook;
+        *namehook = NULL;
 
-       INSIST(nh->entry == NULL);
-       INSIST(!ISC_LINK_LINKED(nh, plink));
+        INSIST(nh->entry == NULL);
+        INSIST(!ISC_LINK_LINKED(nh, plink));
 
-       nh->magic = 0;
-       isc_mempool_put(adb->nhmp, nh);
+        nh->magic = 0;
+        isc_mempool_put(adb->nhmp, nh);
 }
 
 static inline dns_adblameinfo_t *
 new_adblameinfo(dns_adb_t *adb, dns_name_t *qname, dns_rdatatype_t qtype) {
-       dns_adblameinfo_t *li;
+        dns_adblameinfo_t *li;
 
-       li = isc_mempool_get(adb->limp);
-       if (li == NULL)
-               return (NULL);
+        li = isc_mempool_get(adb->limp);
+        if (li == NULL)
+                return (NULL);
 
-       dns_name_init(&li->qname, NULL);
-       if (dns_name_dup(qname, adb->mctx, &li->qname) != ISC_R_SUCCESS) {
-               isc_mempool_put(adb->limp, li);
-               return (NULL);
-       }
-       li->magic = DNS_ADBLAMEINFO_MAGIC;
-       li->lame_timer = 0;
-       li->qtype = qtype;
-       ISC_LINK_INIT(li, plink);
+        dns_name_init(&li->qname, NULL);
+        if (dns_name_dup(qname, adb->mctx, &li->qname) != ISC_R_SUCCESS) {
+                isc_mempool_put(adb->limp, li);
+                return (NULL);
+        }
+        li->magic = DNS_ADBLAMEINFO_MAGIC;
+        li->lame_timer = 0;
+        li->qtype = qtype;
+        ISC_LINK_INIT(li, plink);
 
-       return (li);
+        return (li);
 }
 
 static inline void
 free_adblameinfo(dns_adb_t *adb, dns_adblameinfo_t **lameinfo) {
-       dns_adblameinfo_t *li;
+        dns_adblameinfo_t *li;
 
-       INSIST(lameinfo != NULL && DNS_ADBLAMEINFO_VALID(*lameinfo));
-       li = *lameinfo;
-       *lameinfo = NULL;
+        INSIST(lameinfo != NULL && DNS_ADBLAMEINFO_VALID(*lameinfo));
+        li = *lameinfo;
+        *lameinfo = NULL;
 
-       INSIST(!ISC_LINK_LINKED(li, plink));
+        INSIST(!ISC_LINK_LINKED(li, plink));
 
-       dns_name_free(&li->qname, adb->mctx);
+        dns_name_free(&li->qname, adb->mctx);
 
-       li->magic = 0;
+        li->magic = 0;
 
-       isc_mempool_put(adb->limp, li);
+        isc_mempool_put(adb->limp, li);
 }
 
 static inline dns_adbentry_t *
 new_adbentry(dns_adb_t *adb) {
-       dns_adbentry_t *e;
-       isc_uint32_t r;
-
-       e = isc_mempool_get(adb->emp);
-       if (e == NULL)
-               return (NULL);
-
-       e->magic = DNS_ADBENTRY_MAGIC;
-       e->lock_bucket = DNS_ADB_INVALIDBUCKET;
-       e->refcnt = 0;
-       e->flags = 0;
-       isc_random_get(&r);
-       e->srtt = (r & 0x1f) + 1;
-       e->expires = 0;
-       ISC_LIST_INIT(e->lameinfo);
-       ISC_LINK_INIT(e, plink);
+        dns_adbentry_t *e;
+        isc_uint32_t r;
+
+        e = isc_mempool_get(adb->emp);
+        if (e == NULL)
+                return (NULL);
+
+        e->magic = DNS_ADBENTRY_MAGIC;
+        e->lock_bucket = DNS_ADB_INVALIDBUCKET;
+        e->refcnt = 0;
+        e->flags = 0;
+        isc_random_get(&r);
+        e->srtt = (r & 0x1f) + 1;
+        e->expires = 0;
+        ISC_LIST_INIT(e->lameinfo);
+        ISC_LINK_INIT(e, plink);
+
+#ifdef LRU_DEBUG
+        adb->nentry++;  /* XXX: omit ADB lock for brevity */
+        adb->nentry_total++;
+#endif
 
-       return (e);
+        return (e);
 }
 
 static inline void
 free_adbentry(dns_adb_t *adb, dns_adbentry_t **entry) {
-       dns_adbentry_t *e;
-       dns_adblameinfo_t *li;
+        dns_adbentry_t *e;
+        dns_adblameinfo_t *li;
+
+        INSIST(entry != NULL && DNS_ADBENTRY_VALID(*entry));
+        e = *entry;
+        *entry = NULL;
 
-       INSIST(entry != NULL && DNS_ADBENTRY_VALID(*entry));
-       e = *entry;
-       *entry = NULL;
+        INSIST(e->lock_bucket == DNS_ADB_INVALIDBUCKET);
+        INSIST(e->refcnt == 0);
+        INSIST(!ISC_LINK_LINKED(e, plink));
 
-       INSIST(e->lock_bucket == DNS_ADB_INVALIDBUCKET);
-       INSIST(e->refcnt == 0);
-       INSIST(!ISC_LINK_LINKED(e, plink));
+        e->magic = 0;
 
-       e->magic = 0;
+        li = ISC_LIST_HEAD(e->lameinfo);
+        while (li != NULL) {
+                ISC_LIST_UNLINK(e->lameinfo, li, plink);
+                free_adblameinfo(adb, &li);
+                li = ISC_LIST_HEAD(e->lameinfo);
+        }
 
-       li = ISC_LIST_HEAD(e->lameinfo);
-       while (li != NULL) {
-               ISC_LIST_UNLINK(e->lameinfo, li, plink);
-               free_adblameinfo(adb, &li);
-               li = ISC_LIST_HEAD(e->lameinfo);
-       }
+#ifdef LRU_DEBUG
+        adb->nentry--;  /* XXX: omit ADB lock for brevity */
+        INSIST((int)adb->nentry >= 0);
+#endif
 
-       isc_mempool_put(adb->emp, e);
+        isc_mempool_put(adb->emp, e);
 }
 
 static inline dns_adbfind_t *
 new_adbfind(dns_adb_t *adb) {
-       dns_adbfind_t *h;
-       isc_result_t result;
-
-       h = isc_mempool_get(adb->ahmp);
-       if (h == NULL)
-               return (NULL);
-
-       /*
-        * Public members.
-        */
-       h->magic = 0;
-       h->adb = adb;
-       h->partial_result = 0;
-       h->options = 0;
-       h->flags = 0;
-       h->result_v4 = ISC_R_UNEXPECTED;
-       h->result_v6 = ISC_R_UNEXPECTED;
-       ISC_LINK_INIT(h, publink);
-       ISC_LINK_INIT(h, plink);
-       ISC_LIST_INIT(h->list);
-       h->adbname = NULL;
-       h->name_bucket = DNS_ADB_INVALIDBUCKET;
-
-       /*
-        * private members
-        */
-       result = isc_mutex_init(&h->lock);
-       if (result != ISC_R_SUCCESS) {
-               isc_mempool_put(adb->ahmp, h);
-               return (NULL);
-       }
-
-       ISC_EVENT_INIT(&h->event, sizeof(isc_event_t), 0, 0, 0, NULL, NULL,
-                      NULL, NULL, h);
-
-       inc_adb_irefcnt(adb);
-       h->magic = DNS_ADBFIND_MAGIC;
-       return (h);
+        dns_adbfind_t *h;
+        isc_result_t result;
+
+        h = isc_mempool_get(adb->ahmp);
+        if (h == NULL)
+                return (NULL);
+
+        /*
+         * Public members.
+         */
+        h->magic = 0;
+        h->adb = adb;
+        h->partial_result = 0;
+        h->options = 0;
+        h->flags = 0;
+        h->result_v4 = ISC_R_UNEXPECTED;
+        h->result_v6 = ISC_R_UNEXPECTED;
+        ISC_LINK_INIT(h, publink);
+        ISC_LINK_INIT(h, plink);
+        ISC_LIST_INIT(h->list);
+        h->adbname = NULL;
+        h->name_bucket = DNS_ADB_INVALIDBUCKET;
+
+        /*
+         * private members
+         */
+        result = isc_mutex_init(&h->lock);
+        if (result != ISC_R_SUCCESS) {
+                isc_mempool_put(adb->ahmp, h);
+                return (NULL);
+        }
+
+        ISC_EVENT_INIT(&h->event, sizeof(isc_event_t), 0, 0, 0, NULL, NULL,
+                       NULL, NULL, h);
+
+        inc_adb_irefcnt(adb);
+        h->magic = DNS_ADBFIND_MAGIC;
+        return (h);
 }
 
 static inline dns_adbfetch_t *
 new_adbfetch(dns_adb_t *adb) {
-       dns_adbfetch_t *f;
+        dns_adbfetch_t *f;
 
-       f = isc_mempool_get(adb->afmp);
-       if (f == NULL)
-               return (NULL);
+        f = isc_mempool_get(adb->afmp);
+        if (f == NULL)
+                return (NULL);
 
-       f->magic = 0;
-       f->namehook = NULL;
-       f->entry = NULL;
-       f->fetch = NULL;
+        f->magic = 0;
+        f->namehook = NULL;
+        f->entry = NULL;
+        f->fetch = NULL;
 
-       f->namehook = new_adbnamehook(adb, NULL);
-       if (f->namehook == NULL)
-               goto err;
+        f->namehook = new_adbnamehook(adb, NULL);
+        if (f->namehook == NULL)
+                goto err;
 
-       f->entry = new_adbentry(adb);
-       if (f->entry == NULL)
-               goto err;
+        f->entry = new_adbentry(adb);
+        if (f->entry == NULL)
+                goto err;
 
-       dns_rdataset_init(&f->rdataset);
+        dns_rdataset_init(&f->rdataset);
 
-       f->magic = DNS_ADBFETCH_MAGIC;
+        f->magic = DNS_ADBFETCH_MAGIC;
 
-       return (f);
+        return (f);
 
  err:
-       if (f->namehook != NULL)
-               free_adbnamehook(adb, &f->namehook);
-       if (f->entry != NULL)
-               free_adbentry(adb, &f->entry);
-       isc_mempool_put(adb->afmp, f);
-       return (NULL);
+        if (f->namehook != NULL)
+                free_adbnamehook(adb, &f->namehook);
+        if (f->entry != NULL)
+                free_adbentry(adb, &f->entry);
+        isc_mempool_put(adb->afmp, f);
+        return (NULL);
 }
 
 static inline void
 free_adbfetch(dns_adb_t *adb, dns_adbfetch_t **fetch) {
-       dns_adbfetch_t *f;
+        dns_adbfetch_t *f;
 
-       INSIST(fetch != NULL && DNS_ADBFETCH_VALID(*fetch));
-       f = *fetch;
-       *fetch = NULL;
+        INSIST(fetch != NULL && DNS_ADBFETCH_VALID(*fetch));
+        f = *fetch;
+        *fetch = NULL;
 
-       f->magic = 0;
+        f->magic = 0;
 
-       if (f->namehook != NULL)
-               free_adbnamehook(adb, &f->namehook);
-       if (f->entry != NULL)
-               free_adbentry(adb, &f->entry);
+        if (f->namehook != NULL)
+                free_adbnamehook(adb, &f->namehook);
+        if (f->entry != NULL)
+                free_adbentry(adb, &f->entry);
 
-       if (dns_rdataset_isassociated(&f->rdataset))
-               dns_rdataset_disassociate(&f->rdataset);
+        if (dns_rdataset_isassociated(&f->rdataset))
+                dns_rdataset_disassociate(&f->rdataset);
 
-       isc_mempool_put(adb->afmp, f);
+        isc_mempool_put(adb->afmp, f);
 }
 
 static inline isc_boolean_t
 free_adbfind(dns_adb_t *adb, dns_adbfind_t **findp) {
-       dns_adbfind_t *find;
+        dns_adbfind_t *find;
 
-       INSIST(findp != NULL && DNS_ADBFIND_VALID(*findp));
-       find = *findp;
-       *findp = NULL;
+        INSIST(findp != NULL && DNS_ADBFIND_VALID(*findp));
+        find = *findp;
+        *findp = NULL;
 
-       INSIST(!FIND_HAS_ADDRS(find));
-       INSIST(!ISC_LINK_LINKED(find, publink));
-       INSIST(!ISC_LINK_LINKED(find, plink));
-       INSIST(find->name_bucket == DNS_ADB_INVALIDBUCKET);
-       INSIST(find->adbname == NULL);
+        INSIST(!FIND_HAS_ADDRS(find));
+        INSIST(!ISC_LINK_LINKED(find, publink));
+        INSIST(!ISC_LINK_LINKED(find, plink));
+        INSIST(find->name_bucket == DNS_ADB_INVALIDBUCKET);
+        INSIST(find->adbname == NULL);
 
-       find->magic = 0;
+        find->magic = 0;
 
-       DESTROYLOCK(&find->lock);
-       isc_mempool_put(adb->ahmp, find);
-       return (dec_adb_irefcnt(adb));
+        DESTROYLOCK(&find->lock);
+        isc_mempool_put(adb->ahmp, find);
+        return (dec_adb_irefcnt(adb));
 }
 
 /*
@@ -1539,37 +1585,41 @@ free_adbfind(dns_adb_t *adb, dns_adbfind_t **findp) {
  */
 static inline dns_adbaddrinfo_t *
 new_adbaddrinfo(dns_adb_t *adb, dns_adbentry_t *entry, in_port_t port) {
-       dns_adbaddrinfo_t *ai;
-
-       ai = isc_mempool_get(adb->aimp);
-       if (ai == NULL)
-               return (NULL);
-
-       ai->magic = DNS_ADBADDRINFO_MAGIC;
-       ai->sockaddr = entry->sockaddr;
-       isc_sockaddr_setport(&ai->sockaddr, port);
-       ai->srtt = entry->srtt;
-       ai->flags = entry->flags;
-       ai->entry = entry;
-       ISC_LINK_INIT(ai, publink);
+        dns_adbaddrinfo_t *ai;
+
+        ai = isc_mempool_get(adb->aimp);
+        if (ai == NULL)
+                return (NULL);
+
+        ai->magic = DNS_ADBADDRINFO_MAGIC;
+        ai->sockaddr = entry->sockaddr;
+        isc_sockaddr_setport(&ai->sockaddr, port);
+        ai->srtt = entry->srtt;
+        ai->flags = entry->flags;
+        ai->entry = entry;
+        ISC_LINK_INIT(ai, publink);
+
+#ifdef LRU_DEBUG
+        adb->entryuses++;       /* for debug */
+#endif
 
-       return (ai);
+        return (ai);
 }
 
 static inline void
 free_adbaddrinfo(dns_adb_t *adb, dns_adbaddrinfo_t **ainfo) {
-       dns_adbaddrinfo_t *ai;
+        dns_adbaddrinfo_t *ai;
 
-       INSIST(ainfo != NULL && DNS_ADBADDRINFO_VALID(*ainfo));
-       ai = *ainfo;
-       *ainfo = NULL;
+        INSIST(ainfo != NULL && DNS_ADBADDRINFO_VALID(*ainfo));
+        ai = *ainfo;
+        *ainfo = NULL;
 
-       INSIST(ai->entry == NULL);
-       INSIST(!ISC_LINK_LINKED(ai, publink));
+        INSIST(ai->entry == NULL);
+        INSIST(!ISC_LINK_LINKED(ai, publink));
 
-       ai->magic = 0;
+        ai->magic = 0;
 
-       isc_mempool_put(adb->aimp, ai);
+        isc_mempool_put(adb->aimp, ai);
 }
 
 /*
@@ -1581,34 +1631,34 @@ free_adbaddrinfo(dns_adb_t *adb, dns_adbaddrinfo_t **ainfo) {
  */
 static inline dns_adbname_t *
 find_name_and_lock(dns_adb_t *adb, dns_name_t *name,
-                  unsigned int options, int *bucketp)
+                   unsigned int options, int *bucketp)
 {
-       dns_adbname_t *adbname;
-       int bucket;
-
-       bucket = dns_name_fullhash(name, ISC_FALSE) % NBUCKETS;
-
-       if (*bucketp == DNS_ADB_INVALIDBUCKET) {
-               LOCK(&adb->namelocks[bucket]);
-               *bucketp = bucket;
-       } else if (*bucketp != bucket) {
-               UNLOCK(&adb->namelocks[*bucketp]);
-               LOCK(&adb->namelocks[bucket]);
-               *bucketp = bucket;
-       }
-
-       adbname = ISC_LIST_HEAD(adb->names[bucket]);
-       while (adbname != NULL) {
-               if (!NAME_DEAD(adbname)) {
-                       if (dns_name_equal(name, &adbname->name)
-                           && GLUEHINT_OK(adbname, options)
-                           && STARTATZONE_MATCHES(adbname, options))
-                               return (adbname);
-               }
-               adbname = ISC_LIST_NEXT(adbname, plink);
-       }
-
-       return (NULL);
+        dns_adbname_t *adbname;
+        int bucket;
+
+        bucket = dns_name_fullhash(name, ISC_FALSE) % NBUCKETS;
+
+        if (*bucketp == DNS_ADB_INVALIDBUCKET) {
+                LOCK(&adb->namelocks[bucket]);
+                *bucketp = bucket;
+        } else if (*bucketp != bucket) {
+                UNLOCK(&adb->namelocks[*bucketp]);
+                LOCK(&adb->namelocks[bucket]);
+                *bucketp = bucket;
+        }
+
+        adbname = ISC_LIST_HEAD(adb->names[bucket]);
+        while (adbname != NULL) {
+                if (!NAME_DEAD(adbname)) {
+                        if (dns_name_equal(name, &adbname->name)
+                            && GLUEHINT_OK(adbname, options)
+                            && STARTATZONE_MATCHES(adbname, options))
+                                return (adbname);
+                }
+                adbname = ISC_LIST_NEXT(adbname, plink);
+        }
+
+        return (NULL);
 }
 
 /*
@@ -1623,28 +1673,28 @@ find_name_and_lock(dns_adb_t *adb, dns_name_t *name,
  */
 static inline dns_adbentry_t *
 find_entry_and_lock(dns_adb_t *adb, isc_sockaddr_t *addr, int *bucketp) {
-       dns_adbentry_t *entry;
-       int bucket;
+        dns_adbentry_t *entry;
+        int bucket;
 
-       bucket = isc_sockaddr_hash(addr, ISC_TRUE) % NBUCKETS;
+        bucket = isc_sockaddr_hash(addr, ISC_TRUE) % NBUCKETS;
 
-       if (*bucketp == DNS_ADB_INVALIDBUCKET) {
-               LOCK(&adb->entrylocks[bucket]);
-               *bucketp = bucket;
-       } else if (*bucketp != bucket) {
-               UNLOCK(&adb->entrylocks[*bucketp]);
-               LOCK(&adb->entrylocks[bucket]);
-               *bucketp = bucket;
-       }
+        if (*bucketp == DNS_ADB_INVALIDBUCKET) {
+                LOCK(&adb->entrylocks[bucket]);
+                *bucketp = bucket;
+        } else if (*bucketp != bucket) {
+                UNLOCK(&adb->entrylocks[*bucketp]);
+                LOCK(&adb->entrylocks[bucket]);
+                *bucketp = bucket;
+        }
 
-       entry = ISC_LIST_HEAD(adb->entries[bucket]);
-       while (entry != NULL) {
-               if (isc_sockaddr_equal(addr, &entry->sockaddr))
-                       return (entry);
-               entry = ISC_LIST_NEXT(entry, plink);
-       }
+        entry = ISC_LIST_HEAD(adb->entries[bucket]);
+        while (entry != NULL) {
+                if (isc_sockaddr_equal(addr, &entry->sockaddr))
+                        return (entry);
+                entry = ISC_LIST_NEXT(entry, plink);
+        }
 
-       return (NULL);
+        return (NULL);
 }
 
 /*
@@ -1652,137 +1702,140 @@ find_entry_and_lock(dns_adb_t *adb, isc_sockaddr_t *addr, int *bucketp) {
  */
 static isc_boolean_t
 entry_is_lame(dns_adb_t *adb, dns_adbentry_t *entry, dns_name_t *qname,
-             dns_rdatatype_t qtype, isc_stdtime_t now)
+              dns_rdatatype_t qtype, isc_stdtime_t now)
 {
-       dns_adblameinfo_t *li, *next_li;
-       isc_boolean_t is_bad;
+        dns_adblameinfo_t *li, *next_li;
+        isc_boolean_t is_bad;
 
-       is_bad = ISC_FALSE;
+        is_bad = ISC_FALSE;
 
-       li = ISC_LIST_HEAD(entry->lameinfo);
-       if (li == NULL)
-               return (ISC_FALSE);
-       while (li != NULL) {
-               next_li = ISC_LIST_NEXT(li, plink);
+        li = ISC_LIST_HEAD(entry->lameinfo);
+        if (li == NULL)
+                return (ISC_FALSE);
+        while (li != NULL) {
+                next_li = ISC_LIST_NEXT(li, plink);
 
-               /*
-                * Has the entry expired?
-                */
-               if (li->lame_timer < now) {
-                       ISC_LIST_UNLINK(entry->lameinfo, li, plink);
-                       free_adblameinfo(adb, &li);
-               }
+                /*
+                 * Has the entry expired?
+                 */
+                if (li->lame_timer < now) {
+                        ISC_LIST_UNLINK(entry->lameinfo, li, plink);
+                        free_adblameinfo(adb, &li);
+                }
 
-               /*
-                * Order tests from least to most expensive.
-                *
-                * We do not break out of the main loop here as
-                * we use the loop for house keeping.
-                */
-               if (li != NULL && !is_bad && li->qtype == qtype &&
-                   dns_name_equal(qname, &li->qname))
-                       is_bad = ISC_TRUE;
+                /*
+                 * Order tests from least to most expensive.
+                 *
+                 * We do not break out of the main loop here as
+                 * we use the loop for house keeping.
+                 */
+                if (li != NULL && !is_bad && li->qtype == qtype &&
+                    dns_name_equal(qname, &li->qname))
+                        is_bad = ISC_TRUE;
 
-               li = next_li;
-       }
+                li = next_li;
+        }
 
-       return (is_bad);
+        return (is_bad);
 }
 
 static void
 copy_namehook_lists(dns_adb_t *adb, dns_adbfind_t *find, dns_name_t *qname,
-                   dns_rdatatype_t qtype, dns_adbname_t *name,
-                   isc_stdtime_t now)
+                    dns_rdatatype_t qtype, dns_adbname_t *name,
+                    isc_stdtime_t now)
 {
-       dns_adbnamehook_t *namehook;
-       dns_adbaddrinfo_t *addrinfo;
-       dns_adbentry_t *entry;
-       int bucket;
-
-       bucket = DNS_ADB_INVALIDBUCKET;
-
-       if (find->options & DNS_ADBFIND_INET) {
-               namehook = ISC_LIST_HEAD(name->v4);
-               while (namehook != NULL) {
-                       entry = namehook->entry;
-                       bucket = entry->lock_bucket;
-                       LOCK(&adb->entrylocks[bucket]);
-
-                       if (!FIND_RETURNLAME(find)
-                           && entry_is_lame(adb, entry, qname, qtype, now)) {
-                               find->options |= DNS_ADBFIND_LAMEPRUNED;
-                               goto nextv4;
-                       }
-                       addrinfo = new_adbaddrinfo(adb, entry, find->port);
-                       if (addrinfo == NULL) {
-                               find->partial_result |= DNS_ADBFIND_INET;
-                               goto out;
-                       }
-                       /*
-                        * Found a valid entry.  Add it to the find's list.
-                        */
-                       inc_entry_refcnt(adb, entry, ISC_FALSE);
-                       ISC_LIST_APPEND(find->list, addrinfo, publink);
-                       addrinfo = NULL;
-               nextv4:
-                       UNLOCK(&adb->entrylocks[bucket]);
-                       bucket = DNS_ADB_INVALIDBUCKET;
-                       namehook = ISC_LIST_NEXT(namehook, plink);
-               }
-       }
-
-       if (find->options & DNS_ADBFIND_INET6) {
-               namehook = ISC_LIST_HEAD(name->v6);
-               while (namehook != NULL) {
-                       entry = namehook->entry;
-                       bucket = entry->lock_bucket;
-                       LOCK(&adb->entrylocks[bucket]);
-
-                       if (entry_is_lame(adb, entry, qname, qtype, now))
-                               goto nextv6;
-                       addrinfo = new_adbaddrinfo(adb, entry, find->port);
-                       if (addrinfo == NULL) {
-                               find->partial_result |= DNS_ADBFIND_INET6;
-                               goto out;
-                       }
-                       /*
-                        * Found a valid entry.  Add it to the find's list.
-                        */
-                       inc_entry_refcnt(adb, entry, ISC_FALSE);
-                       ISC_LIST_APPEND(find->list, addrinfo, publink);
-                       addrinfo = NULL;
-               nextv6:
-                       UNLOCK(&adb->entrylocks[bucket]);
-                       bucket = DNS_ADB_INVALIDBUCKET;
-                       namehook = ISC_LIST_NEXT(namehook, plink);
-               }
-       }
+        dns_adbnamehook_t *namehook;
+        dns_adbaddrinfo_t *addrinfo;
+        dns_adbentry_t *entry;
+        int bucket;
+
+        bucket = DNS_ADB_INVALIDBUCKET;
+
+        if (find->options & DNS_ADBFIND_INET) {
+                namehook = ISC_LIST_HEAD(name->v4);
+                while (namehook != NULL) {
+                        entry = namehook->entry;
+                        bucket = entry->lock_bucket;
+                        LOCK(&adb->entrylocks[bucket]);
+
+                        if (!FIND_RETURNLAME(find)
+                            && entry_is_lame(adb, entry, qname, qtype, now)) {
+                                find->options |= DNS_ADBFIND_LAMEPRUNED;
+                                goto nextv4;
+                        }
+                        addrinfo = new_adbaddrinfo(adb, entry, find->port);
+                        if (addrinfo == NULL) {
+                                find->partial_result |= DNS_ADBFIND_INET;
+                                goto out;
+                        }
+                        /*
+                         * Found a valid entry.  Add it to the find's list.
+                         */
+                        inc_entry_refcnt(adb, entry, ISC_FALSE);
+                        ISC_LIST_APPEND(find->list, addrinfo, publink);
+                        addrinfo = NULL;
+                nextv4:
+                        UNLOCK(&adb->entrylocks[bucket]);
+                        bucket = DNS_ADB_INVALIDBUCKET;
+                        namehook = ISC_LIST_NEXT(namehook, plink);
+                }
+        }
+
+        if (find->options & DNS_ADBFIND_INET6) {
+                namehook = ISC_LIST_HEAD(name->v6);
+                while (namehook != NULL) {
+                        entry = namehook->entry;
+                        bucket = entry->lock_bucket;
+                        LOCK(&adb->entrylocks[bucket]);
+
+                        if (entry_is_lame(adb, entry, qname, qtype, now))
+                                goto nextv6;
+                        addrinfo = new_adbaddrinfo(adb, entry, find->port);
+                        if (addrinfo == NULL) {
+                                find->partial_result |= DNS_ADBFIND_INET6;
+                                goto out;
+                        }
+                        /*
+                         * Found a valid entry.  Add it to the find's list.
+                         */
+                        inc_entry_refcnt(adb, entry, ISC_FALSE);
+                        ISC_LIST_APPEND(find->list, addrinfo, publink);
+                        addrinfo = NULL;
+                nextv6:
+                        UNLOCK(&adb->entrylocks[bucket]);
+                        bucket = DNS_ADB_INVALIDBUCKET;
+                        namehook = ISC_LIST_NEXT(namehook, plink);
+                }
+        }
 
  out:
-       if (bucket != DNS_ADB_INVALIDBUCKET)
-               UNLOCK(&adb->entrylocks[bucket]);
+        if (bucket != DNS_ADB_INVALIDBUCKET)
+                UNLOCK(&adb->entrylocks[bucket]);
 }
 
 static void
 shutdown_task(isc_task_t *task, isc_event_t *ev) {
-       dns_adb_t *adb;
-
-       UNUSED(task);
-
-       adb = ev->ev_arg;
-       INSIST(DNS_ADB_VALID(adb));
-
-       /*
-        * Kill the timer, and then the ADB itself.  Note that this implies
-        * that this task was the one scheduled to get timer events.  If
-        * this is not true (and it is unfortunate there is no way to INSIST()
-        * this) badness will occur.
-        */
-       LOCK(&adb->lock);
-       isc_timer_detach(&adb->timer);
-       UNLOCK(&adb->lock);
-       isc_event_free(&ev);
-       destroy(adb);
+        dns_adb_t *adb;
+
+        UNUSED(task);
+
+        adb = ev->ev_arg;
+        INSIST(DNS_ADB_VALID(adb));
+
+        /*
+         * Kill the timer, and then the ADB itself.  Note that this implies
+         * that this task was the one scheduled to get timer events.  If
+         * this is not true (and it is unfortunate there is no way to INSIST()
+         * this) badness will occur.
+         */
+        LOCK(&adb->lock);
+        isc_timer_detach(&adb->timer);
+#ifdef LRU_DEBUG
+        isc_timer_detach(&adb->dump_timer);
+#endif
+        UNLOCK(&adb->lock);
+        isc_event_free(&ev);
+        destroy(adb);
 }
 
 /*
@@ -1790,34 +1843,110 @@ shutdown_task(isc_task_t *task, isc_event_t *ev) {
  */
 static isc_boolean_t
 check_expire_name(dns_adbname_t **namep, isc_stdtime_t now) {
-       dns_adbname_t *name;
-       isc_boolean_t result = ISC_FALSE;
-
-       INSIST(namep != NULL && DNS_ADBNAME_VALID(*namep));
-       name = *namep;
-
-       if (NAME_HAS_V4(name) || NAME_HAS_V6(name))
-               return (result);
-       if (NAME_FETCH(name))
-               return (result);
-       if (!EXPIRE_OK(name->expire_v4, now))
-               return (result);
-       if (!EXPIRE_OK(name->expire_v6, now))
-               return (result);
-       if (!EXPIRE_OK(name->expire_target, now))
-               return (result);
-
-       /*
-        * The name is empty.  Delete it.
-        */
-       result = kill_name(&name, DNS_EVENT_ADBEXPIRED);
-       *namep = NULL;
-
-       /*
-        * Our caller, or one of its callers, will be calling check_exit() at
-        * some point, so we don't need to do it here.
-        */
-       return (result);
+        dns_adbname_t *name;
+        isc_boolean_t result = ISC_FALSE;
+
+        INSIST(namep != NULL && DNS_ADBNAME_VALID(*namep));
+        name = *namep;
+
+        if (NAME_HAS_V4(name) || NAME_HAS_V6(name))
+                return (result);
+        if (NAME_FETCH(name))
+                return (result);
+        if (!EXPIRE_OK(name->expire_v4, now))
+                return (result);
+        if (!EXPIRE_OK(name->expire_v6, now))
+                return (result);
+        if (!EXPIRE_OK(name->expire_target, now))
+                return (result);
+
+        /*
+         * The name is empty.  Delete it.
+         */
+        result = kill_name(&name, DNS_EVENT_ADBEXPIRED, ISC_FALSE);
+        *namep = NULL;
+
+        /*
+         * Our caller, or one of its callers, will be calling check_exit() at
+         * some point, so we don't need to do it here.
+         */
+        return (result);
+}
+
+/*%
+ * Examine the tail entry of the LRU list to see if it expires or is stale
+ * (unused for some period); if so, the name entry will be freed.  If the ADB
+ * is in the overmem condition, the tail and the next to tail entries
+ * will be unconditionally removed (unless they have an outstanding fetch).
+ * We don't care about a race on 'overmem' at the risk of causing some
+ * collateral damage or a small delay in starting cleanup, so we don't bother
+ * to lock ADB (if it's not locked).
+ *
+ * Name bucket must be locked; adb may be locked; no other locks held.
+ */
+static void
+check_stale_name(dns_adb_t *adb, int bucket, isc_stdtime_t now) {
+        int victims, max_victims;
+        isc_boolean_t result;
+        dns_adbname_t *victim, *next_victim;
+        isc_boolean_t overmem = adb->overmem;
+        int scans = 0;
+
+        INSIST(bucket != DNS_ADB_INVALIDBUCKET);
+
+        max_victims = overmem ? 2 : 1;
+
+        /*
+         * We limit the number of scanned entries to 10 (arbitrary choice)
+         * in order to avoid examining too many entries when there are many
+         * tail entries that have fetches (this should be rare, but could
+         * happen).
+         */
+        victim = ISC_LIST_TAIL(adb->names[bucket]);
+        for (victims = 0;
+             victim != NULL && victims < max_victims && scans < 10;
+             victim = next_victim) {
+                scans++;
+                next_victim = ISC_LIST_PREV(victim, plink);
+
+                /*
+                 * If the victim is already dead, it simply waits for some
+                 * final events.  Ignore it.
+                 */
+                if (NAME_DEAD(victim))
+                        goto next;
+
+                result = check_expire_name(&victim, now);
+                if (victim == NULL) {
+#ifdef LRU_DEBUG
+                        adb->stale_expire++;
+#endif
+                        victims++;
+                        goto next;
+                }
+
+                if (!NAME_FETCH(victim) &&
+                    (overmem || victim->last_used + ADB_STALE_MARGIN <= now)) {
+                        RUNTIME_CHECK(kill_name(&victim,
+                                                DNS_EVENT_ADBCANCELED,
+                                                ISC_TRUE) ==
+                                      ISC_FALSE);
+#ifdef LRU_DEBUG
+                        adb->stale_lru++;
+#endif
+                        victims++;
+                }
+
+        next:
+                if (!overmem)
+                        break;
+        }
+
+#ifdef LRU_DEBUG
+        /* XXX: omit lock for brevity */
+        adb->stale_scan += scans;
+        adb->stale_purge += victims;
+#endif
 }
 
 /*
@@ -1826,39 +1955,29 @@ check_expire_name(dns_adbname_t **namep, isc_stdtime_t now) {
 static isc_boolean_t
 check_expire_entry(dns_adb_t *adb, dns_adbentry_t **entryp, isc_stdtime_t now)
 {
-       dns_adbentry_t *entry;
-       isc_boolean_t expire;
-       isc_boolean_t result = ISC_FALSE;
-
-       INSIST(entryp != NULL && DNS_ADBENTRY_VALID(*entryp));
-       entry = *entryp;
-
-       if (entry->refcnt != 0)
-               return (result);
+        dns_adbentry_t *entry;
+        isc_boolean_t result = ISC_FALSE;
 
-       if (adb->overmem) {
-               isc_uint32_t val;
+        INSIST(entryp != NULL && DNS_ADBENTRY_VALID(*entryp));
+        entry = *entryp;
 
-               isc_random_get(&val);
+        if (entry->refcnt != 0)
+                return (result);
 
-               expire = ISC_TF((val % 4) == 0);
-       } else
-               expire = ISC_FALSE;
+        if (entry->expires == 0 || entry->expires > now)
+                return (result);
 
-       if (entry->expires == 0 || (! expire && entry->expires > now))
-               return (result);
-
-       /*
-        * The entry is not in use.  Delete it.
-        */
-       DP(DEF_LEVEL, "killing entry %p", entry);
-       INSIST(ISC_LINK_LINKED(entry, plink));
-       result = unlink_entry(adb, entry);
-       free_adbentry(adb, &entry);
-       if (result)
-               dec_adb_irefcnt(adb);
-       *entryp = NULL;
-       return (result);
+        /*
+         * The entry is not in use.  Delete it.
+         */
+        DP(DEF_LEVEL, "killing entry %p", entry);
+        INSIST(ISC_LINK_LINKED(entry, plink));
+        result = unlink_entry(adb, entry);
+        free_adbentry(adb, &entry);
+        if (result)
+                dec_adb_irefcnt(adb);
+        *entryp = NULL;
+        return (result);
 }
 
 /*
@@ -1866,29 +1985,29 @@ check_expire_entry(dns_adb_t *adb, dns_adbentry_t **entryp, isc_stdtime_t now)
  */
 static isc_boolean_t
 cleanup_names(dns_adb_t *adb, int bucket, isc_stdtime_t now) {
-       dns_adbname_t *name;
-       dns_adbname_t *next_name;
-       isc_boolean_t result = ISC_FALSE;
-
-       DP(CLEAN_LEVEL, "cleaning name bucket %d", bucket);
-
-       LOCK(&adb->namelocks[bucket]);
-       if (adb->name_sd[bucket]) {
-               UNLOCK(&adb->namelocks[bucket]);
-               return (result);
-       }
-
-       name = ISC_LIST_HEAD(adb->names[bucket]);
-       while (name != NULL) {
-               next_name = ISC_LIST_NEXT(name, plink);
-               INSIST(result == ISC_FALSE);
-               result = check_expire_namehooks(name, now, adb->overmem);
-               if (!result)
-                       result = check_expire_name(&name, now);
-               name = next_name;
-       }
-       UNLOCK(&adb->namelocks[bucket]);
-       return (result);
+        dns_adbname_t *name;
+        dns_adbname_t *next_name;
+        isc_boolean_t result = ISC_FALSE;
+
+        DP(CLEAN_LEVEL, "cleaning name bucket %d", bucket);
+
+        LOCK(&adb->namelocks[bucket]);
+        if (adb->name_sd[bucket]) {
+                UNLOCK(&adb->namelocks[bucket]);
+                return (result);
+        }
+
+        name = ISC_LIST_HEAD(adb->names[bucket]);
+        while (name != NULL) {
+                next_name = ISC_LIST_NEXT(name, plink);
+                INSIST(result == ISC_FALSE);
+                result = check_expire_namehooks(name, now);
+                if (!result)
+                        result = check_expire_name(&name, now);
+                name = next_name;
+        }
+        UNLOCK(&adb->namelocks[bucket]);
+        return (result);
 }
 
 /*
@@ -1896,102 +2015,131 @@ cleanup_names(dns_adb_t *adb, int bucket, isc_stdtime_t now) {
  */
 static isc_boolean_t
 cleanup_entries(dns_adb_t *adb, int bucket, isc_stdtime_t now) {
-       dns_adbentry_t *entry, *next_entry;
-       isc_boolean_t result = ISC_FALSE;
+        dns_adbentry_t *entry, *next_entry;
+        isc_boolean_t result = ISC_FALSE;
 
-       DP(CLEAN_LEVEL, "cleaning entry bucket %d", bucket);
+        DP(CLEAN_LEVEL, "cleaning entry bucket %d", bucket);
 
-       LOCK(&adb->entrylocks[bucket]);
-       entry = ISC_LIST_HEAD(adb->entries[bucket]);
-       while (entry != NULL) {
-               next_entry = ISC_LIST_NEXT(entry, plink);
-               INSIST(result == ISC_FALSE);
-               result = check_expire_entry(adb, &entry, now);
-               entry = next_entry;
-       }
-       UNLOCK(&adb->entrylocks[bucket]);
-       return (result);
+        LOCK(&adb->entrylocks[bucket]);
+        entry = ISC_LIST_HEAD(adb->entries[bucket]);
+        while (entry != NULL) {
+                next_entry = ISC_LIST_NEXT(entry, plink);
+                INSIST(result == ISC_FALSE);
+                result = check_expire_entry(adb, &entry, now);
+                entry = next_entry;
+        }
+        UNLOCK(&adb->entrylocks[bucket]);
+        return (result);
 }
 
+#if 1
+static void
+timer_cleanup(isc_task_t *task, isc_event_t *ev) {
+        UNUSED(task);
+
+        isc_event_free(&ev);
+}
+#else
 static void
 timer_cleanup(isc_task_t *task, isc_event_t *ev) {
-       dns_adb_t *adb;
-       isc_stdtime_t now;
-       unsigned int i;
-       isc_interval_t interval;
-
-       UNUSED(task);
-
-       adb = ev->ev_arg;
-       INSIST(DNS_ADB_VALID(adb));
-
-       LOCK(&adb->lock);
-
-       isc_stdtime_get(&now);
-
-       for (i = 0; i < CLEAN_BUCKETS; i++) {
-               /*
-                * Call our cleanup routines.
-                */
-               RUNTIME_CHECK(cleanup_names(adb, adb->next_cleanbucket, now) ==
-                             ISC_FALSE);
-               RUNTIME_CHECK(cleanup_entries(adb, adb->next_cleanbucket, now)
-                             == ISC_FALSE);
-
-               /*
-                * Set the next bucket to be cleaned.
-                */
-               adb->next_cleanbucket++;
-               if (adb->next_cleanbucket >= NBUCKETS) {
-                       adb->next_cleanbucket = 0;
+        dns_adb_t *adb;
+        isc_stdtime_t now;
+        unsigned int i;
+        isc_interval_t interval;
+
+        UNUSED(task);
+
+        adb = ev->ev_arg;
+        INSIST(DNS_ADB_VALID(adb));
+
+        LOCK(&adb->lock);
+
+        isc_stdtime_get(&now);
+
+        for (i = 0; i < CLEAN_BUCKETS; i++) {
+                /*
+                 * Call our cleanup routines.
+                 */
+                RUNTIME_CHECK(cleanup_names(adb, adb->next_cleanbucket, now) ==
+                              ISC_FALSE);
+                RUNTIME_CHECK(cleanup_entries(adb, adb->next_cleanbucket, now)
+                              == ISC_FALSE);
+
+                /*
+                 * Set the next bucket to be cleaned.
+                 */
+                adb->next_cleanbucket++;
+                if (adb->next_cleanbucket >= NBUCKETS) {
+                        adb->next_cleanbucket = 0;
 #ifdef DUMP_ADB_AFTER_CLEANING
-                       dump_adb(adb, stdout, ISC_TRUE, now);
+                        dump_adb(adb, stdout, ISC_TRUE, now);
 #endif
-               }
-       }
+                }
+        }
 
-       /*
-        * Reset the timer.
-        * XXXDCL isc_timer_reset might return ISC_R_UNEXPECTED or
-        * ISC_R_NOMEMORY, but it isn't clear what could be done here
-        * if either one of those things happened.
-        */
-       interval = adb->tick_interval;
-       if (adb->overmem)
-               isc_interval_set(&interval, 0, 1);
-       (void)isc_timer_reset(adb->timer, isc_timertype_once, NULL,
-                             &interval, ISC_FALSE);
+        /*
+         * Reset the timer.
+         * XXXDCL isc_timer_reset might return ISC_R_UNEXPECTED or
+         * ISC_R_NOMEMORY, but it isn't clear what could be done here
+         * if either one of those things happened.
+         */
+        interval = adb->tick_interval;
+        if (adb->overmem)
+                isc_interval_set(&interval, 0, 1);
+        (void)isc_timer_reset(adb->timer, isc_timertype_once, NULL,
+                              &interval, ISC_FALSE);
 
-       UNLOCK(&adb->lock);
+        UNLOCK(&adb->lock);
 
-       isc_event_free(&ev);
+        isc_event_free(&ev);
 }
+#endif
 
 static void
 destroy(dns_adb_t *adb) {
-       adb->magic = 0;
+        adb->magic = 0;
+
+#ifdef LRU_DEBUG
+        /* for debug: print statistics */
+        if (adb->nname_total > 0) {
+                INSIST(adb->nname == 0 && adb->nentry == 0);
+                isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+                              DNS_LOGMODULE_ADB, ISC_LOG_INFO,
+                              "ADB %p name hit %.2f, entry hit %.2f", adb,
+                              (double)adb->nameuses /
+                              (adb->nname_total + adb->nameuses),
+                              adb->entryuses > 0 ?
+                              (double)adb->entryuses /
+                              (adb->nentry_total + adb->entryuses) : 0);
+                isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+                              DNS_LOGMODULE_ADB, ISC_LOG_INFO,
+                              "ADB %p stale name purges: %u(%u,%u)/%u",
+                              adb, adb->stale_purge, adb->stale_expire,
+                              adb->stale_lru, adb->stale_scan);
+        }
+#endif
 
-       /*
-        * The timer is already dead, from the task's shutdown callback.
-        */
-       isc_task_detach(&adb->task);
+        /*
+         * The timer is already dead, from the task's shutdown callback.
+         */
+        isc_task_detach(&adb->task);
 
-       isc_mempool_destroy(&adb->nmp);
-       isc_mempool_destroy(&adb->nhmp);
-       isc_mempool_destroy(&adb->limp);
-       isc_mempool_destroy(&adb->emp);
-       isc_mempool_destroy(&adb->ahmp);
-       isc_mempool_destroy(&adb->aimp);
-       isc_mempool_destroy(&adb->afmp);
+        isc_mempool_destroy(&adb->nmp);
+        isc_mempool_destroy(&adb->nhmp);
+        isc_mempool_destroy(&adb->limp);
+        isc_mempool_destroy(&adb->emp);
+        isc_mempool_destroy(&adb->ahmp);
+        isc_mempool_destroy(&adb->aimp);
+        isc_mempool_destroy(&adb->afmp);
 
-       DESTROYMUTEXBLOCK(adb->entrylocks, NBUCKETS);
-       DESTROYMUTEXBLOCK(adb->namelocks, NBUCKETS);
+        DESTROYMUTEXBLOCK(adb->entrylocks, NBUCKETS);
+        DESTROYMUTEXBLOCK(adb->namelocks, NBUCKETS);
 
-       DESTROYLOCK(&adb->reflock);
-       DESTROYLOCK(&adb->lock);
-       DESTROYLOCK(&adb->mplock);
+        DESTROYLOCK(&adb->reflock);
+        DESTROYLOCK(&adb->lock);
+        DESTROYLOCK(&adb->mplock);
 
-       isc_mem_putanddetach(&adb->mctx, adb, sizeof(dns_adb_t));
+        isc_mem_putanddetach(&adb->mctx, adb, sizeof(dns_adb_t));
 }
 
 
@@ -2001,1341 +2149,1393 @@ destroy(dns_adb_t *adb) {
 
 isc_result_t
 dns_adb_create(isc_mem_t *mem, dns_view_t *view, isc_timermgr_t *timermgr,
-              isc_taskmgr_t *taskmgr, dns_adb_t **newadb)
+               isc_taskmgr_t *taskmgr, dns_adb_t **newadb)
 {
-       dns_adb_t *adb;
-       isc_result_t result;
-       int i;
-
-       REQUIRE(mem != NULL);
-       REQUIRE(view != NULL);
-       REQUIRE(timermgr != NULL);
-       REQUIRE(taskmgr != NULL);
-       REQUIRE(newadb != NULL && *newadb == NULL);
-
-       adb = isc_mem_get(mem, sizeof(dns_adb_t));
-       if (adb == NULL)
-               return (ISC_R_NOMEMORY);
-
-       /*
-        * Initialize things here that cannot fail, and especially things
-        * that must be NULL for the error return to work properly.
-        */
-       adb->magic = 0;
-       adb->erefcnt = 1;
-       adb->irefcnt = 0;
-       adb->nmp = NULL;
-       adb->nhmp = NULL;
-       adb->limp = NULL;
-       adb->emp = NULL;
-       adb->ahmp = NULL;
-       adb->aimp = NULL;
-       adb->afmp = NULL;
-       adb->task = NULL;
-       adb->timer = NULL;
-       adb->mctx = NULL;
-       adb->view = view;
-       adb->timermgr = timermgr;
-       adb->taskmgr = taskmgr;
-       adb->next_cleanbucket = 0;
-       ISC_EVENT_INIT(&adb->cevent, sizeof(adb->cevent), 0, NULL,
-                      DNS_EVENT_ADBCONTROL, shutdown_task, adb,
-                      adb, NULL, NULL);
-       adb->cevent_sent = ISC_FALSE;
-       adb->shutting_down = ISC_FALSE;
-       adb->overmem = ISC_FALSE;
-       ISC_LIST_INIT(adb->whenshutdown);
-
-       isc_mem_attach(mem, &adb->mctx);
-
-       result = isc_mutex_init(&adb->lock);
-       if (result != ISC_R_SUCCESS)
-               goto fail0b;
-
-       result = isc_mutex_init(&adb->mplock);
-       if (result != ISC_R_SUCCESS)
-               goto fail0c;
-
-       result = isc_mutex_init(&adb->reflock);
-       if (result != ISC_R_SUCCESS)
-               goto fail0d;
-
-       /*
-        * Initialize the bucket locks for names and elements.
-        * May as well initialize the list heads, too.
-        */
-       result = isc_mutexblock_init(adb->namelocks, NBUCKETS);
-       if (result != ISC_R_SUCCESS)
-               goto fail1;
-       for (i = 0; i < NBUCKETS; i++) {
-               ISC_LIST_INIT(adb->names[i]);
-               adb->name_sd[i] = ISC_FALSE;
-               adb->name_refcnt[i] = 0;
-               adb->irefcnt++;
-       }
-       for (i = 0; i < NBUCKETS; i++) {
-               ISC_LIST_INIT(adb->entries[i]);
-               adb->entry_sd[i] = ISC_FALSE;
-               adb->entry_refcnt[i] = 0;
-               adb->irefcnt++;
-       }
-       result = isc_mutexblock_init(adb->entrylocks, NBUCKETS);
-       if (result != ISC_R_SUCCESS)
-               goto fail2;
-
-       /*
-        * Memory pools
-        */
+        dns_adb_t *adb;
+        isc_result_t result;
+        int i;
+
+        REQUIRE(mem != NULL);
+        REQUIRE(view != NULL);
+        REQUIRE(timermgr != NULL);
+        REQUIRE(taskmgr != NULL);
+        REQUIRE(newadb != NULL && *newadb == NULL);
+
+        adb = isc_mem_get(mem, sizeof(dns_adb_t));
+        if (adb == NULL)
+                return (ISC_R_NOMEMORY);
+
+        /*
+         * Initialize things here that cannot fail, and especially things
+         * that must be NULL for the error return to work properly.
+         */
+        adb->magic = 0;
+        adb->erefcnt = 1;
+        adb->irefcnt = 0;
+        adb->nmp = NULL;
+        adb->nhmp = NULL;
+        adb->limp = NULL;
+        adb->emp = NULL;
+        adb->ahmp = NULL;
+        adb->aimp = NULL;
+        adb->afmp = NULL;
+        adb->task = NULL;
+        adb->timer = NULL;
+#ifdef LRU_DEBUG
+        adb->dump_timer = NULL;
+#endif
+        adb->mctx = NULL;
+        adb->view = view;
+        adb->timermgr = timermgr;
+        adb->taskmgr = taskmgr;
+        adb->next_cleanbucket = 0;
+        ISC_EVENT_INIT(&adb->cevent, sizeof(adb->cevent), 0, NULL,
+                       DNS_EVENT_ADBCONTROL, shutdown_task, adb,
+                       adb, NULL, NULL);
+        adb->cevent_sent = ISC_FALSE;
+        adb->shutting_down = ISC_FALSE;
+        adb->overmem = ISC_FALSE;
+        ISC_LIST_INIT(adb->whenshutdown);
+
+#ifdef LRU_DEBUG
+        /* for debug */
+        adb->nname = 0;
+        adb->nname_total = 0;
+        adb->nentry = 0;
+        adb->nentry_total = 0;
+        adb->stale_purge = 0;
+        adb->stale_scan = 0;
+        adb->stale_expire = 0;
+        adb->stale_lru = 0;
+        adb->nameuses = 0;
+        adb->entryuses = 0;
+#endif
+
+        isc_mem_attach(mem, &adb->mctx);
+
+        result = isc_mutex_init(&adb->lock);
+        if (result != ISC_R_SUCCESS)
+                goto fail0b;
+
+        result = isc_mutex_init(&adb->mplock);
+        if (result != ISC_R_SUCCESS)
+                goto fail0c;
+
+        result = isc_mutex_init(&adb->reflock);
+        if (result != ISC_R_SUCCESS)
+                goto fail0d;
+
+        /*
+         * Initialize the bucket locks for names and elements.
+         * May as well initialize the list heads, too.
+         */
+        result = isc_mutexblock_init(adb->namelocks, NBUCKETS);
+        if (result != ISC_R_SUCCESS)
+                goto fail1;
+        for (i = 0; i < NBUCKETS; i++) {
+                ISC_LIST_INIT(adb->names[i]);
+                adb->name_sd[i] = ISC_FALSE;
+                adb->name_refcnt[i] = 0;
+                adb->irefcnt++;
+        }
+        for (i = 0; i < NBUCKETS; i++) {
+                ISC_LIST_INIT(adb->entries[i]);
+                adb->entry_sd[i] = ISC_FALSE;
+                adb->entry_refcnt[i] = 0;
+                adb->irefcnt++;
+        }
+        result = isc_mutexblock_init(adb->entrylocks, NBUCKETS);
+        if (result != ISC_R_SUCCESS)
+                goto fail2;
+
+        /*
+         * Memory pools
+         */
 #define MPINIT(t, p, n) do { \
-       result = isc_mempool_create(mem, sizeof(t), &(p)); \
-       if (result != ISC_R_SUCCESS) \
-               goto fail3; \
-       isc_mempool_setfreemax((p), FREE_ITEMS); \
-       isc_mempool_setfillcount((p), FILL_COUNT); \
-       isc_mempool_setname((p), n); \
-       isc_mempool_associatelock((p), &adb->mplock); \
+        result = isc_mempool_create(mem, sizeof(t), &(p)); \
+        if (result != ISC_R_SUCCESS) \
+                goto fail3; \
+        isc_mempool_setfreemax((p), FREE_ITEMS); \
+        isc_mempool_setfillcount((p), FILL_COUNT); \
+        isc_mempool_setname((p), n); \
+        isc_mempool_associatelock((p), &adb->mplock); \
 } while (0)
 
-       MPINIT(dns_adbname_t, adb->nmp, "adbname");
-       MPINIT(dns_adbnamehook_t, adb->nhmp, "adbnamehook");
-       MPINIT(dns_adblameinfo_t, adb->limp, "adblameinfo");
-       MPINIT(dns_adbentry_t, adb->emp, "adbentry");
-       MPINIT(dns_adbfind_t, adb->ahmp, "adbfind");
-       MPINIT(dns_adbaddrinfo_t, adb->aimp, "adbaddrinfo");
-       MPINIT(dns_adbfetch_t, adb->afmp, "adbfetch");
+        MPINIT(dns_adbname_t, adb->nmp, "adbname");
+        MPINIT(dns_adbnamehook_t, adb->nhmp, "adbnamehook");
+        MPINIT(dns_adblameinfo_t, adb->limp, "adblameinfo");
+        MPINIT(dns_adbentry_t, adb->emp, "adbentry");
+        MPINIT(dns_adbfind_t, adb->ahmp, "adbfind");
+        MPINIT(dns_adbaddrinfo_t, adb->aimp, "adbaddrinfo");
+        MPINIT(dns_adbfetch_t, adb->afmp, "adbfetch");
 
 #undef MPINIT
 
-       /*
-        * Allocate a timer and a task for our periodic cleanup.
-        */
-       result = isc_task_create(adb->taskmgr, 0, &adb->task);
-       if (result != ISC_R_SUCCESS)
-               goto fail3;
-       isc_task_setname(adb->task, "ADB", adb);
-       /*
-        * XXXMLG When this is changed to be a config file option,
-        */
-       isc_interval_set(&adb->tick_interval, CLEAN_SECONDS, 0);
-       result = isc_timer_create(adb->timermgr, isc_timertype_once,
-                                 NULL, &adb->tick_interval, adb->task,
-                                 timer_cleanup, adb, &adb->timer);
-       if (result != ISC_R_SUCCESS)
-               goto fail3;
-
-       DP(ISC_LOG_DEBUG(5), "cleaning interval for adb: "
-          "%u buckets every %u seconds, %u buckets in system, %u cl.interval",
-          CLEAN_BUCKETS, CLEAN_SECONDS, NBUCKETS, CLEAN_PERIOD);
-
-       /*
-        * Normal return.
-        */
-       adb->magic = DNS_ADB_MAGIC;
-       *newadb = adb;
-       return (ISC_R_SUCCESS);
+        /*
+         * Allocate a timer and a task for our periodic cleanup.
+         */
+        result = isc_task_create(adb->taskmgr, 0, &adb->task);
+        if (result != ISC_R_SUCCESS)
+                goto fail3;
+        isc_task_setname(adb->task, "ADB", adb);
+        /*
+         * XXXMLG When this is changed to be a config file option,
+         */
+        isc_interval_set(&adb->tick_interval, CLEAN_SECONDS, 0);
+        result = isc_timer_create(adb->timermgr, isc_timertype_once,
+                                  NULL, &adb->tick_interval, adb->task,
+                                  timer_cleanup, adb, &adb->timer);
+        if (result != ISC_R_SUCCESS)
+                goto fail3;
+
+#ifdef LRU_DEBUG
+        {
+                isc_interval_t interval;
+
+                interval.seconds = DUMP_INTERVAL;
+                interval.nanoseconds = 0;
+                RUNTIME_CHECK(isc_time_nowplusinterval(&adb->dump_time,
+                                                       &interval) ==
+                              ISC_R_SUCCESS);
+
+                result = isc_timer_create(adb->timermgr, isc_timertype_once,
+                                          &adb->dump_time, NULL, adb->task,
+                                          timer_dump, adb, &adb->dump_timer);
+        }
+#endif
+
+        DP(ISC_LOG_DEBUG(5), "cleaning interval for adb: "
+           "%u buckets every %u seconds, %u buckets in system, %u cl.interval",
+           CLEAN_BUCKETS, CLEAN_SECONDS, NBUCKETS, CLEAN_PERIOD);
+
+        /*
+         * Normal return.
+         */
+        adb->magic = DNS_ADB_MAGIC;
+        *newadb = adb;
+        return (ISC_R_SUCCESS);
 
  fail3:
-       if (adb->task != NULL)
-               isc_task_detach(&adb->task);
-       if (adb->timer != NULL)
-               isc_timer_detach(&adb->timer);
+        if (adb->task != NULL)
+                isc_task_detach(&adb->task);
+        if (adb->timer != NULL)
+                isc_timer_detach(&adb->timer);
 
-       /* clean up entrylocks */
-       DESTROYMUTEXBLOCK(adb->entrylocks, NBUCKETS);
+        /* clean up entrylocks */
+        DESTROYMUTEXBLOCK(adb->entrylocks, NBUCKETS);
 
  fail2: /* clean up namelocks */
-       DESTROYMUTEXBLOCK(adb->namelocks, NBUCKETS);
+        DESTROYMUTEXBLOCK(adb->namelocks, NBUCKETS);
 
  fail1: /* clean up only allocated memory */
-       if (adb->nmp != NULL)
-               isc_mempool_destroy(&adb->nmp);
-       if (adb->nhmp != NULL)
-               isc_mempool_destroy(&adb->nhmp);
-       if (adb->limp != NULL)
-               isc_mempool_destroy(&adb->limp);
-       if (adb->emp != NULL)
-               isc_mempool_destroy(&adb->emp);
-       if (adb->ahmp != NULL)
-               isc_mempool_destroy(&adb->ahmp);
-       if (adb->aimp != NULL)
-               isc_mempool_destroy(&adb->aimp);
-       if (adb->afmp != NULL)
-               isc_mempool_destroy(&adb->afmp);
-
-       DESTROYLOCK(&adb->reflock);
+        if (adb->nmp != NULL)
+                isc_mempool_destroy(&adb->nmp);
+        if (adb->nhmp != NULL)
+                isc_mempool_destroy(&adb->nhmp);
+        if (adb->limp != NULL)
+                isc_mempool_destroy(&adb->limp);
+        if (adb->emp != NULL)
+                isc_mempool_destroy(&adb->emp);
+        if (adb->ahmp != NULL)
+                isc_mempool_destroy(&adb->ahmp);
+        if (adb->aimp != NULL)
+                isc_mempool_destroy(&adb->aimp);
+        if (adb->afmp != NULL)
+                isc_mempool_destroy(&adb->afmp);
+
+        DESTROYLOCK(&adb->reflock);
  fail0d:
-       DESTROYLOCK(&adb->mplock);
+        DESTROYLOCK(&adb->mplock);
  fail0c:
-       DESTROYLOCK(&adb->lock);
+        DESTROYLOCK(&adb->lock);
  fail0b:
-       isc_mem_putanddetach(&adb->mctx, adb, sizeof(dns_adb_t));
+        isc_mem_putanddetach(&adb->mctx, adb, sizeof(dns_adb_t));
 
-       return (result);
+        return (result);
 }
 
 void
 dns_adb_attach(dns_adb_t *adb, dns_adb_t **adbx) {
 
-       REQUIRE(DNS_ADB_VALID(adb));
-       REQUIRE(adbx != NULL && *adbx == NULL);
+        REQUIRE(DNS_ADB_VALID(adb));
+        REQUIRE(adbx != NULL && *adbx == NULL);
 
-       inc_adb_erefcnt(adb);
-       *adbx = adb;
+        inc_adb_erefcnt(adb);
+        *adbx = adb;
 }
 
 void
 dns_adb_detach(dns_adb_t **adbx) {
-       dns_adb_t *adb;
-       isc_boolean_t need_exit_check;
+        dns_adb_t *adb;
+        isc_boolean_t need_exit_check;
 
-       REQUIRE(adbx != NULL && DNS_ADB_VALID(*adbx));
+        REQUIRE(adbx != NULL && DNS_ADB_VALID(*adbx));
 
-       adb = *adbx;
-       *adbx = NULL;
+        adb = *adbx;
+        *adbx = NULL;
 
-       INSIST(adb->erefcnt > 0);
+        INSIST(adb->erefcnt > 0);
 
-       LOCK(&adb->reflock);
-       adb->erefcnt--;
-       need_exit_check = ISC_TF(adb->erefcnt == 0 && adb->irefcnt == 0);
-       UNLOCK(&adb->reflock);
+        LOCK(&adb->reflock);
+        adb->erefcnt--;
+        need_exit_check = ISC_TF(adb->erefcnt == 0 && adb->irefcnt == 0);
+        UNLOCK(&adb->reflock);
 
-       if (need_exit_check) {
-               LOCK(&adb->lock);
-               INSIST(adb->shutting_down);
-               check_exit(adb);
-               UNLOCK(&adb->lock);
-       }
+        if (need_exit_check) {
+                LOCK(&adb->lock);
+                INSIST(adb->shutting_down);
+                check_exit(adb);
+                UNLOCK(&adb->lock);
+        }
 }
 
 void
 dns_adb_whenshutdown(dns_adb_t *adb, isc_task_t *task, isc_event_t **eventp) {
-       isc_task_t *clone;
-       isc_event_t *event;
-       isc_boolean_t zeroirefcnt = ISC_FALSE;
+        isc_task_t *clone;
+        isc_event_t *event;
+        isc_boolean_t zeroirefcnt = ISC_FALSE;
 
-       /*
-        * Send '*eventp' to 'task' when 'adb' has shutdown.
-        */
+        /*
+         * Send '*eventp' to 'task' when 'adb' has shutdown.
+         */
 
-       REQUIRE(DNS_ADB_VALID(adb));
-       REQUIRE(eventp != NULL);
+        REQUIRE(DNS_ADB_VALID(adb));
+        REQUIRE(eventp != NULL);
 
-       event = *eventp;
-       *eventp = NULL;
+        event = *eventp;
+        *eventp = NULL;
 
-       LOCK(&adb->lock);
+        LOCK(&adb->lock);
 
-       LOCK(&adb->reflock);
-       zeroirefcnt = ISC_TF(adb->irefcnt == 0);
+        LOCK(&adb->reflock);
+        zeroirefcnt = ISC_TF(adb->irefcnt == 0);
 
-       if (adb->shutting_down && zeroirefcnt &&
-           isc_mempool_getallocated(adb->ahmp) == 0) {
-               /*
-                * We're already shutdown.  Send the event.
-                */
-               event->ev_sender = adb;
-               isc_task_send(task, &event);
-       } else {
-               clone = NULL;
-               isc_task_attach(task, &clone);
-               event->ev_sender = clone;
-               ISC_LIST_APPEND(adb->whenshutdown, event, ev_link);
-       }
+        if (adb->shutting_down && zeroirefcnt &&
+            isc_mempool_getallocated(adb->ahmp) == 0) {
+                /*
+                 * We're already shutdown.  Send the event.
+                 */
+                event->ev_sender = adb;
+                isc_task_send(task, &event);
+        } else {
+                clone = NULL;
+                isc_task_attach(task, &clone);
+                event->ev_sender = clone;
+                ISC_LIST_APPEND(adb->whenshutdown, event, ev_link);
+        }
 
-       UNLOCK(&adb->reflock);
-       UNLOCK(&adb->lock);
+        UNLOCK(&adb->reflock);
+        UNLOCK(&adb->lock);
 }
 
 void
 dns_adb_shutdown(dns_adb_t *adb) {
-       isc_boolean_t need_check_exit;
+        isc_boolean_t need_check_exit;
 
-       /*
-        * Shutdown 'adb'.
-        */
+        /*
+         * Shutdown 'adb'.
+         */
 
-       LOCK(&adb->lock);
+        LOCK(&adb->lock);
 
-       if (!adb->shutting_down) {
-               adb->shutting_down = ISC_TRUE;
-               isc_mem_setwater(adb->mctx, water, adb, 0, 0);
-               need_check_exit = shutdown_names(adb);
-               if (!need_check_exit)
-                       need_check_exit = shutdown_entries(adb);
-               if (need_check_exit)
-                       check_exit(adb);
-       }
+        if (!adb->shutting_down) {
+                adb->shutting_down = ISC_TRUE;
+                isc_mem_setwater(adb->mctx, water, adb, 0, 0);
+                need_check_exit = shutdown_names(adb);
+                if (!need_check_exit)
+                        need_check_exit = shutdown_entries(adb);
+                if (need_check_exit)
+                        check_exit(adb);
+        }
 
-       UNLOCK(&adb->lock);
+        UNLOCK(&adb->lock);
 }
 
 isc_result_t
 dns_adb_createfind(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action,
-                  void *arg, dns_name_t *name, dns_name_t *qname,
-                  dns_rdatatype_t qtype, unsigned int options,
-                  isc_stdtime_t now, dns_name_t *target,
-                  in_port_t port, dns_adbfind_t **findp)
+                   void *arg, dns_name_t *name, dns_name_t *qname,
+                   dns_rdatatype_t qtype, unsigned int options,
+                   isc_stdtime_t now, dns_name_t *target,
+                   in_port_t port, dns_adbfind_t **findp)
 {
-       dns_adbfind_t *find;
-       dns_adbname_t *adbname;
-       int bucket;
-       isc_boolean_t want_event, start_at_zone, alias, have_address;
-       isc_result_t result;
-       unsigned int wanted_addresses;
-       unsigned int wanted_fetches;
-       unsigned int query_pending;
-
-       REQUIRE(DNS_ADB_VALID(adb));
-       if (task != NULL) {
-               REQUIRE(action != NULL);
-       }
-       REQUIRE(name != NULL);
-       REQUIRE(qname != NULL);
-       REQUIRE(findp != NULL && *findp == NULL);
-       REQUIRE(target == NULL || dns_name_hasbuffer(target));
-
-       REQUIRE((options & DNS_ADBFIND_ADDRESSMASK) != 0);
-
-       result = ISC_R_UNEXPECTED;
-       wanted_addresses = (options & DNS_ADBFIND_ADDRESSMASK);
-       wanted_fetches = 0;
-       query_pending = 0;
-       want_event = ISC_FALSE;
-       start_at_zone = ISC_FALSE;
-       alias = ISC_FALSE;
-
-       if (now == 0)
-               isc_stdtime_get(&now);
-
-       /*
-        * XXXMLG  Move this comment somewhere else!
-        *
-        * Look up the name in our internal database.
-        *
-        * Possibilities:  Note that these are not always exclusive.
-        *
-        *      No name found.  In this case, allocate a new name header and
-        *      an initial namehook or two.  If any of these allocations
-        *      fail, clean up and return ISC_R_NOMEMORY.
-        *
-        *      Name found, valid addresses present.  Allocate one addrinfo
-        *      structure for each found and append it to the linked list
-        *      of addresses for this header.
-        *
-        *      Name found, queries pending.  In this case, if a task was
-        *      passed in, allocate a job id, attach it to the name's job
-        *      list and remember to tell the caller that there will be
-        *      more info coming later.
-        */
-
-       find = new_adbfind(adb);
-       if (find == NULL)
-               return (ISC_R_NOMEMORY);
-
-       find->port = port;
-
-       /*
-        * Remember what types of addresses we are interested in.
-        */
-       find->options = options;
-       find->flags |= wanted_addresses;
-       if (FIND_WANTEVENT(find)) {
-               REQUIRE(task != NULL);
-       }
-
-       /*
-        * Try to see if we know anything about this name at all.
-        */
-       bucket = DNS_ADB_INVALIDBUCKET;
-       adbname = find_name_and_lock(adb, name, find->options, &bucket);
-       if (adb->name_sd[bucket]) {
-               DP(DEF_LEVEL,
-                  "dns_adb_createfind: returning ISC_R_SHUTTINGDOWN");
-               RUNTIME_CHECK(free_adbfind(adb, &find) == ISC_FALSE);
-               result = ISC_R_SHUTTINGDOWN;
-               goto out;
-       }
-
-       /*
-        * Nothing found.  Allocate a new adbname structure for this name.
-        */
-       if (adbname == NULL) {
-               adbname = new_adbname(adb, name);
-               if (adbname == NULL) {
-                       RUNTIME_CHECK(free_adbfind(adb, &find) == ISC_FALSE);
-                       result = ISC_R_NOMEMORY;
-                       goto out;
-               }
-               link_name(adb, bucket, adbname);
-               if (FIND_HINTOK(find))
-                       adbname->flags |= NAME_HINT_OK;
-               if (FIND_GLUEOK(find))
-                       adbname->flags |= NAME_GLUE_OK;
-               if (FIND_STARTATZONE(find))
-                       adbname->flags |= NAME_STARTATZONE;
-       }
-
-       /*
-        * Expire old entries, etc.
-        */
-       RUNTIME_CHECK(check_expire_namehooks(adbname, now, adb->overmem) ==
-                     ISC_FALSE);
-
-       /*
-        * Do we know that the name is an alias?
-        */
-       if (!EXPIRE_OK(adbname->expire_target, now)) {
-               /*
-                * Yes, it is.
-                */
-               DP(DEF_LEVEL,
-                  "dns_adb_createfind: name %p is an alias (cached)",
-                  adbname);
-               alias = ISC_TRUE;
-               goto post_copy;
-       }
-
-       /*
-        * Try to populate the name from the database and/or
-        * start fetches.  First try looking for an A record
-        * in the database.
-        */
-       if (!NAME_HAS_V4(adbname) && EXPIRE_OK(adbname->expire_v4, now)
-           && WANT_INET(wanted_addresses)) {
-               result = dbfind_name(adbname, now, dns_rdatatype_a);
-               if (result == ISC_R_SUCCESS) {
-                       DP(DEF_LEVEL,
-                          "dns_adb_createfind: found A for name %p in db",
-                          adbname);
-                       goto v6;
-               }
-
-               /*
-                * Did we get a CNAME or DNAME?
-                */
-               if (result == DNS_R_ALIAS) {
-                       DP(DEF_LEVEL,
-                          "dns_adb_createfind: name %p is an alias",
-                          adbname);
-                       alias = ISC_TRUE;
-                       goto post_copy;
-               }
-
-               /*
-                * If the name doesn't exist at all, don't bother with
-                * v6 queries; they won't work.
-                *
-                * If the name does exist but we didn't get our data, go
-                * ahead and try AAAA.
-                *
-                * If the result is neither of these, try a fetch for A.
-                */
-               if (NXDOMAIN_RESULT(result))
-                       goto fetch;
-               else if (NXRRSET_RESULT(result))
-                       goto v6;
-
-               if (!NAME_FETCH_V4(adbname))
-                       wanted_fetches |= DNS_ADBFIND_INET;
-       }
+        dns_adbfind_t *find;
+        dns_adbname_t *adbname;
+        int bucket;
+        isc_boolean_t want_event, start_at_zone, alias, have_address;
+        isc_result_t result;
+        unsigned int wanted_addresses;
+        unsigned int wanted_fetches;
+        unsigned int query_pending;
+
+        REQUIRE(DNS_ADB_VALID(adb));
+        if (task != NULL) {
+                REQUIRE(action != NULL);
+        }
+        REQUIRE(name != NULL);
+        REQUIRE(qname != NULL);
+        REQUIRE(findp != NULL && *findp == NULL);
+        REQUIRE(target == NULL || dns_name_hasbuffer(target));
+
+        REQUIRE((options & DNS_ADBFIND_ADDRESSMASK) != 0);
+
+        result = ISC_R_UNEXPECTED;
+        wanted_addresses = (options & DNS_ADBFIND_ADDRESSMASK);
+        wanted_fetches = 0;
+        query_pending = 0;
+        want_event = ISC_FALSE;
+        start_at_zone = ISC_FALSE;
+        alias = ISC_FALSE;
+
+        if (now == 0)
+                isc_stdtime_get(&now);
+
+        /*
+         * XXXMLG  Move this comment somewhere else!
+         *
+         * Look up the name in our internal database.
+         *
+         * Possibilities:  Note that these are not always exclusive.
+         *
+         *      No name found.  In this case, allocate a new name header and
+         *      an initial namehook or two.  If any of these allocations
+         *      fail, clean up and return ISC_R_NOMEMORY.
+         *
+         *      Name found, valid addresses present.  Allocate one addrinfo
+         *      structure for each found and append it to the linked list
+         *      of addresses for this header.
+         *
+         *      Name found, queries pending.  In this case, if a task was
+         *      passed in, allocate a job id, attach it to the name's job
+         *      list and remember to tell the caller that there will be
+         *      more info coming later.
+         */
+
+        find = new_adbfind(adb);
+        if (find == NULL)
+                return (ISC_R_NOMEMORY);
+
+        find->port = port;
+
+        /*
+         * Remember what types of addresses we are interested in.
+         */
+        find->options = options;
+        find->flags |= wanted_addresses;
+        if (FIND_WANTEVENT(find)) {
+                REQUIRE(task != NULL);
+        }
+
+        /*
+         * Try to see if we know anything about this name at all.
+         */
+        bucket = DNS_ADB_INVALIDBUCKET;
+        adbname = find_name_and_lock(adb, name, find->options, &bucket);
+        if (adb->name_sd[bucket]) {
+                DP(DEF_LEVEL,
+                   "dns_adb_createfind: returning ISC_R_SHUTTINGDOWN");
+                RUNTIME_CHECK(free_adbfind(adb, &find) == ISC_FALSE);
+                result = ISC_R_SHUTTINGDOWN;
+                goto out;
+        }
+
+        /*
+         * Nothing found.  Allocate a new adbname structure for this name.
+         */
+        if (adbname == NULL) {
+                /*
+                 * See if there is any stale name at the end of list, and purge
+                 * it if so.
+                 */
+                check_stale_name(adb, bucket, now);
+
+                adbname = new_adbname(adb, name);
+                if (adbname == NULL) {
+                        RUNTIME_CHECK(free_adbfind(adb, &find) == ISC_FALSE);
+                        result = ISC_R_NOMEMORY;
+                        goto out;
+                }
+                link_name(adb, bucket, adbname);
+                if (FIND_HINTOK(find))
+                        adbname->flags |= NAME_HINT_OK;
+                if (FIND_GLUEOK(find))
+                        adbname->flags |= NAME_GLUE_OK;
+                if (FIND_STARTATZONE(find))
+                        adbname->flags |= NAME_STARTATZONE;
+
+#ifdef LRU_DEBUG
+                adb->nname++;   /* XXX: omit ADB lock for brevity */
+                adb->nname_total++;
+#endif
+        } else {
+                /* Move this name forward in the LRU list */
+                ISC_LIST_UNLINK(adb->names[bucket], adbname, plink);
+                ISC_LIST_PREPEND(adb->names[bucket], adbname, plink);
+#ifdef LRU_DEBUG
+                adb->nameuses++;
+#endif
+        }
+        adbname->last_used = now;
+
+        /*
+         * Expire old entries, etc.
+         */
+        RUNTIME_CHECK(check_expire_namehooks(adbname, now) == ISC_FALSE);
+
+        /*
+         * Do we know that the name is an alias?
+         */
+        if (!EXPIRE_OK(adbname->expire_target, now)) {
+                /*
+                 * Yes, it is.
+                 */
+                DP(DEF_LEVEL,
+                   "dns_adb_createfind: name %p is an alias (cached)",
+                   adbname);
+                alias = ISC_TRUE;
+                goto post_copy;
+        }
+
+        /*
+         * Try to populate the name from the database and/or
+         * start fetches.  First try looking for an A record
+         * in the database.
+         */
+        if (!NAME_HAS_V4(adbname) && EXPIRE_OK(adbname->expire_v4, now)
+            && WANT_INET(wanted_addresses)) {
+                result = dbfind_name(adbname, now, dns_rdatatype_a);
+                if (result == ISC_R_SUCCESS) {
+                        DP(DEF_LEVEL,
+                           "dns_adb_createfind: found A for name %p in db",
+                           adbname);
+                        goto v6;
+                }
+
+                /*
+                 * Did we get a CNAME or DNAME?
+                 */
+                if (result == DNS_R_ALIAS) {
+                        DP(DEF_LEVEL,
+                           "dns_adb_createfind: name %p is an alias",
+                           adbname);
+                        alias = ISC_TRUE;
+                        goto post_copy;
+                }
+
+                /*
+                 * If the name doesn't exist at all, don't bother with
+                 * v6 queries; they won't work.
+                 *
+                 * If the name does exist but we didn't get our data, go
+                 * ahead and try AAAA.
+                 *
+                 * If the result is neither of these, try a fetch for A.
+                 */
+                if (NXDOMAIN_RESULT(result))
+                        goto fetch;
+                else if (NXRRSET_RESULT(result))
+                        goto v6;
+
+                if (!NAME_FETCH_V4(adbname))
+                        wanted_fetches |= DNS_ADBFIND_INET;
+        }
 
  v6:
-       if (!NAME_HAS_V6(adbname) && EXPIRE_OK(adbname->expire_v6, now)
-           && WANT_INET6(wanted_addresses)) {
-               result = dbfind_name(adbname, now, dns_rdatatype_aaaa);
-               if (result == ISC_R_SUCCESS) {
-                       DP(DEF_LEVEL,
-                          "dns_adb_createfind: found AAAA for name %p",
-                          adbname);
-                       goto fetch;
-               }
-
-               /*
-                * Did we get a CNAME or DNAME?
-                */
-               if (result == DNS_R_ALIAS) {
-                       DP(DEF_LEVEL,
-                          "dns_adb_createfind: name %p is an alias",
-                          adbname);
-                       alias = ISC_TRUE;
-                       goto post_copy;
-               }
-
-               /*
-                * Listen to negative cache hints, and don't start
-                * another query.
-                */
-               if (NCACHE_RESULT(result) || AUTH_NX(result))
-                       goto fetch;
-
-               if (!NAME_FETCH_V6(adbname))
-                       wanted_fetches |= DNS_ADBFIND_INET6;
-       }
+        if (!NAME_HAS_V6(adbname) && EXPIRE_OK(adbname->expire_v6, now)
+            && WANT_INET6(wanted_addresses)) {
+                result = dbfind_name(adbname, now, dns_rdatatype_aaaa);
+                if (result == ISC_R_SUCCESS) {
+                        DP(DEF_LEVEL,
+                           "dns_adb_createfind: found AAAA for name %p",
+                           adbname);
+                        goto fetch;
+                }
+
+                /*
+                 * Did we get a CNAME or DNAME?
+                 */
+                if (result == DNS_R_ALIAS) {
+                        DP(DEF_LEVEL,
+                           "dns_adb_createfind: name %p is an alias",
+                           adbname);
+                        alias = ISC_TRUE;
+                        goto post_copy;
+                }
+
+                /*
+                 * Listen to negative cache hints, and don't start
+                 * another query.
+                 */
+                if (NCACHE_RESULT(result) || AUTH_NX(result))
+                        goto fetch;
+
+                if (!NAME_FETCH_V6(adbname))
+                        wanted_fetches |= DNS_ADBFIND_INET6;
+        }
 
  fetch:
-       if ((WANT_INET(wanted_addresses) && NAME_HAS_V4(adbname)) ||
-           (WANT_INET6(wanted_addresses) && NAME_HAS_V6(adbname)))
-               have_address = ISC_TRUE;
-       else
-               have_address = ISC_FALSE;
-       if (wanted_fetches != 0 &&
-           ! (FIND_AVOIDFETCHES(find) && have_address)) {
-               /*
-                * We're missing at least one address family.  Either the
-                * caller hasn't instructed us to avoid fetches, or we don't
-                * know anything about any of the address families that would
-                * be acceptable so we have to launch fetches.
-                */
-
-               if (FIND_STARTATZONE(find))
-                       start_at_zone = ISC_TRUE;
-
-               /*
-                * Start V4.
-                */
-               if (WANT_INET(wanted_fetches) &&
-                   fetch_name(adbname, start_at_zone,
-                              dns_rdatatype_a) == ISC_R_SUCCESS) {
-                       DP(DEF_LEVEL,
-                          "dns_adb_createfind: started A fetch for name %p",
-                          adbname);
-               }
-
-               /*
-                * Start V6.
-                */
-               if (WANT_INET6(wanted_fetches) &&
-                   fetch_name(adbname, start_at_zone,
-                              dns_rdatatype_aaaa) == ISC_R_SUCCESS) {
-                       DP(DEF_LEVEL,
-                          "dns_adb_createfind: "
-                          "started AAAA fetch for name %p",
-                          adbname);
-               }
-       }
-
-       /*
-        * Run through the name and copy out the bits we are
-        * interested in.
-        */
-       copy_namehook_lists(adb, find, qname, qtype, adbname, now);
+        if ((WANT_INET(wanted_addresses) && NAME_HAS_V4(adbname)) ||
+            (WANT_INET6(wanted_addresses) && NAME_HAS_V6(adbname)))
+                have_address = ISC_TRUE;
+        else
+                have_address = ISC_FALSE;
+        if (wanted_fetches != 0 &&
+            ! (FIND_AVOIDFETCHES(find) && have_address)) {
+                /*
+                 * We're missing at least one address family.  Either the
+                 * caller hasn't instructed us to avoid fetches, or we don't
+                 * know anything about any of the address families that would
+                 * be acceptable so we have to launch fetches.
+                 */
+
+                if (FIND_STARTATZONE(find))
+                        start_at_zone = ISC_TRUE;
+
+                /*
+                 * Start V4.
+                 */
+                if (WANT_INET(wanted_fetches) &&
+                    fetch_name(adbname, start_at_zone,
+                               dns_rdatatype_a) == ISC_R_SUCCESS) {
+                        DP(DEF_LEVEL,
+                           "dns_adb_createfind: started A fetch for name %p",
+                           adbname);
+                }
+
+                /*
+                 * Start V6.
+                 */
+                if (WANT_INET6(wanted_fetches) &&
+                    fetch_name(adbname, start_at_zone,
+                               dns_rdatatype_aaaa) == ISC_R_SUCCESS) {
+                        DP(DEF_LEVEL,
+                           "dns_adb_createfind: "
+                           "started AAAA fetch for name %p",
+                           adbname);
+                }
+        }
+
+        /*
+         * Run through the name and copy out the bits we are
+         * interested in.
+         */
+        copy_namehook_lists(adb, find, qname, qtype, adbname, now);
 
  post_copy:
-       if (NAME_FETCH_V4(adbname))
-               query_pending |= DNS_ADBFIND_INET;
-       if (NAME_FETCH_V6(adbname))
-               query_pending |= DNS_ADBFIND_INET6;
-
-       /*
-        * Attach to the name's query list if there are queries
-        * already running, and we have been asked to.
-        */
-       want_event = ISC_TRUE;
-       if (!FIND_WANTEVENT(find))
-               want_event = ISC_FALSE;
-       if (FIND_WANTEMPTYEVENT(find) && FIND_HAS_ADDRS(find))
-               want_event = ISC_FALSE;
-       if ((wanted_addresses & query_pending) == 0)
-               want_event = ISC_FALSE;
-       if (alias)
-               want_event = ISC_FALSE;
-       if (want_event) {
-               find->adbname = adbname;
-               find->name_bucket = bucket;
-               ISC_LIST_APPEND(adbname->finds, find, plink);
-               find->query_pending = (query_pending & wanted_addresses);
-               find->flags &= ~DNS_ADBFIND_ADDRESSMASK;
-               find->flags |= (find->query_pending & DNS_ADBFIND_ADDRESSMASK);
-               DP(DEF_LEVEL, "createfind: attaching find %p to adbname %p",
-                  find, adbname);
-       } else {
-               /*
-                * Remove the flag so the caller knows there will never
-                * be an event, and set internal flags to fake that
-                * the event was sent and freed, so dns_adb_destroyfind() will
-                * do the right thing.
-                */
-               find->query_pending = (query_pending & wanted_addresses);
-               find->options &= ~DNS_ADBFIND_WANTEVENT;
-               find->flags |= (FIND_EVENT_SENT | FIND_EVENT_FREED);
-               find->flags &= ~DNS_ADBFIND_ADDRESSMASK;
-       }
-
-       find->partial_result |= (adbname->partial_result & wanted_addresses);
-       if (alias) {
-               if (target != NULL) {
-                       result = dns_name_copy(&adbname->target, target, NULL);
-                       if (result != ISC_R_SUCCESS)
-                               goto out;
-               }
-               result = DNS_R_ALIAS;
-       } else
-               result = ISC_R_SUCCESS;
-
-       /*
-        * Copy out error flags from the name structure into the find.
-        */
-       find->result_v4 = find_err_map[adbname->fetch_err];
-       find->result_v6 = find_err_map[adbname->fetch6_err];
+        if (NAME_FETCH_V4(adbname))
+                query_pending |= DNS_ADBFIND_INET;
+        if (NAME_FETCH_V6(adbname))
+                query_pending |= DNS_ADBFIND_INET6;
+
+        /*
+         * Attach to the name's query list if there are queries
+         * already running, and we have been asked to.
+         */
+        want_event = ISC_TRUE;
+        if (!FIND_WANTEVENT(find))
+                want_event = ISC_FALSE;
+        if (FIND_WANTEMPTYEVENT(find) && FIND_HAS_ADDRS(find))
+                want_event = ISC_FALSE;
+        if ((wanted_addresses & query_pending) == 0)
+                want_event = ISC_FALSE;
+        if (alias)
+                want_event = ISC_FALSE;
+        if (want_event) {
+                find->adbname = adbname;
+                find->name_bucket = bucket;
+                ISC_LIST_APPEND(adbname->finds, find, plink);
+                find->query_pending = (query_pending & wanted_addresses);
+                find->flags &= ~DNS_ADBFIND_ADDRESSMASK;
+                find->flags |= (find->query_pending & DNS_ADBFIND_ADDRESSMASK);
+                DP(DEF_LEVEL, "createfind: attaching find %p to adbname %p",
+                   find, adbname);
+        } else {
+                /*
+                 * Remove the flag so the caller knows there will never
+                 * be an event, and set internal flags to fake that
+                 * the event was sent and freed, so dns_adb_destroyfind() will
+                 * do the right thing.
+                 */
+                find->query_pending = (query_pending & wanted_addresses);
+                find->options &= ~DNS_ADBFIND_WANTEVENT;
+                find->flags |= (FIND_EVENT_SENT | FIND_EVENT_FREED);
+                find->flags &= ~DNS_ADBFIND_ADDRESSMASK;
+        }
+
+        find->partial_result |= (adbname->partial_result & wanted_addresses);
+        if (alias) {
+                if (target != NULL) {
+                        result = dns_name_copy(&adbname->target, target, NULL);
+                        if (result != ISC_R_SUCCESS)
+                                goto out;
+                }
+                result = DNS_R_ALIAS;
+        } else
+                result = ISC_R_SUCCESS;
+
+        /*
+         * Copy out error flags from the name structure into the find.
+         */
+        find->result_v4 = find_err_map[adbname->fetch_err];
+        find->result_v6 = find_err_map[adbname->fetch6_err];
 
  out:
-       if (find != NULL) {
-               *findp = find;
+        if (find != NULL) {
+                *findp = find;
 
-               if (want_event) {
-                       isc_task_t *taskp;
+                if (want_event) {
+                        isc_task_t *taskp;
 
-                       INSIST((find->flags & DNS_ADBFIND_ADDRESSMASK) != 0);
-                       taskp = NULL;
-                       isc_task_attach(task, &taskp);
-                       find->event.ev_sender = taskp;
-                       find->event.ev_action = action;
-                       find->event.ev_arg = arg;
-               }
-       }
+                        INSIST((find->flags & DNS_ADBFIND_ADDRESSMASK) != 0);
+                        taskp = NULL;
+                        isc_task_attach(task, &taskp);
+                        find->event.ev_sender = taskp;
+                        find->event.ev_action = action;
+                        find->event.ev_arg = arg;
+                }
+        }
 
-       UNLOCK(&adb->namelocks[bucket]);
+        UNLOCK(&adb->namelocks[bucket]);
 
-       return (result);
+        return (result);
 }
 
 void
 dns_adb_destroyfind(dns_adbfind_t **findp) {
-       dns_adbfind_t *find;
-       dns_adbentry_t *entry;
-       dns_adbaddrinfo_t *ai;
-       int bucket;
-       dns_adb_t *adb;
-
-       REQUIRE(findp != NULL && DNS_ADBFIND_VALID(*findp));
-       find = *findp;
-       *findp = NULL;
-
-       LOCK(&find->lock);
-
-       DP(DEF_LEVEL, "dns_adb_destroyfind on find %p", find);
-
-       adb = find->adb;
-       REQUIRE(DNS_ADB_VALID(adb));
-
-       REQUIRE(FIND_EVENTFREED(find));
-
-       bucket = find->name_bucket;
-       INSIST(bucket == DNS_ADB_INVALIDBUCKET);
-
-       UNLOCK(&find->lock);
-
-       /*
-        * The find doesn't exist on any list, and nothing is locked.
-        * Return the find to the memory pool, and decrement the adb's
-        * reference count.
-        */
-       ai = ISC_LIST_HEAD(find->list);
-       while (ai != NULL) {
-               ISC_LIST_UNLINK(find->list, ai, publink);
-               entry = ai->entry;
-               ai->entry = NULL;
-               INSIST(DNS_ADBENTRY_VALID(entry));
-               RUNTIME_CHECK(dec_entry_refcnt(adb, entry, ISC_TRUE) ==
-                             ISC_FALSE);
-               free_adbaddrinfo(adb, &ai);
-               ai = ISC_LIST_HEAD(find->list);
-       }
-
-       /*
-        * WARNING:  The find is freed with the adb locked.  This is done
-        * to avoid a race condition where we free the find, some other
-        * thread tests to see if it should be destroyed, detects it should
-        * be, destroys it, and then we try to lock it for our check, but the
-        * lock is destroyed.
-        */
-       LOCK(&adb->lock);
-       if (free_adbfind(adb, &find))
-               check_exit(adb);
-       UNLOCK(&adb->lock);
+        dns_adbfind_t *find;
+        dns_adbentry_t *entry;
+        dns_adbaddrinfo_t *ai;
+        int bucket;
+        dns_adb_t *adb;
+
+        REQUIRE(findp != NULL && DNS_ADBFIND_VALID(*findp));
+        find = *findp;
+        *findp = NULL;
+
+        LOCK(&find->lock);
+
+        DP(DEF_LEVEL, "dns_adb_destroyfind on find %p", find);
+
+        adb = find->adb;
+        REQUIRE(DNS_ADB_VALID(adb));
+
+        REQUIRE(FIND_EVENTFREED(find));
+
+        bucket = find->name_bucket;
+        INSIST(bucket == DNS_ADB_INVALIDBUCKET);
+
+        UNLOCK(&find->lock);
+
+        /*
+         * The find doesn't exist on any list, and nothing is locked.
+         * Return the find to the memory pool, and decrement the adb's
+         * reference count.
+         */
+        ai = ISC_LIST_HEAD(find->list);
+        while (ai != NULL) {
+                ISC_LIST_UNLINK(find->list, ai, publink);
+                entry = ai->entry;
+                ai->entry = NULL;
+                INSIST(DNS_ADBENTRY_VALID(entry));
+                RUNTIME_CHECK(dec_entry_refcnt(adb, entry, ISC_TRUE) ==
+                              ISC_FALSE);
+                free_adbaddrinfo(adb, &ai);
+                ai = ISC_LIST_HEAD(find->list);
+        }
+
+        /*
+         * WARNING:  The find is freed with the adb locked.  This is done
+         * to avoid a race condition where we free the find, some other
+         * thread tests to see if it should be destroyed, detects it should
+         * be, destroys it, and then we try to lock it for our check, but the
+         * lock is destroyed.
+         */
+        LOCK(&adb->lock);
+        if (free_adbfind(adb, &find))
+                check_exit(adb);
+        UNLOCK(&adb->lock);
 }
 
 void
 dns_adb_cancelfind(dns_adbfind_t *find) {
-       isc_event_t *ev;
-       isc_task_t *task;
-       dns_adb_t *adb;
-       int bucket;
-       int unlock_bucket;
-
-       LOCK(&find->lock);
-
-       DP(DEF_LEVEL, "dns_adb_cancelfind on find %p", find);
-
-       adb = find->adb;
-       REQUIRE(DNS_ADB_VALID(adb));
-
-       REQUIRE(!FIND_EVENTFREED(find));
-       REQUIRE(FIND_WANTEVENT(find));
-
-       bucket = find->name_bucket;
-       if (bucket == DNS_ADB_INVALIDBUCKET)
-               goto cleanup;
-
-       /*
-        * We need to get the adbname's lock to unlink the find.
-        */
-       unlock_bucket = bucket;
-       violate_locking_hierarchy(&find->lock, &adb->namelocks[unlock_bucket]);
-       bucket = find->name_bucket;
-       if (bucket != DNS_ADB_INVALIDBUCKET) {
-               ISC_LIST_UNLINK(find->adbname->finds, find, plink);
-               find->adbname = NULL;
-               find->name_bucket = DNS_ADB_INVALIDBUCKET;
-       }
-       UNLOCK(&adb->namelocks[unlock_bucket]);
-       bucket = DNS_ADB_INVALIDBUCKET;
+        isc_event_t *ev;
+        isc_task_t *task;
+        dns_adb_t *adb;
+        int bucket;
+        int unlock_bucket;
+
+        LOCK(&find->lock);
+
+        DP(DEF_LEVEL, "dns_adb_cancelfind on find %p", find);
+
+        adb = find->adb;
+        REQUIRE(DNS_ADB_VALID(adb));
+
+        REQUIRE(!FIND_EVENTFREED(find));
+        REQUIRE(FIND_WANTEVENT(find));
+
+        bucket = find->name_bucket;
+        if (bucket == DNS_ADB_INVALIDBUCKET)
+                goto cleanup;
+
+        /*
+         * We need to get the adbname's lock to unlink the find.
+         */
+        unlock_bucket = bucket;
+        violate_locking_hierarchy(&find->lock, &adb->namelocks[unlock_bucket]);
+        bucket = find->name_bucket;
+        if (bucket != DNS_ADB_INVALIDBUCKET) {
+                ISC_LIST_UNLINK(find->adbname->finds, find, plink);
+                find->adbname = NULL;
+                find->name_bucket = DNS_ADB_INVALIDBUCKET;
+        }
+        UNLOCK(&adb->namelocks[unlock_bucket]);
+        bucket = DNS_ADB_INVALIDBUCKET;
 
  cleanup:
 
-       if (!FIND_EVENTSENT(find)) {
-               ev = &find->event;
-               task = ev->ev_sender;
-               ev->ev_sender = find;
-               ev->ev_type = DNS_EVENT_ADBCANCELED;
-               ev->ev_destroy = event_free;
-               ev->ev_destroy_arg = find;
-               find->result_v4 = ISC_R_CANCELED;
-               find->result_v6 = ISC_R_CANCELED;
+        if (!FIND_EVENTSENT(find)) {
+                ev = &find->event;
+                task = ev->ev_sender;
+                ev->ev_sender = find;
+                ev->ev_type = DNS_EVENT_ADBCANCELED;
+                ev->ev_destroy = event_free;
+                ev->ev_destroy_arg = find;
+                find->result_v4 = ISC_R_CANCELED;
+                find->result_v6 = ISC_R_CANCELED;
 
-               DP(DEF_LEVEL, "sending event %p to task %p for find %p",
-                  ev, task, find);
+                DP(DEF_LEVEL, "sending event %p to task %p for find %p",
+                   ev, task, find);
 
-               isc_task_sendanddetach(&task, (isc_event_t **)&ev);
-       }
+                isc_task_sendanddetach(&task, (isc_event_t **)&ev);
+        }
 
-       UNLOCK(&find->lock);
+        UNLOCK(&find->lock);
 }
 
 void
 dns_adb_dump(dns_adb_t *adb, FILE *f) {
-       int i;
-       isc_stdtime_t now;
+        int i;
+        isc_stdtime_t now;
 
-       REQUIRE(DNS_ADB_VALID(adb));
-       REQUIRE(f != NULL);
+        REQUIRE(DNS_ADB_VALID(adb));
+        REQUIRE(f != NULL);
 
-       /*
-        * Lock the adb itself, lock all the name buckets, then lock all
-        * the entry buckets.  This should put the adb into a state where
-        * nothing can change, so we can iterate through everything and
-        * print at our leisure.
-        */
+        /*
+         * Lock the adb itself, lock all the name buckets, then lock all
+         * the entry buckets.  This should put the adb into a state where
+         * nothing can change, so we can iterate through everything and
+         * print at our leisure.
+         */
 
-       LOCK(&adb->lock);
-       isc_stdtime_get(&now);
+        LOCK(&adb->lock);
+        isc_stdtime_get(&now);
 
-       for (i = 0; i < NBUCKETS; i++)
-               RUNTIME_CHECK(cleanup_names(adb, i, now) == ISC_FALSE);
-       for (i = 0; i < NBUCKETS; i++)
-               RUNTIME_CHECK(cleanup_entries(adb, i, now) == ISC_FALSE);
+        for (i = 0; i < NBUCKETS; i++)
+                RUNTIME_CHECK(cleanup_names(adb, i, now) == ISC_FALSE);
+        for (i = 0; i < NBUCKETS; i++)
+                RUNTIME_CHECK(cleanup_entries(adb, i, now) == ISC_FALSE);
 
-       dump_adb(adb, f, ISC_FALSE, now);
-       UNLOCK(&adb->lock);
+        dump_adb(adb, f, ISC_FALSE, now);
+        UNLOCK(&adb->lock);
 }
 
 static void
 dump_ttl(FILE *f, const char *legend, isc_stdtime_t value, isc_stdtime_t now) {
-       if (value == INT_MAX)
-               return;
-       fprintf(f, " [%s TTL %d]", legend, value - now);
+        if (value == INT_MAX)
+                return;
+        fprintf(f, " [%s TTL %d]", legend, value - now);
 }
 
 static void
 dump_adb(dns_adb_t *adb, FILE *f, isc_boolean_t debug, isc_stdtime_t now) {
-       int i;
-       dns_adbname_t *name;
-       dns_adbentry_t *entry;
-
-       fprintf(f, ";\n; Address database dump\n;\n");
-       if (debug)
-               fprintf(f, "; addr %p, erefcnt %u, irefcnt %u, finds out %u\n",
-                       adb, adb->erefcnt, adb->irefcnt,
-                       isc_mempool_getallocated(adb->nhmp));
-
-       for (i = 0; i < NBUCKETS; i++)
-               LOCK(&adb->namelocks[i]);
-       for (i = 0; i < NBUCKETS; i++)
-               LOCK(&adb->entrylocks[i]);
-
-       /*
-        * Dump the names
-        */
-       for (i = 0; i < NBUCKETS; i++) {
-               name = ISC_LIST_HEAD(adb->names[i]);
-               if (name == NULL)
-                       continue;
-               if (debug)
-                       fprintf(f, "; bucket %d\n", i);
-               for (;
-                    name != NULL;
-                    name = ISC_LIST_NEXT(name, plink))
-               {
-                       if (debug)
-                               fprintf(f, "; name %p (flags %08x)\n",
-                                       name, name->flags);
-
-                       fprintf(f, "; ");
-                       print_dns_name(f, &name->name);
-                       if (dns_name_countlabels(&name->target) > 0) {
-                               fprintf(f, " alias ");
-                               print_dns_name(f, &name->target);
-                       }
-
-                       dump_ttl(f, "v4", name->expire_v4, now);
-                       dump_ttl(f, "v6", name->expire_v6, now);
-                       dump_ttl(f, "target", name->expire_target, now);
-
-                       fprintf(f, " [v4 %s] [v6 %s]",
-                               errnames[name->fetch_err],
-                               errnames[name->fetch6_err]);
-
-                       fprintf(f, "\n");
-
-                       print_namehook_list(f, "v4", &name->v4, debug, now);
-                       print_namehook_list(f, "v6", &name->v6, debug, now);
-
-                       if (debug)
-                               print_fetch_list(f, name);
-                       if (debug)
-                               print_find_list(f, name);
-
-               }
-       }
-
-       fprintf(f, ";\n; Unassociated entries\n;\n");
-
-       for (i = 0; i < NBUCKETS; i++) {
-               entry = ISC_LIST_HEAD(adb->entries[i]);
-               while (entry != NULL) {
-                       if (entry->refcnt == 0)
-                               dump_entry(f, entry, debug, now);
-                       entry = ISC_LIST_NEXT(entry, plink);
-               }
-       }
-
-       /*
-        * Unlock everything
-        */
-       for (i = 0; i < NBUCKETS; i++)
-               UNLOCK(&adb->entrylocks[i]);
-       for (i = 0; i < NBUCKETS; i++)
-               UNLOCK(&adb->namelocks[i]);
+        int i;
+        dns_adbname_t *name;
+        dns_adbentry_t *entry;
+
+        fprintf(f, ";\n; Address database dump\n;\n");
+        if (debug)
+                fprintf(f, "; addr %p, erefcnt %u, irefcnt %u, finds out %u\n",
+                        adb, adb->erefcnt, adb->irefcnt,
+                        isc_mempool_getallocated(adb->nhmp));
+
+        for (i = 0; i < NBUCKETS; i++)
+                LOCK(&adb->namelocks[i]);
+        for (i = 0; i < NBUCKETS; i++)
+                LOCK(&adb->entrylocks[i]);
+
+        /*
+         * Dump the names
+         */
+        for (i = 0; i < NBUCKETS; i++) {
+                name = ISC_LIST_HEAD(adb->names[i]);
+                if (name == NULL)
+                        continue;
+                if (debug)
+                        fprintf(f, "; bucket %d\n", i);
+                for (;
+                     name != NULL;
+                     name = ISC_LIST_NEXT(name, plink))
+                {
+                        if (debug)
+                                fprintf(f, "; name %p (flags %08x)\n",
+                                        name, name->flags);
+
+                        fprintf(f, "; ");
+                        print_dns_name(f, &name->name);
+                        if (dns_name_countlabels(&name->target) > 0) {
+                                fprintf(f, " alias ");
+                                print_dns_name(f, &name->target);
+                        }
+
+                        dump_ttl(f, "v4", name->expire_v4, now);
+                        dump_ttl(f, "v6", name->expire_v6, now);
+                        dump_ttl(f, "target", name->expire_target, now);
+
+                        fprintf(f, " [v4 %s] [v6 %s]",
+                                errnames[name->fetch_err],
+                                errnames[name->fetch6_err]);
+
+                        fprintf(f, "\n");
+
+                        print_namehook_list(f, "v4", &name->v4, debug, now);
+                        print_namehook_list(f, "v6", &name->v6, debug, now);
+
+                        if (debug)
+                                print_fetch_list(f, name);
+                        if (debug)
+                                print_find_list(f, name);
+
+                }
+        }
+
+        fprintf(f, ";\n; Unassociated entries\n;\n");
+
+        for (i = 0; i < NBUCKETS; i++) {
+                entry = ISC_LIST_HEAD(adb->entries[i]);
+                while (entry != NULL) {
+                        if (entry->refcnt == 0)
+                                dump_entry(f, entry, debug, now);
+                        entry = ISC_LIST_NEXT(entry, plink);
+                }
+        }
+
+        /*
+         * Unlock everything
+         */
+        for (i = 0; i < NBUCKETS; i++)
+                UNLOCK(&adb->entrylocks[i]);
+        for (i = 0; i < NBUCKETS; i++)
+                UNLOCK(&adb->namelocks[i]);
 }
 
 static void
 dump_entry(FILE *f, dns_adbentry_t *entry, isc_boolean_t debug,
-          isc_stdtime_t now)
+           isc_stdtime_t now)
 {
-       char addrbuf[ISC_NETADDR_FORMATSIZE];
-       char typebuf[DNS_RDATATYPE_FORMATSIZE];
-       isc_netaddr_t netaddr;
-       dns_adblameinfo_t *li;
-
-       isc_netaddr_fromsockaddr(&netaddr, &entry->sockaddr);
-       isc_netaddr_format(&netaddr, addrbuf, sizeof(addrbuf));
-
-       if (debug)
-               fprintf(f, ";\t%p: refcnt %u\n", entry, entry->refcnt);
-
-       fprintf(f, ";\t%s [srtt %u] [flags %08x]",
-               addrbuf, entry->srtt, entry->flags);
-       if (entry->expires != 0)
-               fprintf(f, " [ttl %d]", entry->expires - now);
-       fprintf(f, "\n");
-       for (li = ISC_LIST_HEAD(entry->lameinfo);
-            li != NULL;
-            li = ISC_LIST_NEXT(li, plink)) {
-               fprintf(f, ";\t\t");
-               print_dns_name(f, &li->qname);
-               dns_rdatatype_format(li->qtype, typebuf, sizeof(typebuf));
-               fprintf(f, " %s [lame TTL %d]\n", typebuf,
-                       li->lame_timer - now);
-       }
+        char addrbuf[ISC_NETADDR_FORMATSIZE];
+        char typebuf[DNS_RDATATYPE_FORMATSIZE];
+        isc_netaddr_t netaddr;
+        dns_adblameinfo_t *li;
+
+        isc_netaddr_fromsockaddr(&netaddr, &entry->sockaddr);
+        isc_netaddr_format(&netaddr, addrbuf, sizeof(addrbuf));
+
+        if (debug)
+                fprintf(f, ";\t%p: refcnt %u\n", entry, entry->refcnt);
+
+        fprintf(f, ";\t%s [srtt %u] [flags %08x]",
+                addrbuf, entry->srtt, entry->flags);
+        if (entry->expires != 0)
+                fprintf(f, " [ttl %d]", entry->expires - now);
+        fprintf(f, "\n");
+        for (li = ISC_LIST_HEAD(entry->lameinfo);
+             li != NULL;
+             li = ISC_LIST_NEXT(li, plink)) {
+                fprintf(f, ";\t\t");
+                print_dns_name(f, &li->qname);
+                dns_rdatatype_format(li->qtype, typebuf, sizeof(typebuf));
+                fprintf(f, " %s [lame TTL %d]\n", typebuf,
+                        li->lame_timer - now);
+        }
 }
 
 void
 dns_adb_dumpfind(dns_adbfind_t *find, FILE *f) {
-       char tmp[512];
-       const char *tmpp;
-       dns_adbaddrinfo_t *ai;
-       isc_sockaddr_t *sa;
-
-       /*
-        * Not used currently, in the API Just In Case we
-        * want to dump out the name and/or entries too.
-        */
-
-       LOCK(&find->lock);
-
-       fprintf(f, ";Find %p\n", find);
-       fprintf(f, ";\tqpending %08x partial %08x options %08x flags %08x\n",
-               find->query_pending, find->partial_result,
-               find->options, find->flags);
-       fprintf(f, ";\tname_bucket %d, name %p, event sender %p\n",
-               find->name_bucket, find->adbname, find->event.ev_sender);
-
-       ai = ISC_LIST_HEAD(find->list);
-       if (ai != NULL)
-               fprintf(f, "\tAddresses:\n");
-       while (ai != NULL) {
-               sa = &ai->sockaddr;
-               switch (sa->type.sa.sa_family) {
-               case AF_INET:
-                       tmpp = inet_ntop(AF_INET, &sa->type.sin.sin_addr,
-                                        tmp, sizeof(tmp));
-                       break;
-               case AF_INET6:
-                       tmpp = inet_ntop(AF_INET6, &sa->type.sin6.sin6_addr,
-                                        tmp, sizeof(tmp));
-                       break;
-               default:
-                       tmpp = "UnkFamily";
-               }
-
-               if (tmpp == NULL)
-                       tmpp = "BadAddress";
-
-               fprintf(f, "\t\tentry %p, flags %08x"
-                       " srtt %u addr %s\n",
-                       ai->entry, ai->flags, ai->srtt, tmpp);
-
-               ai = ISC_LIST_NEXT(ai, publink);
-       }
-
-       UNLOCK(&find->lock);
+        char tmp[512];
+        const char *tmpp;
+        dns_adbaddrinfo_t *ai;
+        isc_sockaddr_t *sa;
+
+        /*
+         * Not used currently, in the API Just In Case we
+         * want to dump out the name and/or entries too.
+         */
+
+        LOCK(&find->lock);
+
+        fprintf(f, ";Find %p\n", find);
+        fprintf(f, ";\tqpending %08x partial %08x options %08x flags %08x\n",
+                find->query_pending, find->partial_result,
+                find->options, find->flags);
+        fprintf(f, ";\tname_bucket %d, name %p, event sender %p\n",
+                find->name_bucket, find->adbname, find->event.ev_sender);
+
+        ai = ISC_LIST_HEAD(find->list);
+        if (ai != NULL)
+                fprintf(f, "\tAddresses:\n");
+        while (ai != NULL) {
+                sa = &ai->sockaddr;
+                switch (sa->type.sa.sa_family) {
+                case AF_INET:
+                        tmpp = inet_ntop(AF_INET, &sa->type.sin.sin_addr,
+                                         tmp, sizeof(tmp));
+                        break;
+                case AF_INET6:
+                        tmpp = inet_ntop(AF_INET6, &sa->type.sin6.sin6_addr,
+                                         tmp, sizeof(tmp));
+                        break;
+                default:
+                        tmpp = "UnkFamily";
+                }
+
+                if (tmpp == NULL)
+                        tmpp = "BadAddress";
+
+                fprintf(f, "\t\tentry %p, flags %08x"
+                        " srtt %u addr %s\n",
+                        ai->entry, ai->flags, ai->srtt, tmpp);
+
+                ai = ISC_LIST_NEXT(ai, publink);
+        }
+
+        UNLOCK(&find->lock);
 }
 
 static void
 print_dns_name(FILE *f, dns_name_t *name) {
-       char buf[DNS_NAME_FORMATSIZE];
+        char buf[DNS_NAME_FORMATSIZE];
 
-       INSIST(f != NULL);
+        INSIST(f != NULL);
 
-       dns_name_format(name, buf, sizeof(buf));
-       fprintf(f, "%s", buf);
+        dns_name_format(name, buf, sizeof(buf));
+        fprintf(f, "%s", buf);
 }
 
 static void
 print_namehook_list(FILE *f, const char *legend, dns_adbnamehooklist_t *list,
-                   isc_boolean_t debug, isc_stdtime_t now)
+                    isc_boolean_t debug, isc_stdtime_t now)
 {
-       dns_adbnamehook_t *nh;
+        dns_adbnamehook_t *nh;
 
-       for (nh = ISC_LIST_HEAD(*list);
-            nh != NULL;
-            nh = ISC_LIST_NEXT(nh, plink))
-       {
-               if (debug)
-                       fprintf(f, ";\tHook(%s) %p\n", legend, nh);
-               dump_entry(f, nh->entry, debug, now);
-       }
+        for (nh = ISC_LIST_HEAD(*list);
+             nh != NULL;
+             nh = ISC_LIST_NEXT(nh, plink))
+        {
+                if (debug)
+                        fprintf(f, ";\tHook(%s) %p\n", legend, nh);
+                dump_entry(f, nh->entry, debug, now);
+        }
 }
 
 static inline void
 print_fetch(FILE *f, dns_adbfetch_t *ft, const char *type) {
-       fprintf(f, "\t\tFetch(%s): %p -> { nh %p, entry %p, fetch %p }\n",
-               type, ft, ft->namehook, ft->entry, ft->fetch);
+        fprintf(f, "\t\tFetch(%s): %p -> { nh %p, entry %p, fetch %p }\n",
+                type, ft, ft->namehook, ft->entry, ft->fetch);
 }
 
 static void
 print_fetch_list(FILE *f, dns_adbname_t *n) {
-       if (NAME_FETCH_A(n))
-               print_fetch(f, n->fetch_a, "A");
-       if (NAME_FETCH_AAAA(n))
-               print_fetch(f, n->fetch_aaaa, "AAAA");
+        if (NAME_FETCH_A(n))
+                print_fetch(f, n->fetch_a, "A");
+        if (NAME_FETCH_AAAA(n))
+                print_fetch(f, n->fetch_aaaa, "AAAA");
 }
 
 static void
 print_find_list(FILE *f, dns_adbname_t *name) {
-       dns_adbfind_t *find;
+        dns_adbfind_t *find;
 
-       find = ISC_LIST_HEAD(name->finds);
-       while (find != NULL) {
-               dns_adb_dumpfind(find, f);
-               find = ISC_LIST_NEXT(find, plink);
-       }
+        find = ISC_LIST_HEAD(name->finds);
+        while (find != NULL) {
+                dns_adb_dumpfind(find, f);
+                find = ISC_LIST_NEXT(find, plink);
+        }
 }
 
 static isc_result_t
 dbfind_name(dns_adbname_t *adbname, isc_stdtime_t now, dns_rdatatype_t rdtype)
 {
-       isc_result_t result;
-       dns_rdataset_t rdataset;
-       dns_adb_t *adb;
-       dns_fixedname_t foundname;
-       dns_name_t *fname;
-
-       INSIST(DNS_ADBNAME_VALID(adbname));
-       adb = adbname->adb;
-       INSIST(DNS_ADB_VALID(adb));
-       INSIST(rdtype == dns_rdatatype_a || rdtype == dns_rdatatype_aaaa);
-
-       dns_fixedname_init(&foundname);
-       fname = dns_fixedname_name(&foundname);
-       dns_rdataset_init(&rdataset);
-
-       if (rdtype == dns_rdatatype_a)
-               adbname->fetch_err = FIND_ERR_UNEXPECTED;
-       else
-               adbname->fetch6_err = FIND_ERR_UNEXPECTED;
-
-       result = dns_view_find(adb->view, &adbname->name, rdtype, now,
-                              NAME_GLUEOK(adbname) ? DNS_DBFIND_GLUEOK : 0,
-                              ISC_TF(NAME_HINTOK(adbname)),
-                              NULL, NULL, fname, &rdataset, NULL);
-
-       /* XXXVIX this switch statement is too sparse to gen a jump table. */
-       switch (result) {
-       case DNS_R_GLUE:
-       case DNS_R_HINT:
-       case ISC_R_SUCCESS:
-               /*
-                * Found in the database.  Even if we can't copy out
-                * any information, return success, or else a fetch
-                * will be made, which will only make things worse.
-                */
-               if (rdtype == dns_rdatatype_a)
-                       adbname->fetch_err = FIND_ERR_SUCCESS;
-               else
-                       adbname->fetch6_err = FIND_ERR_SUCCESS;
-               result = import_rdataset(adbname, &rdataset, now);
-               break;
-       case DNS_R_NXDOMAIN:
-       case DNS_R_NXRRSET:
-               /*
-                * We're authoritative and the data doesn't exist.
-                * Make up a negative cache entry so we don't ask again
-                * for a while.
-                *
-                * XXXRTH  What time should we use?  I'm putting in 30 seconds
-                * for now.
-                */
-               if (rdtype == dns_rdatatype_a) {
-                       adbname->expire_v4 = now + 30;
-                       DP(NCACHE_LEVEL,
-                          "adb name %p: Caching auth negative entry for A",
-                          adbname);
-                       if (result == DNS_R_NXDOMAIN)
-                               adbname->fetch_err = FIND_ERR_NXDOMAIN;
-                       else
-                               adbname->fetch_err = FIND_ERR_NXRRSET;
-               } else {
-                       DP(NCACHE_LEVEL,
-                          "adb name %p: Caching auth negative entry for AAAA",
-                          adbname);
-                       adbname->expire_v6 = now + 30;
-                       if (result == DNS_R_NXDOMAIN)
-                               adbname->fetch6_err = FIND_ERR_NXDOMAIN;
-                       else
-                               adbname->fetch6_err = FIND_ERR_NXRRSET;
-               }
-               break;
-       case DNS_R_NCACHENXDOMAIN:
-       case DNS_R_NCACHENXRRSET:
-               /*
-                * We found a negative cache entry.  Pull the TTL from it
-                * so we won't ask again for a while.
-                */
-               rdataset.ttl = ttlclamp(rdataset.ttl);
-               if (rdtype == dns_rdatatype_a) {
-                       adbname->expire_v4 = rdataset.ttl + now;
-                       if (result == DNS_R_NCACHENXDOMAIN)
-                               adbname->fetch_err = FIND_ERR_NXDOMAIN;
-                       else
-                               adbname->fetch_err = FIND_ERR_NXRRSET;
-                       DP(NCACHE_LEVEL,
-                         "adb name %p: Caching negative entry for A (ttl %u)",
-                          adbname, rdataset.ttl);
-               } else {
-                       DP(NCACHE_LEVEL,
-                      "adb name %p: Caching negative entry for AAAA (ttl %u)",
-                          adbname, rdataset.ttl);
-                       adbname->expire_v6 = rdataset.ttl + now;
-                       if (result == DNS_R_NCACHENXDOMAIN)
-                               adbname->fetch6_err = FIND_ERR_NXDOMAIN;
-                       else
-                               adbname->fetch6_err = FIND_ERR_NXRRSET;
-               }
-               break;
-       case DNS_R_CNAME:
-       case DNS_R_DNAME:
-               /*
-                * Clear the hint and glue flags, so this will match
-                * more often.
-                */
-               adbname->flags &= ~(DNS_ADBFIND_GLUEOK | DNS_ADBFIND_HINTOK);
-
-               rdataset.ttl = ttlclamp(rdataset.ttl);
-               clean_target(adb, &adbname->target);
-               adbname->expire_target = INT_MAX;
-               result = set_target(adb, &adbname->name, fname, &rdataset,
-                                   &adbname->target);
-               if (result == ISC_R_SUCCESS) {
-                       result = DNS_R_ALIAS;
-                       DP(NCACHE_LEVEL,
-                          "adb name %p: caching alias target",
-                          adbname);
-                       adbname->expire_target = rdataset.ttl + now;
-               }
-               if (rdtype == dns_rdatatype_a)
-                       adbname->fetch_err = FIND_ERR_SUCCESS;
-               else
-                       adbname->fetch6_err = FIND_ERR_SUCCESS;
-               break;
-       }
-
-       if (dns_rdataset_isassociated(&rdataset))
-               dns_rdataset_disassociate(&rdataset);
-
-       return (result);
+        isc_result_t result;
+        dns_rdataset_t rdataset;
+        dns_adb_t *adb;
+        dns_fixedname_t foundname;
+        dns_name_t *fname;
+
+        INSIST(DNS_ADBNAME_VALID(adbname));
+        adb = adbname->adb;
+        INSIST(DNS_ADB_VALID(adb));
+        INSIST(rdtype == dns_rdatatype_a || rdtype == dns_rdatatype_aaaa);
+
+        dns_fixedname_init(&foundname);
+        fname = dns_fixedname_name(&foundname);
+        dns_rdataset_init(&rdataset);
+
+        if (rdtype == dns_rdatatype_a)
+                adbname->fetch_err = FIND_ERR_UNEXPECTED;
+        else
+                adbname->fetch6_err = FIND_ERR_UNEXPECTED;
+
+        result = dns_view_find(adb->view, &adbname->name, rdtype, now,
+                               NAME_GLUEOK(adbname) ? DNS_DBFIND_GLUEOK : 0,
+                               ISC_TF(NAME_HINTOK(adbname)),
+                               NULL, NULL, fname, &rdataset, NULL);
+
+        /* XXXVIX this switch statement is too sparse to gen a jump table. */
+        switch (result) {
+        case DNS_R_GLUE:
+        case DNS_R_HINT:
+        case ISC_R_SUCCESS:
+                /*
+                 * Found in the database.  Even if we can't copy out
+                 * any information, return success, or else a fetch
+                 * will be made, which will only make things worse.
+                 */
+                if (rdtype == dns_rdatatype_a)
+                        adbname->fetch_err = FIND_ERR_SUCCESS;
+                else
+                        adbname->fetch6_err = FIND_ERR_SUCCESS;
+                result = import_rdataset(adbname, &rdataset, now);
+                break;
+        case DNS_R_NXDOMAIN:
+        case DNS_R_NXRRSET:
+                /*
+                 * We're authoritative and the data doesn't exist.
+                 * Make up a negative cache entry so we don't ask again
+                 * for a while.
+                 *
+                 * XXXRTH  What time should we use?  I'm putting in 30 seconds
+                 * for now.
+                 */
+                if (rdtype == dns_rdatatype_a) {
+                        adbname->expire_v4 = now + 30;
+                        DP(NCACHE_LEVEL,
+                           "adb name %p: Caching auth negative entry for A",
+                           adbname);
+                        if (result == DNS_R_NXDOMAIN)
+                                adbname->fetch_err = FIND_ERR_NXDOMAIN;
+                        else
+                                adbname->fetch_err = FIND_ERR_NXRRSET;
+                } else {
+                        DP(NCACHE_LEVEL,
+                           "adb name %p: Caching auth negative entry for AAAA",
+                           adbname);
+                        adbname->expire_v6 = now + 30;
+                        if (result == DNS_R_NXDOMAIN)
+                                adbname->fetch6_err = FIND_ERR_NXDOMAIN;
+                        else
+                                adbname->fetch6_err = FIND_ERR_NXRRSET;
+                }
+                break;
+        case DNS_R_NCACHENXDOMAIN:
+        case DNS_R_NCACHENXRRSET:
+                /*
+                 * We found a negative cache entry.  Pull the TTL from it
+                 * so we won't ask again for a while.
+                 */
+                rdataset.ttl = ttlclamp(rdataset.ttl);
+                if (rdtype == dns_rdatatype_a) {
+                        adbname->expire_v4 = rdataset.ttl + now;
+                        if (result == DNS_R_NCACHENXDOMAIN)
+                                adbname->fetch_err = FIND_ERR_NXDOMAIN;
+                        else
+                                adbname->fetch_err = FIND_ERR_NXRRSET;
+                        DP(NCACHE_LEVEL,
+                          "adb name %p: Caching negative entry for A (ttl %u)",
+                           adbname, rdataset.ttl);
+                } else {
+                        DP(NCACHE_LEVEL,
+                       "adb name %p: Caching negative entry for AAAA (ttl %u)",
+                           adbname, rdataset.ttl);
+                        adbname->expire_v6 = rdataset.ttl + now;
+                        if (result == DNS_R_NCACHENXDOMAIN)
+                                adbname->fetch6_err = FIND_ERR_NXDOMAIN;
+                        else
+                                adbname->fetch6_err = FIND_ERR_NXRRSET;
+                }
+                break;
+        case DNS_R_CNAME:
+        case DNS_R_DNAME:
+                /*
+                 * Clear the hint and glue flags, so this will match
+                 * more often.
+                 */
+                adbname->flags &= ~(DNS_ADBFIND_GLUEOK | DNS_ADBFIND_HINTOK);
+
+                rdataset.ttl = ttlclamp(rdataset.ttl);
+                clean_target(adb, &adbname->target);
+                adbname->expire_target = INT_MAX;
+                result = set_target(adb, &adbname->name, fname, &rdataset,
+                                    &adbname->target);
+                if (result == ISC_R_SUCCESS) {
+                        result = DNS_R_ALIAS;
+                        DP(NCACHE_LEVEL,
+                           "adb name %p: caching alias target",
+                           adbname);
+                        adbname->expire_target = rdataset.ttl + now;
+                }
+                if (rdtype == dns_rdatatype_a)
+                        adbname->fetch_err = FIND_ERR_SUCCESS;
+                else
+                        adbname->fetch6_err = FIND_ERR_SUCCESS;
+                break;
+        }
+
+        if (dns_rdataset_isassociated(&rdataset))
+                dns_rdataset_disassociate(&rdataset);
+
+        return (result);
 }
 
 static void
 fetch_callback(isc_task_t *task, isc_event_t *ev) {
-       dns_fetchevent_t *dev;
-       dns_adbname_t *name;
-       dns_adb_t *adb;
-       dns_adbfetch_t *fetch;
-       int bucket;
-       isc_eventtype_t ev_status;
-       isc_stdtime_t now;
-       isc_result_t result;
-       unsigned int address_type;
-       isc_boolean_t want_check_exit = ISC_FALSE;
-
-       UNUSED(task);
-
-       INSIST(ev->ev_type == DNS_EVENT_FETCHDONE);
-       dev = (dns_fetchevent_t *)ev;
-       name = ev->ev_arg;
-       INSIST(DNS_ADBNAME_VALID(name));
-       adb = name->adb;
-       INSIST(DNS_ADB_VALID(adb));
-
-       bucket = name->lock_bucket;
-       LOCK(&adb->namelocks[bucket]);
-
-       INSIST(NAME_FETCH_A(name) || NAME_FETCH_AAAA(name));
-       address_type = 0;
-       if (NAME_FETCH_A(name) && (name->fetch_a->fetch == dev->fetch)) {
-               address_type = DNS_ADBFIND_INET;
-               fetch = name->fetch_a;
-               name->fetch_a = NULL;
-       } else if (NAME_FETCH_AAAA(name)
-                  && (name->fetch_aaaa->fetch == dev->fetch)) {
-               address_type = DNS_ADBFIND_INET6;
-               fetch = name->fetch_aaaa;
-               name->fetch_aaaa = NULL;
-       }
-       INSIST(address_type != 0);
-
-       dns_resolver_destroyfetch(&fetch->fetch);
-       dev->fetch = NULL;
-
-       ev_status = DNS_EVENT_ADBNOMOREADDRESSES;
-
-       /*
-        * Cleanup things we don't care about.
-        */
-       if (dev->node != NULL)
-               dns_db_detachnode(dev->db, &dev->node);
-       if (dev->db != NULL)
-               dns_db_detach(&dev->db);
-
-       /*
-        * If this name is marked as dead, clean up, throwing away
-        * potentially good data.
-        */
-       if (NAME_DEAD(name)) {
-               free_adbfetch(adb, &fetch);
-               isc_event_free(&ev);
-
-               want_check_exit = kill_name(&name, DNS_EVENT_ADBCANCELED);
-
-               UNLOCK(&adb->namelocks[bucket]);
-
-               if (want_check_exit) {
-                       LOCK(&adb->lock);
-                       check_exit(adb);
-                       UNLOCK(&adb->lock);
-               }
-
-               return;
-       }
-
-       isc_stdtime_get(&now);
-
-       /*
-        * If we got a negative cache response, remember it.
-        */
-       if (NCACHE_RESULT(dev->result)) {
-               dev->rdataset->ttl = ttlclamp(dev->rdataset->ttl);
-               if (address_type == DNS_ADBFIND_INET) {
-                       DP(NCACHE_LEVEL, "adb fetch name %p: "
-                          "caching negative entry for A (ttl %u)",
-                          name, dev->rdataset->ttl);
-                       name->expire_v4 = ISC_MIN(name->expire_v4,
-                                                 dev->rdataset->ttl + now);
-                       if (dev->result == DNS_R_NCACHENXDOMAIN)
-                               name->fetch_err = FIND_ERR_NXDOMAIN;
-                       else
-                               name->fetch_err = FIND_ERR_NXRRSET;
-               } else {
-                       DP(NCACHE_LEVEL, "adb fetch name %p: "
-                          "caching negative entry for AAAA (ttl %u)",
-                          name, dev->rdataset->ttl);
-                       name->expire_v6 = ISC_MIN(name->expire_v6,
-                                                 dev->rdataset->ttl + now);
-                       if (dev->result == DNS_R_NCACHENXDOMAIN)
-                               name->fetch6_err = FIND_ERR_NXDOMAIN;
-                       else
-                               name->fetch6_err = FIND_ERR_NXRRSET;
-               }
-               goto out;
-       }
-
-       /*
-        * Handle CNAME/DNAME.
-        */
-       if (dev->result == DNS_R_CNAME || dev->result == DNS_R_DNAME) {
-               dev->rdataset->ttl = ttlclamp(dev->rdataset->ttl);
-               clean_target(adb, &name->target);
-               name->expire_target = INT_MAX;
-               result = set_target(adb, &name->name,
-                                   dns_fixedname_name(&dev->foundname),
-                                   dev->rdataset,
-                                   &name->target);
-               if (result == ISC_R_SUCCESS) {
-                       DP(NCACHE_LEVEL,
-                          "adb fetch name %p: caching alias target",
-                          name);
-                       name->expire_target = dev->rdataset->ttl + now;
-               }
-               goto check_result;
-       }
-
-       /*
-        * Did we get back junk?  If so, and there are no more fetches
-        * sitting out there, tell all the finds about it.
-        */
-       if (dev->result != ISC_R_SUCCESS) {
-               char buf[DNS_NAME_FORMATSIZE];
-
-               dns_name_format(&name->name, buf, sizeof(buf));
-               DP(DEF_LEVEL, "adb: fetch of '%s' %s failed: %s",
-                  buf, address_type == DNS_ADBFIND_INET ? "A" : "AAAA",
-                  dns_result_totext(dev->result));
-               /* XXXMLG Don't pound on bad servers. */
-               if (address_type == DNS_ADBFIND_INET) {
-                       name->expire_v4 = ISC_MIN(name->expire_v4, now + 300);
-                       name->fetch_err = FIND_ERR_FAILURE;
-               } else {
-                       name->expire_v6 = ISC_MIN(name->expire_v6, now + 300);
-                       name->fetch6_err = FIND_ERR_FAILURE;
-               }
-               goto out;
-       }
-
-       /*
-        * We got something potentially useful.
-        */
-       result = import_rdataset(name, &fetch->rdataset, now);
+        dns_fetchevent_t *dev;
+        dns_adbname_t *name;
+        dns_adb_t *adb;
+        dns_adbfetch_t *fetch;
+        int bucket;
+        isc_eventtype_t ev_status;
+        isc_stdtime_t now;
+        isc_result_t result;
+        unsigned int address_type;
+        isc_boolean_t want_check_exit = ISC_FALSE;
+
+        UNUSED(task);
+
+        INSIST(ev->ev_type == DNS_EVENT_FETCHDONE);
+        dev = (dns_fetchevent_t *)ev;
+        name = ev->ev_arg;
+        INSIST(DNS_ADBNAME_VALID(name));
+        adb = name->adb;
+        INSIST(DNS_ADB_VALID(adb));
+
+        bucket = name->lock_bucket;
+        LOCK(&adb->namelocks[bucket]);
+
+        INSIST(NAME_FETCH_A(name) || NAME_FETCH_AAAA(name));
+        address_type = 0;
+        if (NAME_FETCH_A(name) && (name->fetch_a->fetch == dev->fetch)) {
+                address_type = DNS_ADBFIND_INET;
+                fetch = name->fetch_a;
+                name->fetch_a = NULL;
+        } else if (NAME_FETCH_AAAA(name)
+                   && (name->fetch_aaaa->fetch == dev->fetch)) {
+                address_type = DNS_ADBFIND_INET6;
+                fetch = name->fetch_aaaa;
+                name->fetch_aaaa = NULL;
+        }
+        INSIST(address_type != 0);
+
+        dns_resolver_destroyfetch(&fetch->fetch);
+        dev->fetch = NULL;
+
+        ev_status = DNS_EVENT_ADBNOMOREADDRESSES;
+
+        /*
+         * Cleanup things we don't care about.
+         */
+        if (dev->node != NULL)
+                dns_db_detachnode(dev->db, &dev->node);
+        if (dev->db != NULL)
+                dns_db_detach(&dev->db);
+
+        /*
+         * If this name is marked as dead, clean up, throwing away
+         * potentially good data.
+         */
+        if (NAME_DEAD(name)) {
+                free_adbfetch(adb, &fetch);
+                isc_event_free(&ev);
+
+                want_check_exit = kill_name(&name, DNS_EVENT_ADBCANCELED,
+                                            ISC_FALSE);
+
+                UNLOCK(&adb->namelocks[bucket]);
+
+                if (want_check_exit) {
+                        LOCK(&adb->lock);
+                        check_exit(adb);
+                        UNLOCK(&adb->lock);
+                }
+
+                return;
+        }
+
+        isc_stdtime_get(&now);
+
+        /*
+         * If we got a negative cache response, remember it.
+         */
+        if (NCACHE_RESULT(dev->result)) {
+                dev->rdataset->ttl = ttlclamp(dev->rdataset->ttl);
+                if (address_type == DNS_ADBFIND_INET) {
+                        DP(NCACHE_LEVEL, "adb fetch name %p: "
+                           "caching negative entry for A (ttl %u)",
+                           name, dev->rdataset->ttl);
+                        name->expire_v4 = ISC_MIN(name->expire_v4,
+                                                  dev->rdataset->ttl + now);
+                        if (dev->result == DNS_R_NCACHENXDOMAIN)
+                                name->fetch_err = FIND_ERR_NXDOMAIN;
+                        else
+                                name->fetch_err = FIND_ERR_NXRRSET;
+                } else {
+                        DP(NCACHE_LEVEL, "adb fetch name %p: "
+                           "caching negative entry for AAAA (ttl %u)",
+                           name, dev->rdataset->ttl);
+                        name->expire_v6 = ISC_MIN(name->expire_v6,
+                                                  dev->rdataset->ttl + now);
+                        if (dev->result == DNS_R_NCACHENXDOMAIN)
+                                name->fetch6_err = FIND_ERR_NXDOMAIN;
+                        else
+                                name->fetch6_err = FIND_ERR_NXRRSET;
+                }
+                goto out;
+        }
+
+        /*
+         * Handle CNAME/DNAME.
+         */
+        if (dev->result == DNS_R_CNAME || dev->result == DNS_R_DNAME) {
+                dev->rdataset->ttl = ttlclamp(dev->rdataset->ttl);
+                clean_target(adb, &name->target);
+                name->expire_target = INT_MAX;
+                result = set_target(adb, &name->name,
+                                    dns_fixedname_name(&dev->foundname),
+                                    dev->rdataset,
+                                    &name->target);
+                if (result == ISC_R_SUCCESS) {
+                        DP(NCACHE_LEVEL,
+                           "adb fetch name %p: caching alias target",
+                           name);
+                        name->expire_target = dev->rdataset->ttl + now;
+                }
+                goto check_result;
+        }
+
+        /*
+         * Did we get back junk?  If so, and there are no more fetches
+         * sitting out there, tell all the finds about it.
+         */
+        if (dev->result != ISC_R_SUCCESS) {
+                char buf[DNS_NAME_FORMATSIZE];
+
+                dns_name_format(&name->name, buf, sizeof(buf));
+                DP(DEF_LEVEL, "adb: fetch of '%s' %s failed: %s",
+                   buf, address_type == DNS_ADBFIND_INET ? "A" : "AAAA",
+                   dns_result_totext(dev->result));
+                /* XXXMLG Don't pound on bad servers. */
+                if (address_type == DNS_ADBFIND_INET) {
+                        name->expire_v4 = ISC_MIN(name->expire_v4, now + 300);
+                        name->fetch_err = FIND_ERR_FAILURE;
+                } else {
+                        name->expire_v6 = ISC_MIN(name->expire_v6, now + 300);
+                        name->fetch6_err = FIND_ERR_FAILURE;
+                }
+                goto out;
+        }
+
+        /*
+         * We got something potentially useful.
+         */
+        result = import_rdataset(name, &fetch->rdataset, now);
 
  check_result:
-       if (result == ISC_R_SUCCESS) {
-               ev_status = DNS_EVENT_ADBMOREADDRESSES;
-               if (address_type == DNS_ADBFIND_INET)
-                       name->fetch_err = FIND_ERR_SUCCESS;
-               else
-                       name->fetch6_err = FIND_ERR_SUCCESS;
-       }
+        if (result == ISC_R_SUCCESS) {
+                ev_status = DNS_EVENT_ADBMOREADDRESSES;
+                if (address_type == DNS_ADBFIND_INET)
+                        name->fetch_err = FIND_ERR_SUCCESS;
+                else
+                        name->fetch6_err = FIND_ERR_SUCCESS;
+        }
 
  out:
-       free_adbfetch(adb, &fetch);
-       isc_event_free(&ev);
+        free_adbfetch(adb, &fetch);
+        isc_event_free(&ev);
 
-       clean_finds_at_name(name, ev_status, address_type);
+        clean_finds_at_name(name, ev_status, address_type);
 
-       UNLOCK(&adb->namelocks[bucket]);
+        UNLOCK(&adb->namelocks[bucket]);
 }
 
 static isc_result_t
 fetch_name(dns_adbname_t *adbname,
-          isc_boolean_t start_at_zone,
-          dns_rdatatype_t type)
+           isc_boolean_t start_at_zone,
+           dns_rdatatype_t type)
 {
-       isc_result_t result;
-       dns_adbfetch_t *fetch = NULL;
-       dns_adb_t *adb;
-       dns_fixedname_t fixed;
-       dns_name_t *name;
-       dns_rdataset_t rdataset;
-       dns_rdataset_t *nameservers;
-       unsigned int options;
-
-       INSIST(DNS_ADBNAME_VALID(adbname));
-       adb = adbname->adb;
-       INSIST(DNS_ADB_VALID(adb));
-
-       INSIST((type == dns_rdatatype_a && !NAME_FETCH_V4(adbname)) ||
-              (type == dns_rdatatype_aaaa && !NAME_FETCH_V6(adbname)));
-
-       adbname->fetch_err = FIND_ERR_NOTFOUND;
-
-       name = NULL;
-       nameservers = NULL;
-       dns_rdataset_init(&rdataset);
-
-       options = DNS_FETCHOPT_NOVALIDATE;
-       if (start_at_zone) {
-               DP(ENTER_LEVEL,
-                  "fetch_name: starting at zone for name %p",
-                  adbname);
-               dns_fixedname_init(&fixed);
-               name = dns_fixedname_name(&fixed);
-               result = dns_view_findzonecut2(adb->view, &adbname->name, name,
-                                              0, 0, ISC_TRUE, ISC_FALSE,
-                                              &rdataset, NULL);
-               if (result != ISC_R_SUCCESS && result != DNS_R_HINT)
-                       goto cleanup;
-               nameservers = &rdataset;
-               options |= DNS_FETCHOPT_UNSHARED;
-       }
-
-       fetch = new_adbfetch(adb);
-       if (fetch == NULL) {
-               result = ISC_R_NOMEMORY;
-               goto cleanup;
-       }
-
-       result = dns_resolver_createfetch(adb->view->resolver, &adbname->name,
-                                         type, name, nameservers, NULL,
-                                         options, adb->task, fetch_callback,
-                                         adbname, &fetch->rdataset, NULL,
-                                         &fetch->fetch);
-       if (result != ISC_R_SUCCESS)
-               goto cleanup;
-
-       if (type == dns_rdatatype_a)
-               adbname->fetch_a = fetch;
-       else
-               adbname->fetch_aaaa = fetch;
-       fetch = NULL;  /* Keep us from cleaning this up below. */
+        isc_result_t result;
+        dns_adbfetch_t *fetch = NULL;
+        dns_adb_t *adb;
+        dns_fixedname_t fixed;
+        dns_name_t *name;
+        dns_rdataset_t rdataset;
+        dns_rdataset_t *nameservers;
+        unsigned int options;
+
+        INSIST(DNS_ADBNAME_VALID(adbname));
+        adb = adbname->adb;
+        INSIST(DNS_ADB_VALID(adb));
+
+        INSIST((type == dns_rdatatype_a && !NAME_FETCH_V4(adbname)) ||
+               (type == dns_rdatatype_aaaa && !NAME_FETCH_V6(adbname)));
+
+        adbname->fetch_err = FIND_ERR_NOTFOUND;
+
+        name = NULL;
+        nameservers = NULL;
+        dns_rdataset_init(&rdataset);
+
+        options = DNS_FETCHOPT_NOVALIDATE;
+        if (start_at_zone) {
+                DP(ENTER_LEVEL,
+                   "fetch_name: starting at zone for name %p",
+                   adbname);
+                dns_fixedname_init(&fixed);
+                name = dns_fixedname_name(&fixed);
+                result = dns_view_findzonecut2(adb->view, &adbname->name, name,
+                                               0, 0, ISC_TRUE, ISC_FALSE,
+                                               &rdataset, NULL);
+                if (result != ISC_R_SUCCESS && result != DNS_R_HINT)
+                        goto cleanup;
+                nameservers = &rdataset;
+                options |= DNS_FETCHOPT_UNSHARED;
+        }
+
+        fetch = new_adbfetch(adb);
+        if (fetch == NULL) {
+                result = ISC_R_NOMEMORY;
+                goto cleanup;
+        }
+
+        result = dns_resolver_createfetch(adb->view->resolver, &adbname->name,
+                                          type, name, nameservers, NULL,
+                                          options, adb->task, fetch_callback,
+                                          adbname, &fetch->rdataset, NULL,
+                                          &fetch->fetch);
+        if (result != ISC_R_SUCCESS)
+                goto cleanup;
+
+        if (type == dns_rdatatype_a)
+                adbname->fetch_a = fetch;
+        else
+                adbname->fetch_aaaa = fetch;
+        fetch = NULL;  /* Keep us from cleaning this up below. */
 
  cleanup:
-       if (fetch != NULL)
-               free_adbfetch(adb, &fetch);
-       if (dns_rdataset_isassociated(&rdataset))
-               dns_rdataset_disassociate(&rdataset);
+        if (fetch != NULL)
+                free_adbfetch(adb, &fetch);
+        if (dns_rdataset_isassociated(&rdataset))
+                dns_rdataset_disassociate(&rdataset);
 
-       return (result);
+        return (result);
 }
 
 /*
@@ -3344,267 +3544,315 @@ fetch_name(dns_adbname_t *adbname,
  */
 isc_result_t
 dns_adb_marklame(dns_adb_t *adb, dns_adbaddrinfo_t *addr, dns_name_t *qname,
-                dns_rdatatype_t qtype, isc_stdtime_t expire_time)
+                 dns_rdatatype_t qtype, isc_stdtime_t expire_time)
 {
-       dns_adblameinfo_t *li;
-       int bucket;
-       isc_result_t result = ISC_R_SUCCESS;
-
-       REQUIRE(DNS_ADB_VALID(adb));
-       REQUIRE(DNS_ADBADDRINFO_VALID(addr));
-       REQUIRE(qname != NULL);
-
-       bucket = addr->entry->lock_bucket;
-       LOCK(&adb->entrylocks[bucket]);
-       li = ISC_LIST_HEAD(addr->entry->lameinfo);
-       while (li != NULL &&
-              (li->qtype != qtype || !dns_name_equal(qname, &li->qname)))
-               li = ISC_LIST_NEXT(li, plink);
-       if (li != NULL) {
-               if (expire_time > li->lame_timer)
-                       li->lame_timer = expire_time;
-               goto unlock;
-       }
-       li = new_adblameinfo(adb, qname, qtype);
-       if (li == NULL) {
-               result = ISC_R_NOMEMORY;
-               goto unlock;
-       }
-
-       li->lame_timer = expire_time;
-
-       ISC_LIST_PREPEND(addr->entry->lameinfo, li, plink);
+        dns_adblameinfo_t *li;
+        int bucket;
+        isc_result_t result = ISC_R_SUCCESS;
+
+        REQUIRE(DNS_ADB_VALID(adb));
+        REQUIRE(DNS_ADBADDRINFO_VALID(addr));
+        REQUIRE(qname != NULL);
+
+        bucket = addr->entry->lock_bucket;
+        LOCK(&adb->entrylocks[bucket]);
+        li = ISC_LIST_HEAD(addr->entry->lameinfo);
+        while (li != NULL &&
+               (li->qtype != qtype || !dns_name_equal(qname, &li->qname)))
+                li = ISC_LIST_NEXT(li, plink);
+        if (li != NULL) {
+                if (expire_time > li->lame_timer)
+                        li->lame_timer = expire_time;
+                goto unlock;
+        }
+        li = new_adblameinfo(adb, qname, qtype);
+        if (li == NULL) {
+                result = ISC_R_NOMEMORY;
+                goto unlock;
+        }
+
+        li->lame_timer = expire_time;
+
+        ISC_LIST_PREPEND(addr->entry->lameinfo, li, plink);
  unlock:
-       UNLOCK(&adb->entrylocks[bucket]);
+        UNLOCK(&adb->entrylocks[bucket]);
 
-       return (result);
+        return (result);
 }
 
 void
 dns_adb_adjustsrtt(dns_adb_t *adb, dns_adbaddrinfo_t *addr,
-                  unsigned int rtt, unsigned int factor)
+                   unsigned int rtt, unsigned int factor)
 {
-       int bucket;
-       unsigned int new_srtt;
-       isc_stdtime_t now;
+        int bucket;
+        unsigned int new_srtt;
+        isc_stdtime_t now;
 
-       REQUIRE(DNS_ADB_VALID(adb));
-       REQUIRE(DNS_ADBADDRINFO_VALID(addr));
-       REQUIRE(factor <= 10);
+        REQUIRE(DNS_ADB_VALID(adb));
+        REQUIRE(DNS_ADBADDRINFO_VALID(addr));
+        REQUIRE(factor <= 10);
 
-       bucket = addr->entry->lock_bucket;
-       LOCK(&adb->entrylocks[bucket]);
+        bucket = addr->entry->lock_bucket;
+        LOCK(&adb->entrylocks[bucket]);
 
-       if (factor == DNS_ADB_RTTADJAGE)
-               new_srtt = addr->entry->srtt * 98 / 100;
-       else
-               new_srtt = (addr->entry->srtt / 10 * factor)
-                       + (rtt / 10 * (10 - factor));
+        if (factor == DNS_ADB_RTTADJAGE)
+                new_srtt = addr->entry->srtt * 98 / 100;
+        else
+                new_srtt = (addr->entry->srtt / 10 * factor)
+                        + (rtt / 10 * (10 - factor));
 
-       addr->entry->srtt = new_srtt;
-       addr->srtt = new_srtt;
+        addr->entry->srtt = new_srtt;
+        addr->srtt = new_srtt;
 
-       isc_stdtime_get(&now);
-       addr->entry->expires = now + ADB_ENTRY_WINDOW;
+        isc_stdtime_get(&now);
+        addr->entry->expires = now + ADB_ENTRY_WINDOW;
 
-       UNLOCK(&adb->entrylocks[bucket]);
+        UNLOCK(&adb->entrylocks[bucket]);
 }
 
 void
 dns_adb_changeflags(dns_adb_t *adb, dns_adbaddrinfo_t *addr,
-                   unsigned int bits, unsigned int mask)
+                    unsigned int bits, unsigned int mask)
 {
-       int bucket;
+        int bucket;
 
-       REQUIRE(DNS_ADB_VALID(adb));
-       REQUIRE(DNS_ADBADDRINFO_VALID(addr));
+        REQUIRE(DNS_ADB_VALID(adb));
+        REQUIRE(DNS_ADBADDRINFO_VALID(addr));
 
-       bucket = addr->entry->lock_bucket;
-       LOCK(&adb->entrylocks[bucket]);
+        bucket = addr->entry->lock_bucket;
+        LOCK(&adb->entrylocks[bucket]);
 
-       addr->entry->flags = (addr->entry->flags & ~mask) | (bits & mask);
-       /*
-        * Note that we do not update the other bits in addr->flags with
-        * the most recent values from addr->entry->flags.
-        */
-       addr->flags = (addr->flags & ~mask) | (bits & mask);
+        addr->entry->flags = (addr->entry->flags & ~mask) | (bits & mask);
+        /*
+         * Note that we do not update the other bits in addr->flags with
+         * the most recent values from addr->entry->flags.
+         */
+        addr->flags = (addr->flags & ~mask) | (bits & mask);
 
-       UNLOCK(&adb->entrylocks[bucket]);
+        UNLOCK(&adb->entrylocks[bucket]);
 }
 
 isc_result_t
 dns_adb_findaddrinfo(dns_adb_t *adb, isc_sockaddr_t *sa,
-                    dns_adbaddrinfo_t **addrp, isc_stdtime_t now)
+                     dns_adbaddrinfo_t **addrp, isc_stdtime_t now)
 {
-       int bucket;
-       dns_adbentry_t *entry;
-       dns_adbaddrinfo_t *addr;
-       isc_result_t result;
-       in_port_t port;
-
-       REQUIRE(DNS_ADB_VALID(adb));
-       REQUIRE(addrp != NULL && *addrp == NULL);
-
-       UNUSED(now);
-
-       result = ISC_R_SUCCESS;
-       bucket = DNS_ADB_INVALIDBUCKET;
-       entry = find_entry_and_lock(adb, sa, &bucket);
-       if (adb->entry_sd[bucket]) {
-               result = ISC_R_SHUTTINGDOWN;
-               goto unlock;
-       }
-       if (entry == NULL) {
-               /*
-                * We don't know anything about this address.
-                */
-               entry = new_adbentry(adb);
-               if (entry == NULL) {
-                       result = ISC_R_NOMEMORY;
-                       goto unlock;
-               }
-               entry->sockaddr = *sa;
-               link_entry(adb, bucket, entry);
-               DP(ENTER_LEVEL, "findaddrinfo: new entry %p", entry);
-       } else
-               DP(ENTER_LEVEL, "findaddrinfo: found entry %p", entry);
-
-       port = isc_sockaddr_getport(sa);
-       addr = new_adbaddrinfo(adb, entry, port);
-       if (addr == NULL) {
-               result = ISC_R_NOMEMORY;
-       } else {
-               inc_entry_refcnt(adb, entry, ISC_FALSE);
-               *addrp = addr;
-       }
+        int bucket;
+        dns_adbentry_t *entry;
+        dns_adbaddrinfo_t *addr;
+        isc_result_t result;
+        in_port_t port;
+
+        REQUIRE(DNS_ADB_VALID(adb));
+        REQUIRE(addrp != NULL && *addrp == NULL);
+
+        UNUSED(now);
+
+        result = ISC_R_SUCCESS;
+        bucket = DNS_ADB_INVALIDBUCKET;
+        entry = find_entry_and_lock(adb, sa, &bucket);
+        if (adb->entry_sd[bucket]) {
+                result = ISC_R_SHUTTINGDOWN;
+                goto unlock;
+        }
+        if (entry == NULL) {
+                /*
+                 * We don't know anything about this address.
+                 */
+                entry = new_adbentry(adb);
+                if (entry == NULL) {
+                        result = ISC_R_NOMEMORY;
+                        goto unlock;
+                }
+                entry->sockaddr = *sa;
+                link_entry(adb, bucket, entry);
+                DP(ENTER_LEVEL, "findaddrinfo: new entry %p", entry);
+        } else
+                DP(ENTER_LEVEL, "findaddrinfo: found entry %p", entry);
+
+        port = isc_sockaddr_getport(sa);
+        addr = new_adbaddrinfo(adb, entry, port);
+        if (addr == NULL) {
+                result = ISC_R_NOMEMORY;
+        } else {
+                inc_entry_refcnt(adb, entry, ISC_FALSE);
+                *addrp = addr;
+        }
 
  unlock:
-       UNLOCK(&adb->entrylocks[bucket]);
+        UNLOCK(&adb->entrylocks[bucket]);
 
-       return (result);
+        return (result);
 }
 
 void
 dns_adb_freeaddrinfo(dns_adb_t *adb, dns_adbaddrinfo_t **addrp) {
-       dns_adbaddrinfo_t *addr;
-       dns_adbentry_t *entry;
-       int bucket;
-       isc_stdtime_t now;
-       isc_boolean_t want_check_exit = ISC_FALSE;
+        dns_adbaddrinfo_t *addr;
+        dns_adbentry_t *entry;
+        int bucket;
+        isc_stdtime_t now;
+        isc_boolean_t want_check_exit = ISC_FALSE;
 
-       REQUIRE(DNS_ADB_VALID(adb));
-       REQUIRE(addrp != NULL);
-       addr = *addrp;
-       REQUIRE(DNS_ADBADDRINFO_VALID(addr));
-       entry = addr->entry;
-       REQUIRE(DNS_ADBENTRY_VALID(entry));
+        REQUIRE(DNS_ADB_VALID(adb));
+        REQUIRE(addrp != NULL);
+        addr = *addrp;
+        REQUIRE(DNS_ADBADDRINFO_VALID(addr));
+        entry = addr->entry;
+        REQUIRE(DNS_ADBENTRY_VALID(entry));
 
-       isc_stdtime_get(&now);
+        isc_stdtime_get(&now);
 
-       *addrp = NULL;
+        *addrp = NULL;
 
-       bucket = addr->entry->lock_bucket;
-       LOCK(&adb->entrylocks[bucket]);
+        bucket = addr->entry->lock_bucket;
+        LOCK(&adb->entrylocks[bucket]);
 
-       entry->expires = now + ADB_ENTRY_WINDOW;
+        entry->expires = now + ADB_ENTRY_WINDOW;
 
-       want_check_exit = dec_entry_refcnt(adb, entry, ISC_FALSE);
+        want_check_exit = dec_entry_refcnt(adb, entry, ISC_FALSE);
 
-       UNLOCK(&adb->entrylocks[bucket]);
+        UNLOCK(&adb->entrylocks[bucket]);
 
-       addr->entry = NULL;
-       free_adbaddrinfo(adb, &addr);
+        addr->entry = NULL;
+        free_adbaddrinfo(adb, &addr);
 
-       if (want_check_exit) {
-               LOCK(&adb->lock);
-               check_exit(adb);
-               UNLOCK(&adb->lock);
-       }
+        if (want_check_exit) {
+                LOCK(&adb->lock);
+                check_exit(adb);
+                UNLOCK(&adb->lock);
+        }
 }
 
 void
 dns_adb_flush(dns_adb_t *adb) {
-       unsigned int i;
+        unsigned int i;
 
-       INSIST(DNS_ADB_VALID(adb));
+        INSIST(DNS_ADB_VALID(adb));
 
-       LOCK(&adb->lock);
+        LOCK(&adb->lock);
 
-       /*
-        * Call our cleanup routines.
-        */
-       for (i = 0; i < NBUCKETS; i++)
-               RUNTIME_CHECK(cleanup_names(adb, i, INT_MAX) == ISC_FALSE);
-       for (i = 0; i < NBUCKETS; i++)
-               RUNTIME_CHECK(cleanup_entries(adb, i, INT_MAX) == ISC_FALSE);
+        /*
+         * Call our cleanup routines.
+         */
+        for (i = 0; i < NBUCKETS; i++)
+                RUNTIME_CHECK(cleanup_names(adb, i, INT_MAX) == ISC_FALSE);
+        for (i = 0; i < NBUCKETS; i++)
+                RUNTIME_CHECK(cleanup_entries(adb, i, INT_MAX) == ISC_FALSE);
 
 #ifdef DUMP_ADB_AFTER_CLEANING
-       dump_adb(adb, stdout, ISC_TRUE, INT_MAX);
+        dump_adb(adb, stdout, ISC_TRUE, INT_MAX);
 #endif
 
-       UNLOCK(&adb->lock);
+        UNLOCK(&adb->lock);
 }
 
 void
 dns_adb_flushname(dns_adb_t *adb, dns_name_t *name) {
-       dns_adbname_t *adbname;
-       dns_adbname_t *nextname;
-       int bucket;
-
-       INSIST(DNS_ADB_VALID(adb));
-
-       LOCK(&adb->lock);
-       bucket = dns_name_hash(name, ISC_FALSE) % NBUCKETS;
-       LOCK(&adb->namelocks[bucket]);
-       adbname = ISC_LIST_HEAD(adb->names[bucket]);
-       while (adbname != NULL) {
-               nextname = ISC_LIST_NEXT(adbname, plink);
-               if (!NAME_DEAD(adbname) &&
-                   dns_name_equal(name, &adbname->name)) {
-                       RUNTIME_CHECK(kill_name(&adbname,
-                                               DNS_EVENT_ADBCANCELED) ==
-                                     ISC_FALSE);
-               }
-               adbname = nextname;
-       }
-       UNLOCK(&adb->namelocks[bucket]);
-       UNLOCK(&adb->lock);
+        dns_adbname_t *adbname;
+        dns_adbname_t *nextname;
+        int bucket;
+
+        INSIST(DNS_ADB_VALID(adb));
+
+        LOCK(&adb->lock);
+        bucket = dns_name_hash(name, ISC_FALSE) % NBUCKETS;
+        LOCK(&adb->namelocks[bucket]);
+        adbname = ISC_LIST_HEAD(adb->names[bucket]);
+        while (adbname != NULL) {
+                nextname = ISC_LIST_NEXT(adbname, plink);
+                if (!NAME_DEAD(adbname) &&
+                    dns_name_equal(name, &adbname->name)) {
+                        RUNTIME_CHECK(kill_name(&adbname,
+                                                DNS_EVENT_ADBCANCELED,
+                                                ISC_TRUE) ==
+                                      ISC_FALSE);
+                }
+                adbname = nextname;
+        }
+        UNLOCK(&adb->namelocks[bucket]);
+        UNLOCK(&adb->lock);
 }
 
 static void
 water(void *arg, int mark) {
-       dns_adb_t *adb = arg;
-       isc_boolean_t overmem = ISC_TF(mark == ISC_MEM_HIWATER);
-       isc_interval_t interval;
+        dns_adb_t *adb = arg;
+        isc_boolean_t overmem = ISC_TF(mark == ISC_MEM_HIWATER);
+
+        REQUIRE(DNS_ADB_VALID(adb));
 
-       REQUIRE(DNS_ADB_VALID(adb));
+        DP(ISC_LOG_DEBUG(1),
+           "adb reached %s water mark", overmem ? "high" : "low");
 
-       DP(ISC_LOG_DEBUG(1),
-          "adb reached %s water mark", overmem ? "high" : "low");
+        adb->overmem = overmem;
+#if 0       /* we don't need this timer for the new cleaning policy. */
+        if (overmem) {
+                isc_interval_t interval;
 
-       adb->overmem = overmem;
-       if (overmem) {
-               isc_interval_set(&interval, 0, 1);
-               (void)isc_timer_reset(adb->timer, isc_timertype_once, NULL,
-                                     &interval, ISC_TRUE);
-       }
+                isc_interval_set(&interval, 0, 1);
+                (void)isc_timer_reset(adb->timer, isc_timertype_once, NULL,
+                                      &interval, ISC_TRUE);
+        }
+#endif
 }
 
 void
 dns_adb_setadbsize(dns_adb_t *adb, isc_uint32_t size) {
-       isc_uint32_t hiwater;
-       isc_uint32_t lowater;
+        isc_uint32_t hiwater;
+        isc_uint32_t lowater;
 
-       INSIST(DNS_ADB_VALID(adb));
+        INSIST(DNS_ADB_VALID(adb));
 
-       if (size != 0 && size < DNS_ADB_MINADBSIZE)
-               size = DNS_ADB_MINADBSIZE;
+        if (size != 0 && size < DNS_ADB_MINADBSIZE)
+                size = DNS_ADB_MINADBSIZE;
 
-       hiwater = size - (size >> 3);   /* Approximately 7/8ths. */
-       lowater = size - (size >> 2);   /* Approximately 3/4ths. */
+        hiwater = size - (size >> 3);   /* Approximately 7/8ths. */
+        lowater = size - (size >> 2);   /* Approximately 3/4ths. */
 
-       if (size == 0 || hiwater == 0 || lowater == 0)
-               isc_mem_setwater(adb->mctx, water, adb, 0, 0);
-       else
-               isc_mem_setwater(adb->mctx, water, adb, hiwater, lowater);
+        if (size == 0 || hiwater == 0 || lowater == 0)
+                isc_mem_setwater(adb->mctx, water, adb, 0, 0);
+        else
+                isc_mem_setwater(adb->mctx, water, adb, hiwater, lowater);
 }
+
+#ifdef LRU_DEBUG
+/*
+ * Periodic dumping of the internal state of the statistics.
+ * This will dump the cache contents, uses, record types, etc.
+ */
+static void
+timer_dump(isc_task_t *task, isc_event_t *ev) {
+        dns_adb_t *adb;
+        isc_interval_t interval;
+        isc_time_t nexttime;
+
+        UNUSED(task);
+
+        adb = ev->ev_arg;
+        INSIST(DNS_ADB_VALID(adb));
+
+        LOCK(&adb->lock);
+        if (adb->nname > 0 || adb->nentry > 0) {
+                isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+                              DNS_LOGMODULE_ADB, ISC_LOG_INFO,
+                              "ADB memory usage %p: mem inuse %lu, "
+                              "%u/%u names, %u/%u entries, "
+                              "purge/scan=%u(%u,%u)/%u, overmem=%d",
+                              adb, (unsigned long)isc_mem_inuse(adb->mctx),
+                              adb->nname, adb->nname_total,
+                              adb->nentry, adb->nentry_total,
+                              adb->stale_purge, adb->stale_expire,
+                              adb->stale_lru, adb->stale_scan, adb->overmem);
+        }
+
+        interval.seconds = DUMP_INTERVAL;
+        interval.nanoseconds = 0;
+
+        RUNTIME_CHECK(isc_time_add(&adb->dump_time, &interval, &nexttime) ==
+                      ISC_R_SUCCESS); /* XXX: this is not always true */
+        adb->dump_time = nexttime;
+        (void)isc_timer_reset(adb->dump_timer, isc_timertype_once,
+                              &adb->dump_time, NULL, ISC_FALSE);
+        UNLOCK(&adb->lock);
+
+        isc_event_free(&ev);
+}
+#endif
index 5f6e6c6d734485f494b04017e3e82c33e79e6ed7..cd3842050936f9118ec7c9520fedd6295609157f 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: cache.c,v 1.75 2007/06/19 23:47:16 tbox Exp $ */
+/* $Id: cache.c,v 1.76 2007/10/19 17:15:53 explorer Exp $ */
 
 /*! \file */
 
 #include <dns/rdatasetiter.h>
 #include <dns/result.h>
 
-#define CACHE_MAGIC            ISC_MAGIC('$', '$', '$', '$')
-#define VALID_CACHE(cache)     ISC_MAGIC_VALID(cache, CACHE_MAGIC)
+#define CACHE_MAGIC             ISC_MAGIC('$', '$', '$', '$')
+#define VALID_CACHE(cache)      ISC_MAGIC_VALID(cache, CACHE_MAGIC)
 
-/*! 
+/*!
  * Control incremental cleaning.
  * DNS_CACHE_MINSIZE is how many bytes is the floor for dns_cache_setcachesize().
  * See also DNS_CACHE_CLEANERINCREMENT
  */
-#define DNS_CACHE_MINSIZE              2097152 /*%< Bytes.  2097152 = 2 MB */
-/*! 
+#define DNS_CACHE_MINSIZE               2097152 /*%< Bytes.  2097152 = 2 MB */
+/*!
  * Control incremental cleaning.
  * CLEANERINCREMENT is how many nodes are examined in one pass.
- * See also DNS_CACHE_MINSIZE 
+ * See also DNS_CACHE_MINSIZE
  */
-#define DNS_CACHE_CLEANERINCREMENT     1000U   /*%< Number of nodes. */
+#define DNS_CACHE_CLEANERINCREMENT      1000U   /*%< Number of nodes. */
 
 /***
- ***   Types
+ ***    Types
  ***/
 
 /*
 typedef struct cache_cleaner cache_cleaner_t;
 
 typedef enum {
-       cleaner_s_idle, /*%< Waiting for cleaning-interval to expire. */
-       cleaner_s_busy, /*%< Currently cleaning. */
-       cleaner_s_done  /*%< Freed enough memory after being overmem. */
+        cleaner_s_idle, /*%< Waiting for cleaning-interval to expire. */
+        cleaner_s_busy, /*%< Currently cleaning. */
+        cleaner_s_done  /*%< Freed enough memory after being overmem. */
 } cleaner_state_t;
 
 /*
  * Convenience macros for comprehensive assertion checking.
  */
-#define CLEANER_IDLE(c) ((c)->state == cleaner_s_idle && \
-                        (c)->resched_event != NULL)
-#define CLEANER_BUSY(c) ((c)->state == cleaner_s_busy && \
-                        (c)->iterator != NULL && \
-                        (c)->resched_event == NULL)
+#define CLEANER_IDLE(c) ((c)->state == cleaner_s_idle)
+#define CLEANER_BUSY(c) ((c)->state == cleaner_s_busy)
 
 /*%
  * Accesses to a cache cleaner object are synchronized through
  * task/event serialization, or locked from the cache object.
  */
 struct cache_cleaner {
-       isc_mutex_t     lock;
-       /*%<
-        * Locks overmem_event, overmem.  Note: never allocate memory
-        * while holding this lock - that could lead to deadlock since
-        * the lock is take by water() which is called from the memory
-        * allocator.
-        */
-
-       dns_cache_t     *cache;
-       isc_task_t      *task;
-       unsigned int    cleaning_interval; /*% The cleaning-interval from
-                                             named.conf, in seconds. */
-       isc_timer_t     *cleaning_timer;
-       isc_event_t     *resched_event; /*% Sent by cleaner task to
-                                          itself to reschedule */
-       isc_event_t     *overmem_event;
-
-       dns_dbiterator_t *iterator;
-       unsigned int     increment;     /*% Number of names to
-                                          clean in one increment */
-       cleaner_state_t  state;         /*% Idle/Busy. */
-       isc_boolean_t    overmem;       /*% The cache is in an overmem state. */
-       isc_boolean_t    replaceiterator;
+        isc_mutex_t     lock;
+        /*%<
+         * Locks overmem.  Note: never allocate memory
+         * while holding this lock - that could lead to deadlock since
+         * the lock is take by water() which is called from the memory
+         * allocator.
+         */
+
+        dns_cache_t     *cache;
+        isc_task_t      *task;
+        unsigned int    cleaning_interval; /*% The cleaning-interval from
+                                              named.conf, in seconds. */
+        isc_timer_t     *cleaning_timer;
+
+        unsigned int     increment;     /*% Number of names to
+                                           clean in one increment */
+        cleaner_state_t  state;         /*% Idle/Busy. */
+        isc_boolean_t    overmem;       /*% The cache is in an overmem state. */
 };
 
 /*%
@@ -116,47 +108,54 @@ struct cache_cleaner {
  */
 
 struct dns_cache {
-       /* Unlocked. */
-       unsigned int            magic;
-       isc_mutex_t             lock;
-       isc_mutex_t             filelock;
-       isc_mem_t               *mctx;
-
-       /* Locked by 'lock'. */
-       int                     references;
-       int                     live_tasks;
-       dns_rdataclass_t        rdclass;
-       dns_db_t                *db;
-       cache_cleaner_t         cleaner;
-       char                    *db_type;
-       int                     db_argc;
-       char                    **db_argv;
-
-       /* Locked by 'filelock'. */
-       char *                  filename;
-       /* Access to the on-disk cache file is also locked by 'filelock'. */
+        /* Unlocked. */
+        unsigned int            magic;
+        isc_mutex_t             lock;
+        isc_mutex_t             filelock;
+        isc_mem_t               *mctx;
+
+        /* Locked by 'lock'. */
+        int                     references;
+        int                     live_tasks;
+        dns_rdataclass_t        rdclass;
+        dns_db_t                *db;
+        cache_cleaner_t         cleaner;
+        char                    *db_type;
+        int                     db_argc;
+        char                    **db_argv;
+
+        /* Locked by 'filelock'. */
+        char *                  filename;
+        /* Access to the on-disk cache file is also locked by 'filelock'. */
+
+#ifdef LRU_DEBUG
+#define DUMP_INTERVAL 30        /* seconds */
+        isc_timer_t                    *dump_timer; /* for test */
+        isc_time_t                      dump_time; /* for test */
+#endif
 };
 
 /***
- ***   Functions
+ ***    Functions
  ***/
 
 static isc_result_t
 cache_cleaner_init(dns_cache_t *cache, isc_taskmgr_t *taskmgr,
-                  isc_timermgr_t *timermgr, cache_cleaner_t *cleaner);
+                   isc_timermgr_t *timermgr, cache_cleaner_t *cleaner);
 
 static void
 cleaning_timer_action(isc_task_t *task, isc_event_t *event);
 
-static void
-incremental_cleaning_action(isc_task_t *task, isc_event_t *event);
-
 static void
 cleaner_shutdown_action(isc_task_t *task, isc_event_t *event);
 
+#ifdef LRU_DEBUG
 static void
-overmem_cleaning_action(isc_task_t *task, isc_event_t *event);
+timer_dump(isc_task_t *task, isc_event_t *event);
+#endif
 
+#if 0 /* This is no longer needed.  When LRU_TEST is cleaned up,
+       * this should be as well.  XXXMLG */
 /*%
  * Work out how many nodes can be cleaned in the time between two
  * requests to the nameserver.  Smooth the resulting number and use
@@ -165,386 +164,378 @@ overmem_cleaning_action(isc_task_t *task, isc_event_t *event);
  */
 static void
 adjust_increment(cache_cleaner_t *cleaner, unsigned int remaining,
-                isc_time_t *start)
+                 isc_time_t *start)
 {
-       isc_time_t end;
-       isc_uint64_t usecs;
-       isc_uint64_t new;
-       unsigned int pps = dns_pps;
-       unsigned int interval;
-       unsigned int names;
-       
-       /*
-        * Tune for minumum of 100 packets per second (pps).
-        */
-       if (pps < 100)
-               pps = 100;
-
-       isc_time_now(&end);
-
-       interval = 1000000 / pps; /* Interval between packets in usecs. */
-       if (interval == 0)
-               interval = 1;
-
-       INSIST(cleaner->increment >= remaining);
-       names = cleaner->increment - remaining;
-       usecs = isc_time_microdiff(&end, start);
-
-       isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_CACHE,
-                     ISC_LOG_DEBUG(1), "adjust_increment interval=%u "
-                     "names=%u usec=%" ISC_PLATFORM_QUADFORMAT "u",
-                     interval, names, usecs);
-       
-       if (usecs == 0) {
-               /*
-                * If we cleaned all the nodes in unmeasurable time
-                * double the number of nodes to be cleaned next time.
-                */
-               if (names == cleaner->increment) {
-                       cleaner->increment *= 2;
-                       if (cleaner->increment > DNS_CACHE_CLEANERINCREMENT)
-                               cleaner->increment = DNS_CACHE_CLEANERINCREMENT;
-                       isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
-                                     DNS_LOGMODULE_CACHE, ISC_LOG_DEBUG(1),
-                                     "%p:new cleaner->increment = %u\n",
-                                     cleaner, cleaner->increment);
-               }
-               return;
-       }
-
-       new = (names * interval);
-       new /= (usecs * 2);
-       if (new == 0)
-               new = 1;
-
-       /* Smooth */
-       new = (new + cleaner->increment * 7) / 8;
-
-       if (new > DNS_CACHE_CLEANERINCREMENT)
-               new = DNS_CACHE_CLEANERINCREMENT;
-
-       cleaner->increment = (unsigned int)new;
-
-       isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_CACHE,
-                     ISC_LOG_DEBUG(1), "%p:new cleaner->increment = %u\n",
-                     cleaner, cleaner->increment);
+        isc_time_t end;
+        isc_uint64_t usecs;
+        isc_uint64_t new;
+        unsigned int pps = dns_pps;
+        unsigned int interval;
+        unsigned int names;
+
+        /*
+         * Tune for minumum of 100 packets per second (pps).
+         */
+        if (pps < 100)
+                pps = 100;
+
+        isc_time_now(&end);
+
+        interval = 1000000 / pps; /* Interval between packets in usecs. */
+        if (interval == 0)
+                interval = 1;
+
+        INSIST(cleaner->increment >= remaining);
+        names = cleaner->increment - remaining;
+        usecs = isc_time_microdiff(&end, start);
+
+        isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_CACHE,
+                      ISC_LOG_DEBUG(1), "adjust_increment interval=%u "
+                      "names=%u usec=%" ISC_PLATFORM_QUADFORMAT "u",
+                      interval, names, usecs);
+
+        if (usecs == 0) {
+                /*
+                 * If we cleaned all the nodes in unmeasurable time
+                 * double the number of nodes to be cleaned next time.
+                 */
+                if (names == cleaner->increment) {
+                        cleaner->increment *= 2;
+                        if (cleaner->increment > DNS_CACHE_CLEANERINCREMENT)
+                                cleaner->increment = DNS_CACHE_CLEANERINCREMENT;
+                        isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+                                      DNS_LOGMODULE_CACHE, ISC_LOG_DEBUG(1),
+                                      "%p:new cleaner->increment = %u\n",
+                                      cleaner, cleaner->increment);
+                }
+                return;
+        }
+
+        new = (names * interval);
+        new /= (usecs * 2);
+        if (new == 0)
+                new = 1;
+
+        /* Smooth */
+        new = (new + cleaner->increment * 7) / 8;
+
+        if (new > DNS_CACHE_CLEANERINCREMENT)
+                new = DNS_CACHE_CLEANERINCREMENT;
+
+        cleaner->increment = (unsigned int)new;
+
+        isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_CACHE,
+                      ISC_LOG_DEBUG(1), "%p:new cleaner->increment = %u\n",
+                      cleaner, cleaner->increment);
 }
+#endif
 
 static inline isc_result_t
 cache_create_db(dns_cache_t *cache, dns_db_t **db) {
-       return (dns_db_create(cache->mctx, cache->db_type, dns_rootname,
-                             dns_dbtype_cache, cache->rdclass,
-                             cache->db_argc, cache->db_argv, db));
+        return (dns_db_create(cache->mctx, cache->db_type, dns_rootname,
+                              dns_dbtype_cache, cache->rdclass,
+                              cache->db_argc, cache->db_argv, db));
 }
 
 isc_result_t
 dns_cache_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
-                isc_timermgr_t *timermgr, dns_rdataclass_t rdclass,
-                const char *db_type, unsigned int db_argc, char **db_argv,
-                dns_cache_t **cachep)
+                 isc_timermgr_t *timermgr, dns_rdataclass_t rdclass,
+                 const char *db_type, unsigned int db_argc, char **db_argv,
+                 dns_cache_t **cachep)
 {
-       isc_result_t result;
-       dns_cache_t *cache;
-       int i;
-
-       REQUIRE(cachep != NULL);
-       REQUIRE(*cachep == NULL);
-       REQUIRE(mctx != NULL);
-
-       cache = isc_mem_get(mctx, sizeof(*cache));
-       if (cache == NULL)
-               return (ISC_R_NOMEMORY);
-
-       cache->mctx = NULL;
-       isc_mem_attach(mctx, &cache->mctx);
-
-       result = isc_mutex_init(&cache->lock);
-       if (result != ISC_R_SUCCESS)
-               goto cleanup_mem;
-
-       result = isc_mutex_init(&cache->filelock);
-       if (result != ISC_R_SUCCESS)
-               goto cleanup_lock;
-
-       cache->references = 1;
-       cache->live_tasks = 0;
-       cache->rdclass = rdclass;
-
-       cache->db_type = isc_mem_strdup(mctx, db_type);
-       if (cache->db_type == NULL) {
-               result = ISC_R_NOMEMORY;
-               goto cleanup_filelock;
-       }
-
-       cache->db_argc = db_argc;
-       if (cache->db_argc == 0)
-               cache->db_argv = NULL;
-       else {
-               cache->db_argv = isc_mem_get(mctx,
-                                            cache->db_argc * sizeof(char *));
-               if (cache->db_argv == NULL) {
-                       result = ISC_R_NOMEMORY;
-                       goto cleanup_dbtype;
-               }
-               for (i = 0; i < cache->db_argc; i++)
-                       cache->db_argv[i] = NULL;
-               for (i = 0; i < cache->db_argc; i++) {
-                       cache->db_argv[i] = isc_mem_strdup(mctx, db_argv[i]);
-                       if (cache->db_argv[i] == NULL) {
-                               result = ISC_R_NOMEMORY;
-                               goto cleanup_dbargv;
-                       }
-               }
-       }
-
-       cache->db = NULL;
-       result = cache_create_db(cache, &cache->db);
-       if (result != ISC_R_SUCCESS)
-               goto cleanup_dbargv;
-
-       cache->filename = NULL;
-
-       cache->magic = CACHE_MAGIC;
-
-       result = cache_cleaner_init(cache, taskmgr, timermgr, &cache->cleaner);
-       if (result != ISC_R_SUCCESS)
-               goto cleanup_db;
-
-       *cachep = cache;
-       return (ISC_R_SUCCESS);
+        isc_result_t result;
+        dns_cache_t *cache;
+        int i;
+
+        REQUIRE(cachep != NULL);
+        REQUIRE(*cachep == NULL);
+        REQUIRE(mctx != NULL);
+
+        cache = isc_mem_get(mctx, sizeof(*cache));
+        if (cache == NULL)
+                return (ISC_R_NOMEMORY);
+
+        cache->mctx = NULL;
+        isc_mem_attach(mctx, &cache->mctx);
+
+        result = isc_mutex_init(&cache->lock);
+        if (result != ISC_R_SUCCESS)
+                goto cleanup_mem;
+
+        result = isc_mutex_init(&cache->filelock);
+        if (result != ISC_R_SUCCESS)
+                goto cleanup_lock;
+
+        cache->references = 1;
+        cache->live_tasks = 0;
+        cache->rdclass = rdclass;
+
+        cache->db_type = isc_mem_strdup(mctx, db_type);
+        if (cache->db_type == NULL) {
+                result = ISC_R_NOMEMORY;
+                goto cleanup_filelock;
+        }
+
+        cache->db_argc = db_argc;
+        if (cache->db_argc == 0)
+                cache->db_argv = NULL;
+        else {
+                cache->db_argv = isc_mem_get(mctx,
+                                             cache->db_argc * sizeof(char *));
+                if (cache->db_argv == NULL) {
+                        result = ISC_R_NOMEMORY;
+                        goto cleanup_dbtype;
+                }
+                for (i = 0; i < cache->db_argc; i++)
+                        cache->db_argv[i] = NULL;
+                for (i = 0; i < cache->db_argc; i++) {
+                        cache->db_argv[i] = isc_mem_strdup(mctx, db_argv[i]);
+                        if (cache->db_argv[i] == NULL) {
+                                result = ISC_R_NOMEMORY;
+                                goto cleanup_dbargv;
+                        }
+                }
+        }
+
+        cache->db = NULL;
+        result = cache_create_db(cache, &cache->db);
+        if (result != ISC_R_SUCCESS)
+                goto cleanup_dbargv;
+
+        cache->filename = NULL;
+
+        cache->magic = CACHE_MAGIC;
+
+        result = cache_cleaner_init(cache, taskmgr, timermgr, &cache->cleaner);
+        if (result != ISC_R_SUCCESS)
+                goto cleanup_db;
+
+        *cachep = cache;
+        return (ISC_R_SUCCESS);
 
  cleanup_db:
-       dns_db_detach(&cache->db);
+        dns_db_detach(&cache->db);
  cleanup_dbargv:
-       for (i = 0; i < cache->db_argc; i++)
-               if (cache->db_argv[i] != NULL)
-                       isc_mem_free(mctx, cache->db_argv[i]);
-       if (cache->db_argv != NULL)
-               isc_mem_put(mctx, cache->db_argv,
-                           cache->db_argc * sizeof(char *));
+        for (i = 0; i < cache->db_argc; i++)
+                if (cache->db_argv[i] != NULL)
+                        isc_mem_free(mctx, cache->db_argv[i]);
+        if (cache->db_argv != NULL)
+                isc_mem_put(mctx, cache->db_argv,
+                            cache->db_argc * sizeof(char *));
  cleanup_dbtype:
-       isc_mem_free(mctx, cache->db_type);
+        isc_mem_free(mctx, cache->db_type);
  cleanup_filelock:
-       DESTROYLOCK(&cache->filelock);
+        DESTROYLOCK(&cache->filelock);
  cleanup_lock:
-       DESTROYLOCK(&cache->lock);
+        DESTROYLOCK(&cache->lock);
  cleanup_mem:
-       isc_mem_put(mctx, cache, sizeof(*cache));
-       isc_mem_detach(&mctx);
-       return (result);
+        isc_mem_put(mctx, cache, sizeof(*cache));
+        isc_mem_detach(&mctx);
+        return (result);
 }
 
 static void
 cache_free(dns_cache_t *cache) {
-       isc_mem_t *mctx;
-       int i;
-
-       REQUIRE(VALID_CACHE(cache));
-       REQUIRE(cache->references == 0);
-
-       isc_mem_setwater(cache->mctx, NULL, NULL, 0, 0);
-
-       if (cache->cleaner.task != NULL)
-               isc_task_detach(&cache->cleaner.task);
+        isc_mem_t *mctx;
+        int i;
 
-       if (cache->cleaner.overmem_event != NULL)
-               isc_event_free(&cache->cleaner.overmem_event);
+        REQUIRE(VALID_CACHE(cache));
+        REQUIRE(cache->references == 0);
 
-       if (cache->cleaner.resched_event != NULL)
-               isc_event_free(&cache->cleaner.resched_event);
+        isc_mem_setwater(cache->mctx, NULL, NULL, 0, 0);
 
-       if (cache->cleaner.iterator != NULL)
-               dns_dbiterator_destroy(&cache->cleaner.iterator);
+        if (cache->cleaner.task != NULL)
+                isc_task_detach(&cache->cleaner.task);
 
-       DESTROYLOCK(&cache->cleaner.lock);
+        DESTROYLOCK(&cache->cleaner.lock);
 
-       if (cache->filename) {
-               isc_mem_free(cache->mctx, cache->filename);
-               cache->filename = NULL;
-       }
+        if (cache->filename) {
+                isc_mem_free(cache->mctx, cache->filename);
+                cache->filename = NULL;
+        }
 
-       if (cache->db != NULL)
-               dns_db_detach(&cache->db);
+        if (cache->db != NULL)
+                dns_db_detach(&cache->db);
 
-       if (cache->db_argv != NULL) {
-               for (i = 0; i < cache->db_argc; i++)
-                       if (cache->db_argv[i] != NULL)
-                               isc_mem_free(cache->mctx, cache->db_argv[i]);
-               isc_mem_put(cache->mctx, cache->db_argv,
-                           cache->db_argc * sizeof(char *));
-       }
+        if (cache->db_argv != NULL) {
+                for (i = 0; i < cache->db_argc; i++)
+                        if (cache->db_argv[i] != NULL)
+                                isc_mem_free(cache->mctx, cache->db_argv[i]);
+                isc_mem_put(cache->mctx, cache->db_argv,
+                            cache->db_argc * sizeof(char *));
+        }
 
-       if (cache->db_type != NULL)
-               isc_mem_free(cache->mctx, cache->db_type);
+        if (cache->db_type != NULL)
+                isc_mem_free(cache->mctx, cache->db_type);
 
-       DESTROYLOCK(&cache->lock);
-       DESTROYLOCK(&cache->filelock);
-       cache->magic = 0;
-       mctx = cache->mctx;
-       isc_mem_put(cache->mctx, cache, sizeof(*cache));
-       isc_mem_detach(&mctx);
+        DESTROYLOCK(&cache->lock);
+        DESTROYLOCK(&cache->filelock);
+        cache->magic = 0;
+        mctx = cache->mctx;
+        isc_mem_put(cache->mctx, cache, sizeof(*cache));
+        isc_mem_detach(&mctx);
 }
 
 
 void
 dns_cache_attach(dns_cache_t *cache, dns_cache_t **targetp) {
 
-       REQUIRE(VALID_CACHE(cache));
-       REQUIRE(targetp != NULL && *targetp == NULL);
+        REQUIRE(VALID_CACHE(cache));
+        REQUIRE(targetp != NULL && *targetp == NULL);
 
-       LOCK(&cache->lock);
-       cache->references++;
-       UNLOCK(&cache->lock);
+        LOCK(&cache->lock);
+        cache->references++;
+        UNLOCK(&cache->lock);
 
-       *targetp = cache;
+        *targetp = cache;
 }
 
 void
 dns_cache_detach(dns_cache_t **cachep) {
-       dns_cache_t *cache;
-       isc_boolean_t free_cache = ISC_FALSE;
-
-       REQUIRE(cachep != NULL);
-       cache = *cachep;
-       REQUIRE(VALID_CACHE(cache));
-
-       LOCK(&cache->lock);
-       REQUIRE(cache->references > 0);
-       cache->references--;
-       if (cache->references == 0) {
-               cache->cleaner.overmem = ISC_FALSE;
-               free_cache = ISC_TRUE;
-       }
-
-       *cachep = NULL;
-
-       if (free_cache) {
-               /*
-                * When the cache is shut down, dump it to a file if one is
-                * specified.
-                */
-               isc_result_t result = dns_cache_dump(cache);
-               if (result != ISC_R_SUCCESS)
-                       isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
-                                     DNS_LOGMODULE_CACHE, ISC_LOG_WARNING,
-                                     "error dumping cache: %s ",
-                                     isc_result_totext(result));
-
-               /*
-                * If the cleaner task exists, let it free the cache.
-                */
-               if (cache->live_tasks > 0) {
-                       isc_task_shutdown(cache->cleaner.task);
-                       free_cache = ISC_FALSE;
-               }
-       }
-
-       UNLOCK(&cache->lock);
-
-       if (free_cache)
-               cache_free(cache);
+        dns_cache_t *cache;
+        isc_boolean_t free_cache = ISC_FALSE;
+
+        REQUIRE(cachep != NULL);
+        cache = *cachep;
+        REQUIRE(VALID_CACHE(cache));
+
+        LOCK(&cache->lock);
+        REQUIRE(cache->references > 0);
+        cache->references--;
+        if (cache->references == 0) {
+                cache->cleaner.overmem = ISC_FALSE;
+                free_cache = ISC_TRUE;
+        }
+
+        *cachep = NULL;
+
+        if (free_cache) {
+                /*
+                 * When the cache is shut down, dump it to a file if one is
+                 * specified.
+                 */
+                isc_result_t result = dns_cache_dump(cache);
+                if (result != ISC_R_SUCCESS)
+                        isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+                                      DNS_LOGMODULE_CACHE, ISC_LOG_WARNING,
+                                      "error dumping cache: %s ",
+                                      isc_result_totext(result));
+
+                /*
+                 * If the cleaner task exists, let it free the cache.
+                 */
+                if (cache->live_tasks > 0) {
+                        isc_task_shutdown(cache->cleaner.task);
+                        free_cache = ISC_FALSE;
+                }
+        }
+
+        UNLOCK(&cache->lock);
+
+        if (free_cache)
+                cache_free(cache);
 }
 
 void
 dns_cache_attachdb(dns_cache_t *cache, dns_db_t **dbp) {
-       REQUIRE(VALID_CACHE(cache));
-       REQUIRE(dbp != NULL && *dbp == NULL);
-       REQUIRE(cache->db != NULL);
+        REQUIRE(VALID_CACHE(cache));
+        REQUIRE(dbp != NULL && *dbp == NULL);
+        REQUIRE(cache->db != NULL);
 
-       LOCK(&cache->lock);
-       dns_db_attach(cache->db, dbp);
-       UNLOCK(&cache->lock);
+        LOCK(&cache->lock);
+        dns_db_attach(cache->db, dbp);
+        UNLOCK(&cache->lock);
 
 }
 
 isc_result_t
 dns_cache_setfilename(dns_cache_t *cache, const char *filename) {
-       char *newname;
+        char *newname;
 
-       REQUIRE(VALID_CACHE(cache));
-       REQUIRE(filename != NULL);
+        REQUIRE(VALID_CACHE(cache));
+        REQUIRE(filename != NULL);
 
-       newname = isc_mem_strdup(cache->mctx, filename);
-       if (newname == NULL)
-               return (ISC_R_NOMEMORY);
+        newname = isc_mem_strdup(cache->mctx, filename);
+        if (newname == NULL)
+                return (ISC_R_NOMEMORY);
 
-       LOCK(&cache->filelock);
-       if (cache->filename)
-               isc_mem_free(cache->mctx, cache->filename);
-       cache->filename = newname;
-       UNLOCK(&cache->filelock);
+        LOCK(&cache->filelock);
+        if (cache->filename)
+                isc_mem_free(cache->mctx, cache->filename);
+        cache->filename = newname;
+        UNLOCK(&cache->filelock);
 
-       return (ISC_R_SUCCESS);
+        return (ISC_R_SUCCESS);
 }
 
 isc_result_t
 dns_cache_load(dns_cache_t *cache) {
-       isc_result_t result;
+        isc_result_t result;
 
-       REQUIRE(VALID_CACHE(cache));
+        REQUIRE(VALID_CACHE(cache));
 
-       if (cache->filename == NULL)
-               return (ISC_R_SUCCESS);
+        if (cache->filename == NULL)
+                return (ISC_R_SUCCESS);
 
-       LOCK(&cache->filelock);
-       result = dns_db_load(cache->db, cache->filename);
-       UNLOCK(&cache->filelock);
+        LOCK(&cache->filelock);
+        result = dns_db_load(cache->db, cache->filename);
+        UNLOCK(&cache->filelock);
 
-       return (result);
+        return (result);
 }
 
 isc_result_t
 dns_cache_dump(dns_cache_t *cache) {
-       isc_result_t result;
+        isc_result_t result;
 
-       REQUIRE(VALID_CACHE(cache));
+        REQUIRE(VALID_CACHE(cache));
 
-       if (cache->filename == NULL)
-               return (ISC_R_SUCCESS);
+        if (cache->filename == NULL)
+                return (ISC_R_SUCCESS);
 
-       LOCK(&cache->filelock);
-       result = dns_master_dump(cache->mctx, cache->db, NULL,
-                                &dns_master_style_cache, cache->filename);
-       UNLOCK(&cache->filelock);
+        LOCK(&cache->filelock);
+        result = dns_master_dump(cache->mctx, cache->db, NULL,
+                                 &dns_master_style_cache, cache->filename);
+        UNLOCK(&cache->filelock);
 
-       return (result);
+        return (result);
 }
 
 void
 dns_cache_setcleaninginterval(dns_cache_t *cache, unsigned int t) {
-       isc_interval_t interval;
-       isc_result_t result;
-
-       LOCK(&cache->lock);
-
-       /*
-        * It may be the case that the cache has already shut down.
-        * If so, it has no timer.
-        */
-       if (cache->cleaner.cleaning_timer == NULL)
-               goto unlock;
-
-       cache->cleaner.cleaning_interval = t;
-
-       if (t == 0) {
-               result = isc_timer_reset(cache->cleaner.cleaning_timer,
-                                        isc_timertype_inactive,
-                                        NULL, NULL, ISC_TRUE);
-       } else {
-               isc_interval_set(&interval, cache->cleaner.cleaning_interval,
-                                0);
-               result = isc_timer_reset(cache->cleaner.cleaning_timer,
-                                        isc_timertype_ticker,
-                                        NULL, &interval, ISC_FALSE);
-       }
-       if (result != ISC_R_SUCCESS)    
-               isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
-                             DNS_LOGMODULE_CACHE, ISC_LOG_WARNING,
-                             "could not set cache cleaning interval: %s",
-                             isc_result_totext(result));
+        isc_interval_t interval;
+        isc_result_t result;
+
+        LOCK(&cache->lock);
+
+        /*
+         * It may be the case that the cache has already shut down.
+         * If so, it has no timer.
+         */
+        if (cache->cleaner.cleaning_timer == NULL)
+                goto unlock;
+
+        cache->cleaner.cleaning_interval = t;
+
+        if (t == 0) {
+                result = isc_timer_reset(cache->cleaner.cleaning_timer,
+                                         isc_timertype_inactive,
+                                         NULL, NULL, ISC_TRUE);
+        } else {
+                isc_interval_set(&interval, cache->cleaner.cleaning_interval,
+                                 0);
+                result = isc_timer_reset(cache->cleaner.cleaning_timer,
+                                         isc_timertype_ticker,
+                                         NULL, &interval, ISC_FALSE);
+        }
+        if (result != ISC_R_SUCCESS)
+                isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+                              DNS_LOGMODULE_CACHE, ISC_LOG_WARNING,
+                              "could not set cache cleaning interval: %s",
+                              isc_result_totext(result));
 
  unlock:
-       UNLOCK(&cache->lock);
+        UNLOCK(&cache->lock);
 }
 
 /*
@@ -554,181 +545,86 @@ dns_cache_setcleaninginterval(dns_cache_t *cache, unsigned int t) {
 
 static isc_result_t
 cache_cleaner_init(dns_cache_t *cache, isc_taskmgr_t *taskmgr,
-                  isc_timermgr_t *timermgr, cache_cleaner_t *cleaner)
+                   isc_timermgr_t *timermgr, cache_cleaner_t *cleaner)
 {
-       isc_result_t result;
-
-       result = isc_mutex_init(&cleaner->lock);
-       if (result != ISC_R_SUCCESS)
-               goto fail;
-
-       cleaner->increment = DNS_CACHE_CLEANERINCREMENT;
-       cleaner->state = cleaner_s_idle;
-       cleaner->cache = cache;
-       cleaner->iterator = NULL;
-       cleaner->overmem = ISC_FALSE;
-       cleaner->replaceiterator = ISC_FALSE;
-
-       cleaner->task = NULL;
-       cleaner->cleaning_timer = NULL;
-       cleaner->resched_event = NULL;
-       cleaner->overmem_event = NULL;
-
-       result = dns_db_createiterator(cleaner->cache->db, ISC_FALSE,
-                                      &cleaner->iterator);
-       if (result != ISC_R_SUCCESS)
-               goto cleanup;
-
-       if (taskmgr != NULL && timermgr != NULL) {
-               result = isc_task_create(taskmgr, 1, &cleaner->task);
-               if (result != ISC_R_SUCCESS) {
-                       UNEXPECTED_ERROR(__FILE__, __LINE__,
-                                        "isc_task_create() failed: %s",
-                                        dns_result_totext(result));
-                       result = ISC_R_UNEXPECTED;
-                       goto cleanup;
-               }
-               cleaner->cache->live_tasks++;
-               isc_task_setname(cleaner->task, "cachecleaner", cleaner);
-
-               result = isc_task_onshutdown(cleaner->task,
-                                            cleaner_shutdown_action, cache);
-               if (result != ISC_R_SUCCESS) {
-                       UNEXPECTED_ERROR(__FILE__, __LINE__,
-                                        "cache cleaner: "
-                                        "isc_task_onshutdown() failed: %s",
-                                        dns_result_totext(result));
-                       goto cleanup;
-               }
-
-               cleaner->cleaning_interval = 0; /* Initially turned off. */
-               result = isc_timer_create(timermgr, isc_timertype_inactive,
-                                          NULL, NULL,
-                                          cleaner->task,
-                                          cleaning_timer_action, cleaner,
-                                          &cleaner->cleaning_timer);
-               if (result != ISC_R_SUCCESS) {
-                       UNEXPECTED_ERROR(__FILE__, __LINE__,
-                                        "isc_timer_create() failed: %s",
-                                        dns_result_totext(result));
-                       result = ISC_R_UNEXPECTED;
-                       goto cleanup;
-               }
-
-               cleaner->resched_event =
-                       isc_event_allocate(cache->mctx, cleaner,
-                                          DNS_EVENT_CACHECLEAN,
-                                          incremental_cleaning_action,
-                                          cleaner, sizeof(isc_event_t));
-               if (cleaner->resched_event == NULL) {
-                       result = ISC_R_NOMEMORY;
-                       goto cleanup;
-               }
-               
-               cleaner->overmem_event =
-                       isc_event_allocate(cache->mctx, cleaner,
-                                          DNS_EVENT_CACHEOVERMEM,
-                                          overmem_cleaning_action,
-                                          cleaner, sizeof(isc_event_t));
-               if (cleaner->overmem_event == NULL) {
-                       result = ISC_R_NOMEMORY;
-                       goto cleanup;
-               }
-       }
-
-       return (ISC_R_SUCCESS);
+        isc_result_t result;
+#ifdef LRU_DEBUG
+        isc_interval_t interval;
+#endif
+
+        result = isc_mutex_init(&cleaner->lock);
+        if (result != ISC_R_SUCCESS)
+                goto fail;
+
+        cleaner->increment = DNS_CACHE_CLEANERINCREMENT;
+        cleaner->state = cleaner_s_idle;
+        cleaner->cache = cache;
+        cleaner->overmem = ISC_FALSE;
+
+        cleaner->task = NULL;
+        cleaner->cleaning_timer = NULL;
+
+        if (taskmgr != NULL && timermgr != NULL) {
+                result = isc_task_create(taskmgr, 1, &cleaner->task);
+                if (result != ISC_R_SUCCESS) {
+                        UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                         "isc_task_create() failed: %s",
+                                         dns_result_totext(result));
+                        result = ISC_R_UNEXPECTED;
+                        goto cleanup;
+                }
+                cleaner->cache->live_tasks++;
+                isc_task_setname(cleaner->task, "cachecleaner", cleaner);
+
+                result = isc_task_onshutdown(cleaner->task,
+                                             cleaner_shutdown_action, cache);
+                if (result != ISC_R_SUCCESS) {
+                        UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                         "cache cleaner: "
+                                         "isc_task_onshutdown() failed: %s",
+                                         dns_result_totext(result));
+                        goto cleanup;
+                }
+
+                cleaner->cleaning_interval = 0; /* Initially turned off. */
+                result = isc_timer_create(timermgr, isc_timertype_inactive,
+                                           NULL, NULL,
+                                           cleaner->task,
+                                           cleaning_timer_action, cleaner,
+                                           &cleaner->cleaning_timer);
+                if (result != ISC_R_SUCCESS) {
+                        UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                         "isc_timer_create() failed: %s",
+                                         dns_result_totext(result));
+                        result = ISC_R_UNEXPECTED;
+                        goto cleanup;
+                }
+
+#ifdef LRU_DEBUG
+                interval.seconds = DUMP_INTERVAL;
+                interval.nanoseconds = 0;
+                RUNTIME_CHECK(isc_time_nowplusinterval(&cache->dump_time,
+                                                       &interval) ==
+                              ISC_R_SUCCESS);
+                cache->dump_timer = NULL;
+                result = isc_timer_create(timermgr, isc_timertype_once,
+                                          &cache->dump_time, NULL,
+                                          cleaner->task, timer_dump,
+                                          cache, &cache->dump_timer);
+                RUNTIME_CHECK(result == ISC_R_SUCCESS); /* for brevity */
+#endif
+        }
+
+        return (ISC_R_SUCCESS);
 
  cleanup:
-       if (cleaner->overmem_event != NULL)
-               isc_event_free(&cleaner->overmem_event);
-       if (cleaner->resched_event != NULL)
-               isc_event_free(&cleaner->resched_event);
-       if (cleaner->cleaning_timer != NULL)
-               isc_timer_detach(&cleaner->cleaning_timer);
-       if (cleaner->task != NULL)
-               isc_task_detach(&cleaner->task);
-       if (cleaner->iterator != NULL)
-               dns_dbiterator_destroy(&cleaner->iterator);
-       DESTROYLOCK(&cleaner->lock);
+        if (cleaner->cleaning_timer != NULL)
+                isc_timer_detach(&cleaner->cleaning_timer);
+        if (cleaner->task != NULL)
+                isc_task_detach(&cleaner->task);
+        DESTROYLOCK(&cleaner->lock);
  fail:
-       return (result);
-}
-
-static void
-begin_cleaning(cache_cleaner_t *cleaner) {
-       isc_result_t result = ISC_R_SUCCESS;
-
-       REQUIRE(CLEANER_IDLE(cleaner));
-
-       /*
-        * Create an iterator, if it does not already exist, and
-         * position it at the beginning of the cache.
-        */
-       if (cleaner->iterator == NULL)
-               result = dns_db_createiterator(cleaner->cache->db, ISC_FALSE,
-                                              &cleaner->iterator);
-       if (result != ISC_R_SUCCESS)
-               isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
-                             DNS_LOGMODULE_CACHE, ISC_LOG_WARNING,
-                             "cache cleaner could not create "
-                             "iterator: %s", isc_result_totext(result));
-       else {
-               dns_dbiterator_setcleanmode(cleaner->iterator, ISC_TRUE);
-               result = dns_dbiterator_first(cleaner->iterator);
-       }
-       if (result != ISC_R_SUCCESS) {
-               /*
-                * If the result is ISC_R_NOMORE, the database is empty,
-                * so there is nothing to be cleaned.
-                */
-               if (result != ISC_R_NOMORE && cleaner->iterator != NULL) {
-                       UNEXPECTED_ERROR(__FILE__, __LINE__,
-                                        "cache cleaner: "
-                                        "dns_dbiterator_first() failed: %s",
-                                        dns_result_totext(result));
-                       dns_dbiterator_destroy(&cleaner->iterator);
-               } else if (cleaner->iterator != NULL) {
-                       result = dns_dbiterator_pause(cleaner->iterator);
-                       RUNTIME_CHECK(result == ISC_R_SUCCESS);
-               }
-       } else {
-               /*
-                * Pause the iterator to free its lock.
-                */
-               result = dns_dbiterator_pause(cleaner->iterator);
-               RUNTIME_CHECK(result == ISC_R_SUCCESS);
-
-               isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
-                             DNS_LOGMODULE_CACHE, ISC_LOG_DEBUG(1),
-                             "begin cache cleaning, mem inuse %lu",
-                           (unsigned long)isc_mem_inuse(cleaner->cache->mctx));
-               cleaner->state = cleaner_s_busy;
-               isc_task_send(cleaner->task, &cleaner->resched_event);
-       }
-
-       return;
-}
-
-static void
-end_cleaning(cache_cleaner_t *cleaner, isc_event_t *event) {
-       isc_result_t result;
-
-       REQUIRE(CLEANER_BUSY(cleaner));
-       REQUIRE(event != NULL);
-
-       result = dns_dbiterator_pause(cleaner->iterator);
-       if (result != ISC_R_SUCCESS)
-               dns_dbiterator_destroy(&cleaner->iterator);
-
-       dns_cache_setcleaninginterval(cleaner->cache,
-                                     cleaner->cleaning_interval);
-
-       isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_CACHE,
-                     ISC_LOG_DEBUG(1), "end cache cleaning, mem inuse %lu",
-                     (unsigned long)isc_mem_inuse(cleaner->cache->mctx));
-
-       cleaner->state = cleaner_s_idle;
-       cleaner->resched_event = event;
+        return (result);
 }
 
 /*
@@ -736,187 +632,18 @@ end_cleaning(cache_cleaner_t *cleaner, isc_event_t *event) {
  */
 static void
 cleaning_timer_action(isc_task_t *task, isc_event_t *event) {
-       cache_cleaner_t *cleaner = event->ev_arg;
-
-       UNUSED(task);
+        cache_cleaner_t *cleaner = event->ev_arg;
 
-       INSIST(task == cleaner->task);
-       INSIST(event->ev_type == ISC_TIMEREVENT_TICK);
+        UNUSED(task);
 
-       isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_CACHE,
-                     ISC_LOG_DEBUG(1), "cache cleaning timer fired, "
-                     "cleaner state = %d", cleaner->state);
+        INSIST(task == cleaner->task);
+        INSIST(event->ev_type == ISC_TIMEREVENT_TICK);
 
-       if (cleaner->state == cleaner_s_idle)
-               begin_cleaning(cleaner);
+        isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_CACHE,
+                      ISC_LOG_DEBUG(1), "cache cleaning timer fired, "
+                      "cleaner state = %d", cleaner->state);
 
-       isc_event_free(&event);
-}
-
-/*
- * This is called when the cache either surpasses its upper limit
- * or shrinks beyond its lower limit.
- */
-static void
-overmem_cleaning_action(isc_task_t *task, isc_event_t *event) {
-       cache_cleaner_t *cleaner = event->ev_arg;
-       isc_boolean_t want_cleaning = ISC_FALSE;
-       
-       UNUSED(task);
-
-       INSIST(task == cleaner->task);
-       INSIST(event->ev_type == DNS_EVENT_CACHEOVERMEM);
-       INSIST(cleaner->overmem_event == NULL);
-
-       isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_CACHE,
-                     ISC_LOG_DEBUG(1), "overmem_cleaning_action called, "
-                     "overmem = %d, state = %d", cleaner->overmem,
-                     cleaner->state);
-
-       LOCK(&cleaner->lock);
-
-       if (cleaner->overmem) {
-               if (cleaner->state == cleaner_s_idle)
-                       want_cleaning = ISC_TRUE;
-       } else {
-               if (cleaner->state == cleaner_s_busy)
-                       /*
-                        * end_cleaning() can't be called here because
-                        * then both cleaner->overmem_event and
-                        * cleaner->resched_event will point to this
-                        * event.  Set the state to done, and then
-                        * when the incremental_cleaning_action() event
-                        * is posted, it will handle the end_cleaning.
-                        */
-                       cleaner->state = cleaner_s_done;
-       }
-
-       cleaner->overmem_event = event;
-
-       UNLOCK(&cleaner->lock);
-
-       if (want_cleaning)
-               begin_cleaning(cleaner);
-}
-
-/*
- * Do incremental cleaning.
- */
-static void
-incremental_cleaning_action(isc_task_t *task, isc_event_t *event) {
-       cache_cleaner_t *cleaner = event->ev_arg;
-       isc_result_t result;
-       unsigned int n_names;
-       isc_time_t start;
-
-       UNUSED(task);
-
-       INSIST(task == cleaner->task);
-       INSIST(event->ev_type == DNS_EVENT_CACHECLEAN);
-
-       if (cleaner->state == cleaner_s_done) {
-               cleaner->state = cleaner_s_busy;
-               end_cleaning(cleaner, event);
-               LOCK(&cleaner->cache->lock);
-               LOCK(&cleaner->lock);
-               if (cleaner->replaceiterator) {
-                       dns_dbiterator_destroy(&cleaner->iterator);
-                       (void) dns_db_createiterator(cleaner->cache->db,
-                                                    ISC_FALSE,
-                                                    &cleaner->iterator);
-                       cleaner->replaceiterator = ISC_FALSE;
-               }
-               UNLOCK(&cleaner->lock);
-               UNLOCK(&cleaner->cache->lock);
-               return;
-       }
-
-       INSIST(CLEANER_BUSY(cleaner));
-
-       n_names = cleaner->increment;
-
-       REQUIRE(DNS_DBITERATOR_VALID(cleaner->iterator));
-
-       isc_time_now(&start);
-       while (n_names-- > 0) {
-               dns_dbnode_t *node = NULL;
-
-               result = dns_dbiterator_current(cleaner->iterator, &node,
-                                               NULL);
-               if (result != ISC_R_SUCCESS) {
-                       UNEXPECTED_ERROR(__FILE__, __LINE__,
-                                "cache cleaner: dns_dbiterator_current() "
-                                "failed: %s", dns_result_totext(result));
-
-                       adjust_increment(cleaner, n_names, &start);
-                       end_cleaning(cleaner, event);
-                       return;
-               }
-
-               /*
-                * The node was not needed, but was required by
-                * dns_dbiterator_current().  Give up its reference.
-                */
-               dns_db_detachnode(cleaner->cache->db, &node);
-
-               /*
-                * Step to the next node.
-                */
-               result = dns_dbiterator_next(cleaner->iterator);
-
-               if (result != ISC_R_SUCCESS) {
-                       /*
-                        * Either the end was reached (ISC_R_NOMORE) or
-                        * some error was signaled.  If the cache is still
-                        * overmem and no error was encountered,
-                        * keep trying to clean it, otherwise stop cleaning.
-                        */
-                       if (result != ISC_R_NOMORE)
-                               UNEXPECTED_ERROR(__FILE__, __LINE__,
-                                                "cache cleaner: "
-                                                "dns_dbiterator_next() "
-                                                "failed: %s",
-                                                dns_result_totext(result));
-                       else if (cleaner->overmem) {
-                               result = dns_dbiterator_first(cleaner->
-                                                             iterator);
-                               if (result == ISC_R_SUCCESS) {
-                                       isc_log_write(dns_lctx,
-                                                     DNS_LOGCATEGORY_DATABASE,
-                                                     DNS_LOGMODULE_CACHE,
-                                                     ISC_LOG_DEBUG(1),
-                                                     "cache cleaner: "
-                                                     "still overmem, "
-                                                     "reset and try again");
-                                       continue;
-                               }
-                       }
-
-                       adjust_increment(cleaner, n_names, &start);
-                       end_cleaning(cleaner, event);
-                       return;
-               }
-       }
-
-       adjust_increment(cleaner, 0U, &start);
-
-       /*
-        * We have successfully performed a cleaning increment but have
-        * not gone through the entire cache.  Free the iterator locks
-        * and reschedule another batch.  If it fails, just try to continue
-        * anyway.
-        */
-       result = dns_dbiterator_pause(cleaner->iterator);
-       RUNTIME_CHECK(result == ISC_R_SUCCESS);
-
-       isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_CACHE,
-                     ISC_LOG_DEBUG(1), "cache cleaner: checked %u nodes, "
-                     "mem inuse %lu, sleeping", cleaner->increment,
-                     (unsigned long)isc_mem_inuse(cleaner->cache->mctx));
-
-       isc_task_send(task, &event);
-       INSIST(CLEANER_BUSY(cleaner));
-       return;
+        isc_event_free(&event);
 }
 
 /*
@@ -924,108 +651,104 @@ incremental_cleaning_action(isc_task_t *task, isc_event_t *event) {
  */
 isc_result_t
 dns_cache_clean(dns_cache_t *cache, isc_stdtime_t now) {
-       isc_result_t result;
-       dns_dbiterator_t *iterator = NULL;
-
-       REQUIRE(VALID_CACHE(cache));
-
-       result = dns_db_createiterator(cache->db, ISC_FALSE, &iterator);
-       if (result != ISC_R_SUCCESS)
-               return result;
-
-       result = dns_dbiterator_first(iterator);
-
-       while (result == ISC_R_SUCCESS) {
-               dns_dbnode_t *node = NULL;
-               result = dns_dbiterator_current(iterator, &node,
-                                               (dns_name_t *)NULL);
-               if (result != ISC_R_SUCCESS)
-                       break;
-
-               /*
-                * Check TTLs, mark expired rdatasets stale.
-                */
-               result = dns_db_expirenode(cache->db, node, now);
-               if (result != ISC_R_SUCCESS) {
-                       UNEXPECTED_ERROR(__FILE__, __LINE__,
-                                        "cache cleaner: dns_db_expirenode() "
-                                        "failed: %s",
-                                        dns_result_totext(result));
-                       /*
-                        * Continue anyway.
-                        */
-               }
-
-               /*
-                * This is where the actual freeing takes place.
-                */
-               dns_db_detachnode(cache->db, &node);
-
-               result = dns_dbiterator_next(iterator);
-       }
-
-       dns_dbiterator_destroy(&iterator);
-
-       if (result == ISC_R_NOMORE)
-               result = ISC_R_SUCCESS;
-
-       return (result);
+        isc_result_t result;
+        dns_dbiterator_t *iterator = NULL;
+
+        REQUIRE(VALID_CACHE(cache));
+
+        result = dns_db_createiterator(cache->db, ISC_FALSE, &iterator);
+        if (result != ISC_R_SUCCESS)
+                return result;
+
+        result = dns_dbiterator_first(iterator);
+
+        while (result == ISC_R_SUCCESS) {
+                dns_dbnode_t *node = NULL;
+                result = dns_dbiterator_current(iterator, &node,
+                                                (dns_name_t *)NULL);
+                if (result != ISC_R_SUCCESS)
+                        break;
+
+                /*
+                 * Check TTLs, mark expired rdatasets stale.
+                 */
+                result = dns_db_expirenode(cache->db, node, now);
+                if (result != ISC_R_SUCCESS) {
+                        UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                         "cache cleaner: dns_db_expirenode() "
+                                         "failed: %s",
+                                         dns_result_totext(result));
+                        /*
+                         * Continue anyway.
+                         */
+                }
+
+                /*
+                 * This is where the actual freeing takes place.
+                 */
+                dns_db_detachnode(cache->db, &node);
+
+                result = dns_dbiterator_next(iterator);
+        }
+
+        dns_dbiterator_destroy(&iterator);
+
+        if (result == ISC_R_NOMORE)
+                result = ISC_R_SUCCESS;
+
+        return (result);
 }
 
 static void
 water(void *arg, int mark) {
-       dns_cache_t *cache = arg;
-       isc_boolean_t overmem = ISC_TF(mark == ISC_MEM_HIWATER);
+        dns_cache_t *cache = arg;
+        isc_boolean_t overmem = ISC_TF(mark == ISC_MEM_HIWATER);
 
-       REQUIRE(VALID_CACHE(cache));
+        REQUIRE(VALID_CACHE(cache));
 
-       LOCK(&cache->cleaner.lock);
-       
-       dns_db_overmem(cache->db, overmem);
-       cache->cleaner.overmem = overmem;
+        LOCK(&cache->cleaner.lock);
 
-       if (cache->cleaner.overmem_event != NULL)
-               isc_task_send(cache->cleaner.task,
-                             &cache->cleaner.overmem_event);
+        dns_db_overmem(cache->db, overmem);
+        cache->cleaner.overmem = overmem;
 
-       UNLOCK(&cache->cleaner.lock);
+        UNLOCK(&cache->cleaner.lock);
 }
 
 void
 dns_cache_setcachesize(dns_cache_t *cache, isc_uint32_t size) {
-       isc_uint32_t lowater;
-       isc_uint32_t hiwater;
-
-       REQUIRE(VALID_CACHE(cache));
-
-       /*
-        * Impose a minumum cache size; pathological things happen if there
-        * is too little room.
-        */
-       if (size != 0 && size < DNS_CACHE_MINSIZE)
-               size = DNS_CACHE_MINSIZE;
-
-       hiwater = size - (size >> 3);   /* Approximately 7/8ths. */
-       lowater = size - (size >> 2);   /* Approximately 3/4ths. */
-
-       /*
-        * If the cache was overmem and cleaning, but now with the new limits
-        * it is no longer in an overmem condition, then the next
-        * isc_mem_put for cache memory will do the right thing and trigger
-        * water().
-        */
-
-       if (size == 0 || hiwater == 0 || lowater == 0)
-               /*
-                * Disable cache memory limiting.
-                */
-               isc_mem_setwater(cache->mctx, water, cache, 0, 0);
-       else
-               /*
-                * Establish new cache memory limits (either for the first
-                * time, or replacing other limits).
-                */
-               isc_mem_setwater(cache->mctx, water, cache, hiwater, lowater);
+        isc_uint32_t lowater;
+        isc_uint32_t hiwater;
+
+        REQUIRE(VALID_CACHE(cache));
+
+        /*
+         * Impose a minumum cache size; pathological things happen if there
+         * is too little room.
+         */
+        if (size != 0 && size < DNS_CACHE_MINSIZE)
+                size = DNS_CACHE_MINSIZE;
+
+        hiwater = size - (size >> 3);   /* Approximately 7/8ths. */
+        lowater = size - (size >> 2);   /* Approximately 3/4ths. */
+
+        /*
+         * If the cache was overmem and cleaning, but now with the new limits
+         * it is no longer in an overmem condition, then the next
+         * isc_mem_put for cache memory will do the right thing and trigger
+         * water().
+         */
+
+        if (size == 0 || hiwater == 0 || lowater == 0)
+                /*
+                 * Disable cache memory limiting.
+                 */
+                isc_mem_setwater(cache->mctx, water, cache, 0, 0);
+        else
+                /*
+                 * Establish new cache memory limits (either for the first
+                 * time, or replacing other limits).
+                 */
+                isc_mem_setwater(cache->mctx, water, cache, hiwater, lowater);
 }
 
 /*
@@ -1033,122 +756,148 @@ dns_cache_setcachesize(dns_cache_t *cache, isc_uint32_t size) {
  */
 static void
 cleaner_shutdown_action(isc_task_t *task, isc_event_t *event) {
-       dns_cache_t *cache = event->ev_arg;
-       isc_boolean_t should_free = ISC_FALSE;
+        dns_cache_t *cache = event->ev_arg;
+        isc_boolean_t should_free = ISC_FALSE;
+
+        UNUSED(task);
 
-       UNUSED(task);
+        INSIST(task == cache->cleaner.task);
+        INSIST(event->ev_type == ISC_TASKEVENT_SHUTDOWN);
 
-       INSIST(task == cache->cleaner.task);
-       INSIST(event->ev_type == ISC_TASKEVENT_SHUTDOWN);
+        LOCK(&cache->lock);
 
-       if (CLEANER_BUSY(&cache->cleaner))
-               end_cleaning(&cache->cleaner, event);
-       else
-               isc_event_free(&event);
+        cache->live_tasks--;
+        INSIST(cache->live_tasks == 0);
 
-       LOCK(&cache->lock);
+        if (cache->references == 0)
+                should_free = ISC_TRUE;
 
-       cache->live_tasks--;
-       INSIST(cache->live_tasks == 0);
+        /*
+         * By detaching the timer in the context of its task,
+         * we are guaranteed that there will be no further timer
+         * events.
+         */
+        if (cache->cleaner.cleaning_timer != NULL)
+                isc_timer_detach(&cache->cleaner.cleaning_timer);
 
-       if (cache->references == 0)
-               should_free = ISC_TRUE;
+#ifdef LRU_DEBUG
+        isc_timer_detach(&cache->dump_timer);
+#endif
 
-       /*
-        * By detaching the timer in the context of its task,
-        * we are guaranteed that there will be no further timer
-        * events.
-        */
-       if (cache->cleaner.cleaning_timer != NULL)
-               isc_timer_detach(&cache->cleaner.cleaning_timer);
+        /* Make sure we don't reschedule anymore. */
+        (void)isc_task_purge(task, NULL, DNS_EVENT_CACHECLEAN, NULL);
 
-       /* Make sure we don't reschedule anymore. */
-       (void)isc_task_purge(task, NULL, DNS_EVENT_CACHECLEAN, NULL);
+        UNLOCK(&cache->lock);
 
-       UNLOCK(&cache->lock);
+        if (should_free)
+                cache_free(cache);
 
-       if (should_free)
-               cache_free(cache);
+        isc_event_free(&event);
 }
 
 isc_result_t
 dns_cache_flush(dns_cache_t *cache) {
-       dns_db_t *db = NULL;
-       isc_result_t result;
-
-       result = cache_create_db(cache, &db);
-       if (result != ISC_R_SUCCESS)
-               return (result);
-
-       LOCK(&cache->lock);
-       LOCK(&cache->cleaner.lock);
-       if (cache->cleaner.state == cleaner_s_idle) {
-               if (cache->cleaner.iterator != NULL)
-                       dns_dbiterator_destroy(&cache->cleaner.iterator);
-               (void) dns_db_createiterator(db, ISC_FALSE,
-                                            &cache->cleaner.iterator);
-       } else {
-               if (cache->cleaner.state == cleaner_s_busy)
-                       cache->cleaner.state = cleaner_s_done;
-               cache->cleaner.replaceiterator = ISC_TRUE;
-       }
-       dns_db_detach(&cache->db);
-       cache->db = db;
-       UNLOCK(&cache->cleaner.lock);
-       UNLOCK(&cache->lock);
-
-       return (ISC_R_SUCCESS);
+        dns_db_t *db = NULL;
+        isc_result_t result;
+
+        result = cache_create_db(cache, &db);
+        if (result != ISC_R_SUCCESS)
+                return (result);
+
+        LOCK(&cache->lock);
+        LOCK(&cache->cleaner.lock);
+        if (cache->cleaner.state == cleaner_s_idle) {
+                /* XXXMLG do something */
+        } else if (cache->cleaner.state == cleaner_s_busy) {
+                /* XXXMLG do something else */
+        }
+        dns_db_detach(&cache->db);
+        cache->db = db;
+        UNLOCK(&cache->cleaner.lock);
+        UNLOCK(&cache->lock);
+
+        return (ISC_R_SUCCESS);
 }
 
 isc_result_t
 dns_cache_flushname(dns_cache_t *cache, dns_name_t *name) {
-       isc_result_t result;
-       dns_rdatasetiter_t *iter = NULL;
-       dns_dbnode_t *node = NULL;
-       dns_db_t *db = NULL;
-       
-       LOCK(&cache->lock);
-       if (cache->db != NULL)
-               dns_db_attach(cache->db, &db);
-       UNLOCK(&cache->lock);
-       if (db == NULL)
-               return (ISC_R_SUCCESS);
-       result = dns_db_findnode(cache->db, name, ISC_FALSE, &node);
-       if (result == ISC_R_NOTFOUND) {
-               result = ISC_R_SUCCESS;
-               goto cleanup_db;
-       }
-       if (result != ISC_R_SUCCESS)
-               goto cleanup_db;
-
-       result = dns_db_allrdatasets(cache->db, node, NULL,
-                                    (isc_stdtime_t)0, &iter);
-       if (result != ISC_R_SUCCESS)
-               goto cleanup_node;
-
-       for (result = dns_rdatasetiter_first(iter);
-            result == ISC_R_SUCCESS;
-            result = dns_rdatasetiter_next(iter))
-       {
-               dns_rdataset_t rdataset;
-               dns_rdataset_init(&rdataset);
-
-               dns_rdatasetiter_current(iter, &rdataset);
-               result = dns_db_deleterdataset(cache->db, node, NULL,
-                                              rdataset.type, rdataset.covers);
-               dns_rdataset_disassociate(&rdataset);
-               if (result != ISC_R_SUCCESS && result != DNS_R_UNCHANGED)
-                       break;
-       }
-       if (result == ISC_R_NOMORE)
-               result = ISC_R_SUCCESS;
-
-       dns_rdatasetiter_destroy(&iter);
+        isc_result_t result;
+        dns_rdatasetiter_t *iter = NULL;
+        dns_dbnode_t *node = NULL;
+        dns_db_t *db = NULL;
+
+        LOCK(&cache->lock);
+        if (cache->db != NULL)
+                dns_db_attach(cache->db, &db);
+        UNLOCK(&cache->lock);
+        if (db == NULL)
+                return (ISC_R_SUCCESS);
+        result = dns_db_findnode(cache->db, name, ISC_FALSE, &node);
+        if (result == ISC_R_NOTFOUND) {
+                result = ISC_R_SUCCESS;
+                goto cleanup_db;
+        }
+        if (result != ISC_R_SUCCESS)
+                goto cleanup_db;
+
+        result = dns_db_allrdatasets(cache->db, node, NULL,
+                                     (isc_stdtime_t)0, &iter);
+        if (result != ISC_R_SUCCESS)
+                goto cleanup_node;
+
+        for (result = dns_rdatasetiter_first(iter);
+             result == ISC_R_SUCCESS;
+             result = dns_rdatasetiter_next(iter))
+        {
+                dns_rdataset_t rdataset;
+                dns_rdataset_init(&rdataset);
+
+                dns_rdatasetiter_current(iter, &rdataset);
+                result = dns_db_deleterdataset(cache->db, node, NULL,
+                                               rdataset.type, rdataset.covers);
+                dns_rdataset_disassociate(&rdataset);
+                if (result != ISC_R_SUCCESS && result != DNS_R_UNCHANGED)
+                        break;
+        }
+        if (result == ISC_R_NOMORE)
+                result = ISC_R_SUCCESS;
+
+        dns_rdatasetiter_destroy(&iter);
 
  cleanup_node:
-       dns_db_detachnode(cache->db, &node);
+        dns_db_detachnode(cache->db, &node);
 
  cleanup_db:
-       dns_db_detach(&db);
-       return (result);
+        dns_db_detach(&db);
+        return (result);
+}
+
+#ifdef LRU_DEBUG
+static void
+timer_dump(isc_task_t *task, isc_event_t *event) {
+        dns_cache_t *cache;
+        isc_interval_t interval;
+        isc_time_t nexttime;
+
+        UNUSED(task);
+
+        cache = event->ev_arg;
+        INSIST(VALID_CACHE(cache));
+
+#ifdef LRU_DEBUG
+        /* XXX: abuse existing overmem method */
+        dns_db_overmem(cache->db, (isc_boolean_t)-1);
+#endif
+
+        interval.seconds = DUMP_INTERVAL;
+        interval.nanoseconds = 0;
+
+        RUNTIME_CHECK(isc_time_add(&cache->dump_time, &interval, &nexttime) ==
+                      ISC_R_SUCCESS); /* XXX: this is not always true */
+        cache->dump_time = nexttime;
+        (void)isc_timer_reset(cache->dump_timer, isc_timertype_once,
+                              &cache->dump_time, NULL, ISC_FALSE);
+
+        isc_event_free(&event);
 }
+#endif
index f308df0d02f1c942312683842aaba67bec7ff7e3..f5f00a9f01f5cfc70537350532e47f7ac93d2e72 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: rbt.h,v 1.68 2007/06/19 23:47:17 tbox Exp $ */
+/* $Id: rbt.h,v 1.69 2007/10/19 17:15:53 explorer Exp $ */
 
 #ifndef DNS_RBT_H
 #define DNS_RBT_H 1
@@ -37,10 +37,10 @@ ISC_LANG_BEGINDECLS
  * Option values for dns_rbt_findnode() and dns_rbt_findname().
  * These are used to form a bitmask.
  */
-#define DNS_RBTFIND_NOOPTIONS                  0x00
-#define DNS_RBTFIND_EMPTYDATA                  0x01
-#define DNS_RBTFIND_NOEXACT                    0x02
-#define DNS_RBTFIND_NOPREDECESSOR              0x04
+#define DNS_RBTFIND_NOOPTIONS                   0x00
+#define DNS_RBTFIND_EMPTYDATA                   0x01
+#define DNS_RBTFIND_NOEXACT                     0x02
+#define DNS_RBTFIND_NOPREDECESSOR               0x04
 /*@}*/
 
 #ifndef DNS_RBT_USEISCREFCOUNT
@@ -52,14 +52,14 @@ ISC_LANG_BEGINDECLS
 /*
  * These should add up to 30.
  */
-#define DNS_RBT_LOCKLENGTH                     10
-#define DNS_RBT_REFLENGTH                      20
+#define DNS_RBT_LOCKLENGTH                      10
+#define DNS_RBT_REFLENGTH                       20
 
-#define DNS_RBTNODE_MAGIC              ISC_MAGIC('R','B','N','O')
+#define DNS_RBTNODE_MAGIC               ISC_MAGIC('R','B','N','O')
 #if DNS_RBT_USEMAGIC
-#define DNS_RBTNODE_VALID(n)           ISC_MAGIC_VALID(n, DNS_RBTNODE_MAGIC)
+#define DNS_RBTNODE_VALID(n)            ISC_MAGIC_VALID(n, DNS_RBTNODE_MAGIC)
 #else
-#define DNS_RBTNODE_VALID(n)           ISC_TRUE
+#define DNS_RBTNODE_VALID(n)            ISC_TRUE
 #endif
 
 /*%
@@ -69,66 +69,75 @@ ISC_LANG_BEGINDECLS
  * appended to this structure.  Allocating a contiguous block of memory for
  * multiple dns_rbtnode structures will not work.
  */
-typedef struct dns_rbtnode {
+typedef struct dns_rbtnode dns_rbtnode_t;
+struct dns_rbtnode {
 #if DNS_RBT_USEMAGIC
-       unsigned int magic;
+        unsigned int magic;
 #endif
-       struct dns_rbtnode *parent;
-       struct dns_rbtnode *left;
-       struct dns_rbtnode *right;
-       struct dns_rbtnode *down;
+        dns_rbtnode_t *parent;
+        dns_rbtnode_t *left;
+        dns_rbtnode_t *right;
+        dns_rbtnode_t *down;
 #ifdef DNS_RBT_USEHASH
-       struct dns_rbtnode *hashnext;
+        dns_rbtnode_t *hashnext;
 #endif
-       /*@{*/
-       /*!
-        * The following bitfields add up to a total bitwidth of 32.
-        * The range of values necessary for each item is indicated,
-        * but in the case of "attributes" the field is wider to accomodate
-        * possible future expansion.  "offsetlen" could be one bit
-        * narrower by always adjusting its value by 1 to find the real
-        * offsetlen, but doing so does not gain anything (except perhaps
-        * another bit for "attributes", which doesn't yet need any more).
-        *
-        * In each case below the "range" indicated is what's _necessary_ for
-        * the bitfield to hold, not what it actually _can_ hold.
-        */
-       unsigned int is_root : 1;       /*%< range is 0..1 */
-       unsigned int color : 1;         /*%< range is 0..1 */
-       unsigned int find_callback : 1; /*%< range is 0..1 */
-       unsigned int attributes : 4;    /*%< range is 0..2 */
-       unsigned int namelen : 8;       /*%< range is 1..255 */
-       unsigned int offsetlen : 8;     /*%< range is 1..128 */
-       unsigned int padbytes : 9;      /*%< range is 0..380 */
-       /*@}*/
+
+        /*%
+         * Used for LRU cache.  This linked list is used to mark nodes which
+         * have no data any longer, but we cannot unlink at that exact moment
+         * because we did not or could not obtain a write lock on the tree.
+         */
+        ISC_LINK(dns_rbtnode_t) deadlink;
+
+        /*@{*/
+        /*!
+         * The following bitfields add up to a total bitwidth of 32.
+         * The range of values necessary for each item is indicated,
+         * but in the case of "attributes" the field is wider to accomodate
+         * possible future expansion.  "offsetlen" could be one bit
+         * narrower by always adjusting its value by 1 to find the real
+         * offsetlen, but doing so does not gain anything (except perhaps
+         * another bit for "attributes", which doesn't yet need any more).
+         *
+         * In each case below the "range" indicated is what's _necessary_ for
+         * the bitfield to hold, not what it actually _can_ hold.
+         */
+        unsigned int is_root : 1;       /*%< range is 0..1 */
+        unsigned int color : 1;         /*%< range is 0..1 */
+        unsigned int find_callback : 1; /*%< range is 0..1 */
+        unsigned int attributes : 4;    /*%< range is 0..2 */
+        unsigned int namelen : 8;       /*%< range is 1..255 */
+        unsigned int offsetlen : 8;     /*%< range is 1..128 */
+        unsigned int padbytes : 9;      /*%< range is 0..380 */
+        /*@}*/
 
 #ifdef DNS_RBT_USEHASH
-       unsigned int hashval;
+        unsigned int hashval;
 #endif
 
-       /*@{*/
-       /*!
-        * These values are used in the RBT DB implementation.  The appropriate
-        * node lock must be held before accessing them.
-        */
-       void *data;
-       unsigned int dirty:1;
-       unsigned int wild:1;
-       unsigned int locknum:DNS_RBT_LOCKLENGTH;
+        /*@{*/
+        /*!
+         * These values are used in the RBT DB implementation.  The appropriate
+         * node lock must be held before accessing them.
+         */
+        void *data;
+        unsigned int dirty:1;
+        unsigned int wild:1;
+        unsigned int locknum:DNS_RBT_LOCKLENGTH;
 #ifndef DNS_RBT_USEISCREFCOUNT
-       unsigned int references:DNS_RBT_REFLENGTH;
+        unsigned int references:DNS_RBT_REFLENGTH;
 #else
-       isc_refcount_t references; /* note that this is not in the bitfield */
+        isc_refcount_t references; /* note that this is not in the bitfield */
 #endif
-       /*@}*/
-} dns_rbtnode_t;
+        /*@}*/
+};
 
 typedef isc_result_t (*dns_rbtfindcallback_t)(dns_rbtnode_t *node,
-                                             dns_name_t *name,
-                                             void *callback_arg);
+                                              dns_name_t *name,
+                                              void *callback_arg);
 
 /*****
- ***** Chain Info
+ *****  Chain Info
  *****/
 
 /*!
@@ -182,41 +191,41 @@ typedef isc_result_t (*dns_rbtfindcallback_t)(dns_rbtnode_t *node,
 #define DNS_RBT_LEVELBLOCK 254
 
 typedef struct dns_rbtnodechain {
-       unsigned int            magic;
-       isc_mem_t *             mctx;
-       /*%
-        * The terminal node of the chain.  It is not in levels[].
-        * This is ostensibly private ... but in a pinch it could be
-        * used tell that the chain points nowhere without needing to
-        * call dns_rbtnodechain_current().
-        */
-       dns_rbtnode_t *         end;
-       /*%
-        * The maximum number of labels in a name is 128; bitstrings mean
-        * a conceptually very large number (which I have not bothered to
-        * compute) of logical levels because splitting can potentially occur
-        * at each bit.  However, DNSSEC restricts the number of "logical"
-        * labels in a name to 255, meaning only 254 pointers are needed
-        * in the worst case.
-        */
-       dns_rbtnode_t *         levels[DNS_RBT_LEVELBLOCK];
-       /*%
-        * level_count indicates how deep the chain points into the
-        * tree of trees, and is the index into the levels[] array.
-        * Thus, levels[level_count - 1] is the last level node stored.
-        * A chain that points to the top level of the tree of trees has
-        * a level_count of 0, the first level has a level_count of 1, and
-        * so on.
-        */
-       unsigned int            level_count;
-       /*%
-        * level_matches tells how many levels matched above the node
-        * returned by dns_rbt_findnode().  A match (partial or exact) found
-        * in the first level thus results in level_matches being set to 1.
-        * This is used by the rbtdb to set the start point for a recursive
-        * search of superdomains until the RR it is looking for is found.
-        */
-       unsigned int            level_matches;
+        unsigned int            magic;
+        isc_mem_t *             mctx;
+        /*%
+         * The terminal node of the chain.  It is not in levels[].
+         * This is ostensibly private ... but in a pinch it could be
+         * used tell that the chain points nowhere without needing to
+         * call dns_rbtnodechain_current().
+         */
+        dns_rbtnode_t *         end;
+        /*%
+         * The maximum number of labels in a name is 128; bitstrings mean
+         * a conceptually very large number (which I have not bothered to
+         * compute) of logical levels because splitting can potentially occur
+         * at each bit.  However, DNSSEC restricts the number of "logical"
+         * labels in a name to 255, meaning only 254 pointers are needed
+         * in the worst case.
+         */
+        dns_rbtnode_t *         levels[DNS_RBT_LEVELBLOCK];
+        /*%
+         * level_count indicates how deep the chain points into the
+         * tree of trees, and is the index into the levels[] array.
+         * Thus, levels[level_count - 1] is the last level node stored.
+         * A chain that points to the top level of the tree of trees has
+         * a level_count of 0, the first level has a level_count of 1, and
+         * so on.
+         */
+        unsigned int            level_count;
+        /*%
+         * level_matches tells how many levels matched above the node
+         * returned by dns_rbt_findnode().  A match (partial or exact) found
+         * in the first level thus results in level_matches being set to 1.
+         * This is used by the rbtdb to set the start point for a recursive
+         * search of superdomains until the RR it is looking for is found.
+         */
+        unsigned int            level_matches;
 } dns_rbtnodechain_t;
 
 /*****
@@ -224,32 +233,32 @@ typedef struct dns_rbtnodechain {
  *****/
 isc_result_t
 dns_rbt_create(isc_mem_t *mctx, void (*deleter)(void *, void *),
-              void *deleter_arg, dns_rbt_t **rbtp);
+               void *deleter_arg, dns_rbt_t **rbtp);
 /*%<
  * Initialize a red-black tree of trees.
  *
  * Notes:
- *\li  The deleter argument, if non-null, points to a function that is
- *     responsible for cleaning up any memory associated with the data
- *     pointer of a node when the node is deleted.  It is passed the
- *     deleted node's data pointer as its first argument and deleter_arg
- *     as its second argument.
+ *\li   The deleter argument, if non-null, points to a function that is
+ *      responsible for cleaning up any memory associated with the data
+ *      pointer of a node when the node is deleted.  It is passed the
+ *      deleted node's data pointer as its first argument and deleter_arg
+ *      as its second argument.
  *
  * Requires:
- * \li mctx is a pointer to a valid memory context.
- *\li  rbtp != NULL && *rbtp == NULL
- *\li  arg == NULL iff deleter == NULL
+ * \li  mctx is a pointer to a valid memory context.
+ *\li   rbtp != NULL && *rbtp == NULL
+ *\li   arg == NULL iff deleter == NULL
  *
  * Ensures:
- *\li  If result is ISC_R_SUCCESS:
- *             *rbtp points to a valid red-black tree manager
+ *\li   If result is ISC_R_SUCCESS:
+ *              *rbtp points to a valid red-black tree manager
  *
- *\li  If result is failure:
- *             *rbtp does not point to a valid red-black tree manager.
+ *\li   If result is failure:
+ *              *rbtp does not point to a valid red-black tree manager.
  *
  * Returns:
- *\li  #ISC_R_SUCCESS  Success
- *\li  #ISC_R_NOMEMORY Resource limit: Out of Memory
+ *\li   #ISC_R_SUCCESS  Success
+ *\li   #ISC_R_NOMEMORY Resource limit: Out of Memory
  */
 
 isc_result_t
@@ -258,38 +267,38 @@ dns_rbt_addname(dns_rbt_t *rbt, dns_name_t *name, void *data);
  * Add 'name' to the tree of trees, associated with 'data'.
  *
  * Notes:
- *\li  'data' is never required to be non-NULL, but specifying it
- *     when the name is added is faster than searching for 'name'
- *     again and then setting the data pointer.  The lack of a data pointer
- *     for a node also has other ramifications regarding whether
- *     dns_rbt_findname considers a node to exist, or dns_rbt_deletename
- *     joins nodes.
+ *\li   'data' is never required to be non-NULL, but specifying it
+ *      when the name is added is faster than searching for 'name'
+ *      again and then setting the data pointer.  The lack of a data pointer
+ *      for a node also has other ramifications regarding whether
+ *      dns_rbt_findname considers a node to exist, or dns_rbt_deletename
+ *      joins nodes.
  *
  * Requires:
- *\li  rbt is a valid rbt manager.
- *\li  dns_name_isabsolute(name) == TRUE
+ *\li   rbt is a valid rbt manager.
+ *\li   dns_name_isabsolute(name) == TRUE
  *
  * Ensures:
- *\li  'name' is not altered in any way.
+ *\li   'name' is not altered in any way.
  *
- *\li  Any external references to nodes in the tree are unaffected by
- *     node splits that are necessary to insert the new name.
+ *\li   Any external references to nodes in the tree are unaffected by
+ *      node splits that are necessary to insert the new name.
  *
- *\li  If result is #ISC_R_SUCCESS:
- *             'name' is findable in the red/black tree of trees in O(log N).
- *             The data pointer of the node for 'name' is set to 'data'.
+ *\li   If result is #ISC_R_SUCCESS:
+ *              'name' is findable in the red/black tree of trees in O(log N).
+ *              The data pointer of the node for 'name' is set to 'data'.
  *
- *\li  If result is #ISC_R_EXISTS or #ISC_R_NOSPACE:
- *             The tree of trees is unaltered.
+ *\li   If result is #ISC_R_EXISTS or #ISC_R_NOSPACE:
+ *              The tree of trees is unaltered.
  *
- *\li  If result is #ISC_R_NOMEMORY:
- *             No guarantees.
+ *\li   If result is #ISC_R_NOMEMORY:
+ *              No guarantees.
  *
  * Returns:
- *\li  #ISC_R_SUCCESS  Success
- *\li  #ISC_R_EXISTS   The name already exists with associated data.
- *\li  #ISC_R_NOSPACE  The name had more logical labels than are allowed.
- *\li  #ISC_R_NOMEMORY Resource Limit: Out of Memory
+ *\li   #ISC_R_SUCCESS  Success
+ *\li   #ISC_R_EXISTS   The name already exists with associated data.
+ *\li   #ISC_R_NOSPACE  The name had more logical labels than are allowed.
+ *\li   #ISC_R_NOMEMORY Resource Limit: Out of Memory
  */
 
 isc_result_t
@@ -299,175 +308,175 @@ dns_rbt_addnode(dns_rbt_t *rbt, dns_name_t *name, dns_rbtnode_t **nodep);
  * Just like dns_rbt_addname, but returns the address of the node.
  *
  * Requires:
- *\li  rbt is a valid rbt structure.
- *\li  dns_name_isabsolute(name) == TRUE
- *\li  nodep != NULL && *nodep == NULL
+ *\li   rbt is a valid rbt structure.
+ *\li   dns_name_isabsolute(name) == TRUE
+ *\li   nodep != NULL && *nodep == NULL
  *
  * Ensures:
- *\li  'name' is not altered in any way.
+ *\li   'name' is not altered in any way.
  *
- *\li  Any external references to nodes in the tree are unaffected by
- *     node splits that are necessary to insert the new name.
+ *\li   Any external references to nodes in the tree are unaffected by
+ *      node splits that are necessary to insert the new name.
  *
- *\li  If result is ISC_R_SUCCESS:
- *             'name' is findable in the red/black tree of trees in O(log N).
- *             *nodep is the node that was added for 'name'.
+ *\li   If result is ISC_R_SUCCESS:
+ *              'name' is findable in the red/black tree of trees in O(log N).
+ *              *nodep is the node that was added for 'name'.
  *
- *\li  If result is ISC_R_EXISTS:
- *             The tree of trees is unaltered.
- *             *nodep is the existing node for 'name'.
+ *\li   If result is ISC_R_EXISTS:
+ *              The tree of trees is unaltered.
+ *              *nodep is the existing node for 'name'.
  *
- *\li  If result is ISC_R_NOMEMORY:
- *             No guarantees.
+ *\li   If result is ISC_R_NOMEMORY:
+ *              No guarantees.
  *
  * Returns:
- *\li  #ISC_R_SUCCESS  Success
- *\li  #ISC_R_EXISTS   The name already exists, possibly without data.
- *\li  #ISC_R_NOMEMORY Resource Limit: Out of Memory
+ *\li   #ISC_R_SUCCESS  Success
+ *\li   #ISC_R_EXISTS   The name already exists, possibly without data.
+ *\li   #ISC_R_NOMEMORY Resource Limit: Out of Memory
  */
 
 isc_result_t
 dns_rbt_findname(dns_rbt_t *rbt, dns_name_t *name, unsigned int options,
-                dns_name_t *foundname, void **data);
+                 dns_name_t *foundname, void **data);
 /*%<
  * Get the data pointer associated with 'name'.
  *
  * Notes:
- *\li  When #DNS_RBTFIND_NOEXACT is set, the closest matching superdomain is
+ *\li   When #DNS_RBTFIND_NOEXACT is set, the closest matching superdomain is
  *      returned (also subject to #DNS_RBTFIND_EMPTYDATA), even when there is
- *     an exact match in the tree.
+ *      an exact match in the tree.
  *
  *\li   A node that has no data is considered not to exist for this function,
  *      unless the #DNS_RBTFIND_EMPTYDATA option is set.
  *
  * Requires:
- *\li  rbt is a valid rbt manager.
- *\li  dns_name_isabsolute(name) == TRUE
- *\li  data != NULL && *data == NULL
+ *\li   rbt is a valid rbt manager.
+ *\li   dns_name_isabsolute(name) == TRUE
+ *\li   data != NULL && *data == NULL
  *
  * Ensures:
- *\li  'name' and the tree are not altered in any way.
+ *\li   'name' and the tree are not altered in any way.
  *
- *\li  If result is ISC_R_SUCCESS:
- *             *data is the data associated with 'name'.
+ *\li   If result is ISC_R_SUCCESS:
+ *              *data is the data associated with 'name'.
  *
- *\li  If result is DNS_R_PARTIALMATCH:
- *             *data is the data associated with the deepest superdomain
- *             of 'name' which has data.
+ *\li   If result is DNS_R_PARTIALMATCH:
+ *              *data is the data associated with the deepest superdomain
+ *              of 'name' which has data.
  *
- *\li  If result is ISC_R_NOTFOUND:
- *             Neither the name nor a superdomain was found with data.
+ *\li   If result is ISC_R_NOTFOUND:
+ *              Neither the name nor a superdomain was found with data.
  *
  * Returns:
- *\li  #ISC_R_SUCCESS          Success
- *\li  #DNS_R_PARTIALMATCH     Superdomain found with data
- *\li  #ISC_R_NOTFOUND         No match
- *\li  #ISC_R_NOSPACE          Concatenating nodes to form foundname failed
+ *\li   #ISC_R_SUCCESS          Success
+ *\li   #DNS_R_PARTIALMATCH     Superdomain found with data
+ *\li   #ISC_R_NOTFOUND         No match
+ *\li   #ISC_R_NOSPACE          Concatenating nodes to form foundname failed
  */
 
 isc_result_t
 dns_rbt_findnode(dns_rbt_t *rbt, dns_name_t *name, dns_name_t *foundname,
-                dns_rbtnode_t **node, dns_rbtnodechain_t *chain,
-                unsigned int options, dns_rbtfindcallback_t callback,
-                void *callback_arg);
+                 dns_rbtnode_t **node, dns_rbtnodechain_t *chain,
+                 unsigned int options, dns_rbtfindcallback_t callback,
+                 void *callback_arg);
 /*%<
  * Find the node for 'name'.
  *
  * Notes:
- *\li  A node that has no data is considered not to exist for this function,
- *     unless the DNS_RBTFIND_EMPTYDATA option is set.  This applies to both
- *     exact matches and partial matches.
- *
- *\li  If the chain parameter is non-NULL, then the path through the tree
- *     to the DNSSEC predecessor of the searched for name is maintained,
- *     unless the DNS_RBTFIND_NOPREDECESSOR or DNS_RBTFIND_NOEXACT option
- *     is used. (For more details on those options, see below.)
- *
- *\li  If there is no predecessor, then the chain will point to nowhere, as
- *     indicated by chain->end being NULL or dns_rbtnodechain_current
- *     returning ISC_R_NOTFOUND.  Note that in a normal Internet DNS RBT
- *     there will always be a predecessor for all names except the root
- *     name, because '.' will exist and '.' is the predecessor of
- *     everything.  But you can certainly construct a trivial tree and a
- *     search for it that has no predecessor.
- *
- *\li  Within the chain structure, the 'levels' member of the structure holds
- *     the root node of each level except the first.
- *
- *\li  The 'level_count' of the chain indicates how deep the chain to the
- *     predecessor name is, as an index into the 'levels[]' array.  It does
- *     not count name elements, per se, but only levels of the tree of trees,
- *     the distinction arrising because multiple labels from a name can be
- *     stored on only one level.  It is also does not include the level
- *     that has the node, since that level is not stored in levels[].
- *
- *\li  The chain's 'level_matches' is not directly related to the predecessor.
- *     It is the number of levels above the level of the found 'node',
- *     regardless of whether it was a partial match or exact match.  When
- *     the node is found in the top level tree, or no node is found at all,
- *     level_matches is 0.
- *
- *\li  When DNS_RBTFIND_NOEXACT is set, the closest matching superdomain is
+ *\li   A node that has no data is considered not to exist for this function,
+ *      unless the DNS_RBTFIND_EMPTYDATA option is set.  This applies to both
+ *      exact matches and partial matches.
+ *
+ *\li   If the chain parameter is non-NULL, then the path through the tree
+ *      to the DNSSEC predecessor of the searched for name is maintained,
+ *      unless the DNS_RBTFIND_NOPREDECESSOR or DNS_RBTFIND_NOEXACT option
+ *      is used. (For more details on those options, see below.)
+ *
+ *\li   If there is no predecessor, then the chain will point to nowhere, as
+ *      indicated by chain->end being NULL or dns_rbtnodechain_current
+ *      returning ISC_R_NOTFOUND.  Note that in a normal Internet DNS RBT
+ *      there will always be a predecessor for all names except the root
+ *      name, because '.' will exist and '.' is the predecessor of
+ *      everything.  But you can certainly construct a trivial tree and a
+ *      search for it that has no predecessor.
+ *
+ *\li   Within the chain structure, the 'levels' member of the structure holds
+ *      the root node of each level except the first.
+ *
+ *\li   The 'level_count' of the chain indicates how deep the chain to the
+ *      predecessor name is, as an index into the 'levels[]' array.  It does
+ *      not count name elements, per se, but only levels of the tree of trees,
+ *      the distinction arrising because multiple labels from a name can be
+ *      stored on only one level.  It is also does not include the level
+ *      that has the node, since that level is not stored in levels[].
+ *
+ *\li   The chain's 'level_matches' is not directly related to the predecessor.
+ *      It is the number of levels above the level of the found 'node',
+ *      regardless of whether it was a partial match or exact match.  When
+ *      the node is found in the top level tree, or no node is found at all,
+ *      level_matches is 0.
+ *
+ *\li   When DNS_RBTFIND_NOEXACT is set, the closest matching superdomain is
  *      returned (also subject to DNS_RBTFIND_EMPTYDATA), even when
  *      there is an exact match in the tree.  In this case, the chain
- *     will not point to the DNSSEC predecessor, but will instead point
- *     to the exact match, if there was any.  Thus the preceding paragraphs
- *     should have "exact match" substituted for "predecessor" to describe
- *     how the various elements of the chain are set.  This was done to
- *     ensure that the chain's state was sane, and to prevent problems that
- *     occurred when running the predecessor location code under conditions
- *     it was not designed for.  It is not clear *where* the chain should
- *     point when DNS_RBTFIND_NOEXACT is set, so if you end up using a chain
- *     with this option because you want a particular node, let us know
- *     where you want the chain pointed, so this can be made more firm.
+ *      will not point to the DNSSEC predecessor, but will instead point
+ *      to the exact match, if there was any.  Thus the preceding paragraphs
+ *      should have "exact match" substituted for "predecessor" to describe
+ *      how the various elements of the chain are set.  This was done to
+ *      ensure that the chain's state was sane, and to prevent problems that
+ *      occurred when running the predecessor location code under conditions
+ *      it was not designed for.  It is not clear *where* the chain should
+ *      point when DNS_RBTFIND_NOEXACT is set, so if you end up using a chain
+ *      with this option because you want a particular node, let us know
+ *      where you want the chain pointed, so this can be made more firm.
  *
  * Requires:
- *\li  rbt is a valid rbt manager.
- *\li  dns_name_isabsolute(name) == TRUE.
- *\li  node != NULL && *node == NULL.
- *\li  #DNS_RBTFIND_NOEXACT and DNS_RBTFIND_NOPREDECESSOR are mutally
- *             exclusive.
+ *\li   rbt is a valid rbt manager.
+ *\li   dns_name_isabsolute(name) == TRUE.
+ *\li   node != NULL && *node == NULL.
+ *\li   #DNS_RBTFIND_NOEXACT and DNS_RBTFIND_NOPREDECESSOR are mutally
+ *              exclusive.
  *
  * Ensures:
- *\li  'name' and the tree are not altered in any way.
+ *\li   'name' and the tree are not altered in any way.
  *
- *\li  If result is ISC_R_SUCCESS:
+ *\li   If result is ISC_R_SUCCESS:
  *\verbatim
- *             *node is the terminal node for 'name'.
+ *              *node is the terminal node for 'name'.
 
- *             'foundname' and 'name' represent the same name (though not
- *             the same memory).
+ *              'foundname' and 'name' represent the same name (though not
+ *              the same memory).
 
- *             'chain' points to the DNSSEC predecessor, if any, of 'name'.
+ *              'chain' points to the DNSSEC predecessor, if any, of 'name'.
  *
- *             chain->level_matches and chain->level_count are equal.
+ *              chain->level_matches and chain->level_count are equal.
  *\endverbatim
  *
- *     If result is DNS_R_PARTIALMATCH:
+ *      If result is DNS_R_PARTIALMATCH:
  *\verbatim
- *             *node is the data associated with the deepest superdomain
- *             of 'name' which has data.
+ *              *node is the data associated with the deepest superdomain
+ *              of 'name' which has data.
  *
- *             'foundname' is the name of deepest superdomain (which has
- *             data, unless the DNS_RBTFIND_EMPTYDATA option is set).
+ *              'foundname' is the name of deepest superdomain (which has
+ *              data, unless the DNS_RBTFIND_EMPTYDATA option is set).
  *
- *             'chain' points to the DNSSEC predecessor, if any, of 'name'.
+ *              'chain' points to the DNSSEC predecessor, if any, of 'name'.
  *\endverbatim
  *
- *\li  If result is ISC_R_NOTFOUND:
+ *\li   If result is ISC_R_NOTFOUND:
  *\verbatim
- *             Neither the name nor a superdomain was found.  *node is NULL.
+ *              Neither the name nor a superdomain was found.  *node is NULL.
  *
- *             'chain' points to the DNSSEC predecessor, if any, of 'name'.
+ *              'chain' points to the DNSSEC predecessor, if any, of 'name'.
  *
- *             chain->level_matches is 0.
+ *              chain->level_matches is 0.
  *\endverbatim
  *
  * Returns:
- *\li  #ISC_R_SUCCESS          Success
- *\li  #DNS_R_PARTIALMATCH     Superdomain found with data
- *\li  #ISC_R_NOTFOUND         No match, or superdomain with no data
- *\li  #ISC_R_NOSPACE Concatenating nodes to form foundname failed
+ *\li   #ISC_R_SUCCESS          Success
+ *\li   #DNS_R_PARTIALMATCH     Superdomain found with data
+ *\li   #ISC_R_NOTFOUND         No match, or superdomain with no data
+ *\li   #ISC_R_NOSPACE Concatenating nodes to form foundname failed
  */
 
 isc_result_t
@@ -476,41 +485,41 @@ dns_rbt_deletename(dns_rbt_t *rbt, dns_name_t *name, isc_boolean_t recurse);
  * Delete 'name' from the tree of trees.
  *
  * Notes:
- *\li  When 'name' is removed, if recurse is ISC_TRUE then all of its
+ *\li   When 'name' is removed, if recurse is ISC_TRUE then all of its
  *      subnames are removed too.
  *
  * Requires:
- *\li  rbt is a valid rbt manager.
- *\li  dns_name_isabsolute(name) == TRUE
+ *\li   rbt is a valid rbt manager.
+ *\li   dns_name_isabsolute(name) == TRUE
  *
  * Ensures:
- *\li  'name' is not altered in any way.
+ *\li   'name' is not altered in any way.
  *
- *\li  Does NOT ensure that any external references to nodes in the tree
- *     are unaffected by node joins.
+ *\li   Does NOT ensure that any external references to nodes in the tree
+ *      are unaffected by node joins.
  *
- *\li  If result is ISC_R_SUCCESS:
- *             'name' does not appear in the tree with data; however,
- *             the node for the name might still exist which can be
- *             found with dns_rbt_findnode (but not dns_rbt_findname).
+ *\li   If result is ISC_R_SUCCESS:
+ *              'name' does not appear in the tree with data; however,
+ *              the node for the name might still exist which can be
+ *              found with dns_rbt_findnode (but not dns_rbt_findname).
  *
- *\li  If result is ISC_R_NOTFOUND:
- *             'name' does not appear in the tree with data, because
- *             it did not appear in the tree before the function was called.
+ *\li   If result is ISC_R_NOTFOUND:
+ *              'name' does not appear in the tree with data, because
+ *              it did not appear in the tree before the function was called.
  *
- *\li  If result is something else:
- *             See result codes for dns_rbt_findnode (if it fails, the
- *             node is not deleted) or dns_rbt_deletenode (if it fails,
- *             the node is deleted, but the tree is not optimized when
- *             it could have been).
+ *\li   If result is something else:
+ *              See result codes for dns_rbt_findnode (if it fails, the
+ *              node is not deleted) or dns_rbt_deletenode (if it fails,
+ *              the node is deleted, but the tree is not optimized when
+ *              it could have been).
  *
  * Returns:
- *\li  #ISC_R_SUCCESS  Success
- *\li  #ISC_R_NOTFOUND No match
- *\li  something_else  Any return code from dns_rbt_findnode except
- *                     DNS_R_PARTIALMATCH (which causes ISC_R_NOTFOUND
- *                     to be returned instead), and any code from
- *                     dns_rbt_deletenode.
+ *\li   #ISC_R_SUCCESS  Success
+ *\li   #ISC_R_NOTFOUND No match
+ *\li   something_else  Any return code from dns_rbt_findnode except
+ *                      DNS_R_PARTIALMATCH (which causes ISC_R_NOTFOUND
+ *                      to be returned instead), and any code from
+ *                      dns_rbt_deletenode.
  */
 
 isc_result_t
@@ -519,32 +528,32 @@ dns_rbt_deletenode(dns_rbt_t *rbt, dns_rbtnode_t *node, isc_boolean_t recurse);
  * Delete 'node' from the tree of trees.
  *
  * Notes:
- *\li  When 'node' is removed, if recurse is ISC_TRUE then all nodes
- *     in levels down from it are removed too.
+ *\li   When 'node' is removed, if recurse is ISC_TRUE then all nodes
+ *      in levels down from it are removed too.
  *
  * Requires:
- *\li  rbt is a valid rbt manager.
- *\li  node != NULL.
+ *\li   rbt is a valid rbt manager.
+ *\li   node != NULL.
  *
  * Ensures:
- *\li  Does NOT ensure that any external references to nodes in the tree
- *     are unaffected by node joins.
+ *\li   Does NOT ensure that any external references to nodes in the tree
+ *      are unaffected by node joins.
  *
- *\li  If result is ISC_R_SUCCESS:
- *             'node' does not appear in the tree with data; however,
- *             the node might still exist if it serves as a pointer to
- *             a lower tree level as long as 'recurse' was false, hence
- *             the node could can be found with dns_rbt_findnode whem
- *             that function's empty_data_ok parameter is true.
+ *\li   If result is ISC_R_SUCCESS:
+ *              'node' does not appear in the tree with data; however,
+ *              the node might still exist if it serves as a pointer to
+ *              a lower tree level as long as 'recurse' was false, hence
+ *              the node could can be found with dns_rbt_findnode whem
+ *              that function's empty_data_ok parameter is true.
  *
- *\li  If result is ISC_R_NOMEMORY or ISC_R_NOSPACE:
- *             The node was deleted, but the tree structure was not
- *             optimized.
+ *\li   If result is ISC_R_NOMEMORY or ISC_R_NOSPACE:
+ *              The node was deleted, but the tree structure was not
+ *              optimized.
  *
  * Returns:
- *\li  #ISC_R_SUCCESS  Success
- *\li  #ISC_R_NOMEMORY Resource Limit: Out of Memory when joining nodes.
- *\li  #ISC_R_NOSPACE  dns_name_concatenate failed when joining nodes.
+ *\li   #ISC_R_SUCCESS  Success
+ *\li   #ISC_R_NOMEMORY Resource Limit: Out of Memory when joining nodes.
+ *\li   #ISC_R_NOSPACE  dns_name_concatenate failed when joining nodes.
  */
 
 void
@@ -553,24 +562,24 @@ dns_rbt_namefromnode(dns_rbtnode_t *node, dns_name_t *name);
  * Convert the sequence of labels stored at 'node' into a 'name'.
  *
  * Notes:
- *\li  This function does not return the full name, from the root, but
- *     just the labels at the indicated node.
+ *\li   This function does not return the full name, from the root, but
+ *      just the labels at the indicated node.
  *
- *\li  The name data pointed to by 'name' is the information stored
- *     in the node, not a copy.  Altering the data at this pointer
- *     will likely cause grief.
+ *\li   The name data pointed to by 'name' is the information stored
+ *      in the node, not a copy.  Altering the data at this pointer
+ *      will likely cause grief.
  *
  * Requires:
- * \li name->offsets == NULL
+ * \li  name->offsets == NULL
  *
  * Ensures:
- * \li 'name' is DNS_NAMEATTR_READONLY.
+ * \li  'name' is DNS_NAMEATTR_READONLY.
  *
- * \li 'name' will point directly to the labels stored after the
- *     dns_rbtnode_t struct.
+ * \li  'name' will point directly to the labels stored after the
+ *      dns_rbtnode_t struct.
  *
- * \li 'name' will have offsets that also point to the information stored
- *     as part of the node.
+ * \li  'name' will have offsets that also point to the information stored
+ *      as part of the node.
  */
 
 isc_result_t
@@ -579,35 +588,35 @@ dns_rbt_fullnamefromnode(dns_rbtnode_t *node, dns_name_t *name);
  * Like dns_rbt_namefromnode, but returns the full name from the root.
  *
  * Notes:
- * \li Unlike dns_rbt_namefromnode, the name will not point directly
- *     to node data.  Rather, dns_name_concatenate will be used to copy
- *     the name data from each node into the 'name' argument.
+ * \li  Unlike dns_rbt_namefromnode, the name will not point directly
+ *      to node data.  Rather, dns_name_concatenate will be used to copy
+ *      the name data from each node into the 'name' argument.
  *
  * Requires:
- * \li name != NULL
- * \li name has a dedicated buffer.
+ * \li  name != NULL
+ * \li  name has a dedicated buffer.
  *
  * Returns:
- * \li ISC_R_SUCCESS
- * \li ISC_R_NOSPACE           (possible via dns_name_concatenate)
- * \li DNS_R_NAMETOOLONG       (possible via dns_name_concatenate)
+ * \li  ISC_R_SUCCESS
+ * \li  ISC_R_NOSPACE           (possible via dns_name_concatenate)
+ * \li  DNS_R_NAMETOOLONG       (possible via dns_name_concatenate)
  */
 
 char *
 dns_rbt_formatnodename(dns_rbtnode_t *node, char *printname,
-                      unsigned int size);
+                       unsigned int size);
 /*%<
  * Format the full name of a node for printing, using dns_name_format().
  *
  * Notes:
- * \li 'size' is the length of the printname buffer.  This should be
- *     DNS_NAME_FORMATSIZE or larger.
+ * \li  'size' is the length of the printname buffer.  This should be
+ *      DNS_NAME_FORMATSIZE or larger.
  *
  * Requires:
- * \li node and printname are not NULL.
+ * \li  node and printname are not NULL.
  *
  * Returns:
- * \li The 'printname' pointer.
+ * \li  The 'printname' pointer.
  */
 
 unsigned int
@@ -616,7 +625,7 @@ dns_rbt_nodecount(dns_rbt_t *rbt);
  * Obtain the number of nodes in the tree of trees.
  *
  * Requires:
- * \li rbt is a valid rbt manager.
+ * \li  rbt is a valid rbt manager.
  */
 
 void
@@ -624,25 +633,25 @@ dns_rbt_destroy(dns_rbt_t **rbtp);
 isc_result_t
 dns_rbt_destroy2(dns_rbt_t **rbtp, unsigned int quantum);
 /*%<
- * Stop working with a red-black tree of trees. 
+ * Stop working with a red-black tree of trees.
  * If 'quantum' is zero then the entire tree will be destroyed.
  * If 'quantum' is non zero then up to 'quantum' nodes will be destroyed
  * allowing the rbt to be incrementally destroyed by repeated calls to
  * dns_rbt_destroy2().  Once dns_rbt_destroy2() has been called no other
  * operations than dns_rbt_destroy()/dns_rbt_destroy2() should be
  * performed on the tree of trees.
- * 
+ *
  * Requires:
- * \li *rbt is a valid rbt manager.
+ * \li  *rbt is a valid rbt manager.
  *
  * Ensures on ISC_R_SUCCESS:
- * \li All space allocated by the RBT library has been returned.
+ * \li  All space allocated by the RBT library has been returned.
  *
- * \li *rbt is invalidated as an rbt manager.
+ * \li  *rbt is invalidated as an rbt manager.
  *
  * Returns:
- * \li ISC_R_SUCCESS
- * \li ISC_R_QUOTA if 'quantum' nodes have been destroyed.
+ * \li  ISC_R_SUCCESS
+ * \li  ISC_R_QUOTA if 'quantum' nodes have been destroyed.
  */
 
 void
@@ -652,10 +661,10 @@ dns_rbt_printall(dns_rbt_t *rbt);
  * tree of trees.
  *
  * Notes:
- * \li The name stored at each node, along with the node's color, is printed.
- *     Then the down pointer, left and right pointers are displayed
- *     recursively in turn.  NULL down pointers are silently omitted;
- *     NULL left and right pointers are printed.
+ * \li  The name stored at each node, along with the node's color, is printed.
+ *      Then the down pointer, left and right pointers are displayed
+ *      recursively in turn.  NULL down pointers are silently omitted;
+ *      NULL left and right pointers are printed.
  */
 
 /*****
@@ -668,12 +677,12 @@ dns_rbtnodechain_init(dns_rbtnodechain_t *chain, isc_mem_t *mctx);
  * Initialize 'chain'.
  *
  * Requires:
- *\li  'chain' is a valid pointer.
+ *\li   'chain' is a valid pointer.
  *
- *\li  'mctx' is a valid memory context.
+ *\li   'mctx' is a valid memory context.
  *
  * Ensures:
- *\li  'chain' is suitable for use.
+ *\li   'chain' is suitable for use.
  */
 
 void
@@ -683,10 +692,10 @@ dns_rbtnodechain_reset(dns_rbtnodechain_t *chain);
  * 'chain'.
  *
  * Requires:
- *\li  'chain' is a valid pointer.
+ *\li   'chain' is a valid pointer.
  *
  * Ensures:
- *\li  'chain' is suitable for use, and uses no dynamic storage.
+ *\li   'chain' is suitable for use, and uses no dynamic storage.
  */
 
 void
@@ -695,163 +704,163 @@ dns_rbtnodechain_invalidate(dns_rbtnodechain_t *chain);
  * Free any dynamic storage associated with 'chain', and then invalidates it.
  *
  * Notes:
- *\li  Future calls to any dns_rbtnodechain_ function will need to call
- *     dns_rbtnodechain_init on the chain first (except, of course,
- *     dns_rbtnodechain_init itself).
+ *\li   Future calls to any dns_rbtnodechain_ function will need to call
+ *      dns_rbtnodechain_init on the chain first (except, of course,
+ *      dns_rbtnodechain_init itself).
  *
  * Requires:
- *\li  'chain' is a valid chain.
+ *\li   'chain' is a valid chain.
  *
  * Ensures:
- *\li  'chain' is no longer suitable for use, and uses no dynamic storage.
+ *\li   'chain' is no longer suitable for use, and uses no dynamic storage.
  */
 
 isc_result_t
 dns_rbtnodechain_current(dns_rbtnodechain_t *chain, dns_name_t *name,
-                        dns_name_t *origin, dns_rbtnode_t **node);
+                         dns_name_t *origin, dns_rbtnode_t **node);
 /*%<
  * Provide the name, origin and node to which the chain is currently pointed.
  *
  * Notes:
- *\li  The tree need not have be locked against additions for the chain
- *     to remain valid, however there are no guarantees if any deletion
- *     has been made since the chain was established.
+ *\li   The tree need not have be locked against additions for the chain
+ *      to remain valid, however there are no guarantees if any deletion
+ *      has been made since the chain was established.
  *
  * Requires:
- *\li  'chain' is a valid chain.
+ *\li   'chain' is a valid chain.
  *
  * Ensures:
- *\li  'node', if non-NULL, is the node to which the chain was pointed
- *     by dns_rbt_findnode, dns_rbtnodechain_first or dns_rbtnodechain_last.
- *     If none were called for the chain since it was initialized or reset,
- *     or if the was no predecessor to the name searched for with
- *     dns_rbt_findnode, then '*node' is NULL and ISC_R_NOTFOUND is returned.
+ *\li   'node', if non-NULL, is the node to which the chain was pointed
+ *      by dns_rbt_findnode, dns_rbtnodechain_first or dns_rbtnodechain_last.
+ *      If none were called for the chain since it was initialized or reset,
+ *      or if the was no predecessor to the name searched for with
+ *      dns_rbt_findnode, then '*node' is NULL and ISC_R_NOTFOUND is returned.
  *
- *\li  'name', if non-NULL, is the name stored at the terminal level of
- *     the chain.  This is typically a single label, like the "www" of
- *     "www.isc.org", but need not be so.  At the root of the tree of trees,
- *     if the node is "." then 'name' is ".", otherwise it is relative to ".".
- *     (Minimalist and atypical case:  if the tree has just the name
- *     "isc.org." then the root node's stored name is "isc.org." but 'name'
- *     will be "isc.org".)
+ *\li   'name', if non-NULL, is the name stored at the terminal level of
+ *      the chain.  This is typically a single label, like the "www" of
+ *      "www.isc.org", but need not be so.  At the root of the tree of trees,
+ *      if the node is "." then 'name' is ".", otherwise it is relative to ".".
+ *      (Minimalist and atypical case:  if the tree has just the name
+ *      "isc.org." then the root node's stored name is "isc.org." but 'name'
+ *      will be "isc.org".)
  *
- *\li  'origin', if non-NULL, is the sequence of labels in the levels
- *     above the terminal level, such as "isc.org." in the above example.
- *     'origin' is always "." for the root node.
+ *\li   'origin', if non-NULL, is the sequence of labels in the levels
+ *      above the terminal level, such as "isc.org." in the above example.
+ *      'origin' is always "." for the root node.
  *
  *
  * Returns:
- *\li  #ISC_R_SUCCESS          name, origin & node were successfully set.
- *\li  #ISC_R_NOTFOUND         The chain does not point to any node.
- *\li  &lt;something_else>     Any error return from dns_name_concatenate.
+ *\li   #ISC_R_SUCCESS          name, origin & node were successfully set.
+ *\li   #ISC_R_NOTFOUND         The chain does not point to any node.
+ *\li   &lt;something_else>     Any error return from dns_name_concatenate.
  */
 
 isc_result_t
 dns_rbtnodechain_first(dns_rbtnodechain_t *chain, dns_rbt_t *rbt,
-                      dns_name_t *name, dns_name_t *origin);
+                       dns_name_t *name, dns_name_t *origin);
 /*%<
  * Set the chain to the lexically first node in the tree of trees.
  *
  * Notes:
- *\li  By the definition of ordering for DNS names, the root of the tree of
- *     trees is the very first node, since everything else in the megatree
- *     uses it as a common suffix.
+ *\li   By the definition of ordering for DNS names, the root of the tree of
+ *      trees is the very first node, since everything else in the megatree
+ *      uses it as a common suffix.
  *
  * Requires:
- *\li  'chain' is a valid chain.
- *\li  'rbt' is a valid rbt manager.
+ *\li   'chain' is a valid chain.
+ *\li   'rbt' is a valid rbt manager.
  *
  * Ensures:
- *\li  The chain points to the very first node of the tree.
+ *\li   The chain points to the very first node of the tree.
  *
- *\li  'name' and 'origin', if non-NULL, are set as described for
- *     dns_rbtnodechain_current.  Thus 'origin' will always be ".".
+ *\li   'name' and 'origin', if non-NULL, are set as described for
+ *      dns_rbtnodechain_current.  Thus 'origin' will always be ".".
  *
  * Returns:
- *\li  #DNS_R_NEWORIGIN                The name & origin were successfully set.
- *\li  &lt;something_else>     Any error result from dns_rbtnodechain_current.
+ *\li   #DNS_R_NEWORIGIN                The name & origin were successfully set.
+ *\li   &lt;something_else>     Any error result from dns_rbtnodechain_current.
  */
 
 isc_result_t
 dns_rbtnodechain_last(dns_rbtnodechain_t *chain, dns_rbt_t *rbt,
-                      dns_name_t *name, dns_name_t *origin);
+                       dns_name_t *name, dns_name_t *origin);
 /*%<
  * Set the chain to the lexically last node in the tree of trees.
  *
  * Requires:
- *\li  'chain' is a valid chain.
- *\li  'rbt' is a valid rbt manager.
+ *\li   'chain' is a valid chain.
+ *\li   'rbt' is a valid rbt manager.
  *
  * Ensures:
- *\li  The chain points to the very last node of the tree.
+ *\li   The chain points to the very last node of the tree.
  *
- *\li  'name' and 'origin', if non-NULL, are set as described for
- *     dns_rbtnodechain_current.
+ *\li   'name' and 'origin', if non-NULL, are set as described for
+ *      dns_rbtnodechain_current.
  *
  * Returns:
- *\li  #DNS_R_NEWORIGIN                The name & origin were successfully set.
- *\li  #ISC_R_NOMEMORY         Resource Limit: Out of Memory building chain.
- *\li  &lt;something_else>     Any error result from dns_name_concatenate.
+ *\li   #DNS_R_NEWORIGIN                The name & origin were successfully set.
+ *\li   #ISC_R_NOMEMORY         Resource Limit: Out of Memory building chain.
+ *\li   &lt;something_else>     Any error result from dns_name_concatenate.
  */
 
 isc_result_t
 dns_rbtnodechain_prev(dns_rbtnodechain_t *chain, dns_name_t *name,
-                     dns_name_t *origin);
+                      dns_name_t *origin);
 /*%<
  * Adjusts chain to point the DNSSEC predecessor of the name to which it
  * is currently pointed.
  *
  * Requires:
- *\li  'chain' is a valid chain.
- *\li  'chain' has been pointed somewhere in the tree with dns_rbt_findnode,
- *     dns_rbtnodechain_first or dns_rbtnodechain_last -- and remember that
- *     dns_rbt_findnode is not guaranteed to point the chain somewhere,
- *     since there may have been no predecessor to the searched for name.
+ *\li   'chain' is a valid chain.
+ *\li   'chain' has been pointed somewhere in the tree with dns_rbt_findnode,
+ *      dns_rbtnodechain_first or dns_rbtnodechain_last -- and remember that
+ *      dns_rbt_findnode is not guaranteed to point the chain somewhere,
+ *      since there may have been no predecessor to the searched for name.
  *
  * Ensures:
- *\li  The chain is pointed to the predecessor of its current target.
+ *\li   The chain is pointed to the predecessor of its current target.
  *
- *\li  'name' and 'origin', if non-NULL, are set as described for
- *     dns_rbtnodechain_current.
+ *\li   'name' and 'origin', if non-NULL, are set as described for
+ *      dns_rbtnodechain_current.
  *
- *\li  'origin' is only if a new origin was found.
+ *\li   'origin' is only if a new origin was found.
  *
  * Returns:
- *\li  #ISC_R_SUCCESS          The predecessor was found and 'name' was set.
- *\li  #DNS_R_NEWORIGIN                The predecessor was found with a different
- *                             origin and 'name' and 'origin' were set.
- *\li  #ISC_R_NOMORE           There was no predecessor.
- *\li  &lt;something_else>     Any error result from dns_rbtnodechain_current.
+ *\li   #ISC_R_SUCCESS          The predecessor was found and 'name' was set.
+ *\li   #DNS_R_NEWORIGIN                The predecessor was found with a different
+ *                              origin and 'name' and 'origin' were set.
+ *\li   #ISC_R_NOMORE           There was no predecessor.
+ *\li   &lt;something_else>     Any error result from dns_rbtnodechain_current.
  */
 
 isc_result_t
 dns_rbtnodechain_next(dns_rbtnodechain_t *chain, dns_name_t *name,
-                     dns_name_t *origin);
+                      dns_name_t *origin);
 /*%<
  * Adjusts chain to point the DNSSEC successor of the name to which it
  * is currently pointed.
  *
  * Requires:
- *\li  'chain' is a valid chain.
- *\li  'chain' has been pointed somewhere in the tree with dns_rbt_findnode,
- *     dns_rbtnodechain_first or dns_rbtnodechain_last -- and remember that
- *     dns_rbt_findnode is not guaranteed to point the chain somewhere,
- *     since there may have been no predecessor to the searched for name.
+ *\li   'chain' is a valid chain.
+ *\li   'chain' has been pointed somewhere in the tree with dns_rbt_findnode,
+ *      dns_rbtnodechain_first or dns_rbtnodechain_last -- and remember that
+ *      dns_rbt_findnode is not guaranteed to point the chain somewhere,
+ *      since there may have been no predecessor to the searched for name.
  *
  * Ensures:
- *\li  The chain is pointed to the successor of its current target.
+ *\li   The chain is pointed to the successor of its current target.
  *
- *\li  'name' and 'origin', if non-NULL, are set as described for
- *     dns_rbtnodechain_current.
+ *\li   'name' and 'origin', if non-NULL, are set as described for
+ *      dns_rbtnodechain_current.
  *
- *\li  'origin' is only if a new origin was found.
+ *\li   'origin' is only if a new origin was found.
  *
  * Returns:
- *\li  #ISC_R_SUCCESS          The successor was found and 'name' was set.
- *\li  #DNS_R_NEWORIGIN                The successor was found with a different
- *                             origin and 'name' and 'origin' were set.
- *\li  #ISC_R_NOMORE           There was no successor.
- *\li  &lt;something_else>     Any error result from dns_name_concatenate.
+ *\li   #ISC_R_SUCCESS          The successor was found and 'name' was set.
+ *\li   #DNS_R_NEWORIGIN                The successor was found with a different
+ *                              origin and 'name' and 'origin' were set.
+ *\li   #ISC_R_NOMORE           There was no successor.
+ *\li   &lt;something_else>     Any error result from dns_name_concatenate.
  */
 
 /*
@@ -862,53 +871,53 @@ dns_rbtnodechain_next(dns_rbtnodechain_t *chain, dns_name_t *name,
  *   hiding the back-end.  The usage is the same as that of isc_refcount_xxx().
  */
 #ifdef DNS_RBT_USEISCREFCOUNT
-#define dns_rbtnode_refinit(node, n)                           \
-       do {                                                    \
-               isc_refcount_init(&(node)->references, (n));    \
-       } while (0) 
-#define dns_rbtnode_refdestroy(node)                           \
-       do {                                                    \
-               isc_refcount_destroy(&(node)->references);      \
-       } while (0) 
-#define dns_rbtnode_refcurrent(node)                           \
-       isc_refcount_current(&(node)->references)
-#define dns_rbtnode_refincrement0(node, refs)                  \
-       do {                                                    \
-               isc_refcount_increment0(&(node)->references, (refs)); \
-       } while (0) 
-#define dns_rbtnode_refincrement(node, refs)                   \
-       do {                                                    \
-               isc_refcount_increment(&(node)->references, (refs)); \
-       } while (0) 
-#define dns_rbtnode_refdecrement(node, refs)                   \
-       do {                                                    \
-               isc_refcount_decrement(&(node)->references, (refs)); \
-       } while (0) 
+#define dns_rbtnode_refinit(node, n)                            \
+        do {                                                    \
+                isc_refcount_init(&(node)->references, (n));    \
+        } while (0)
+#define dns_rbtnode_refdestroy(node)                            \
+        do {                                                    \
+                isc_refcount_destroy(&(node)->references);      \
+        } while (0)
+#define dns_rbtnode_refcurrent(node)                            \
+        isc_refcount_current(&(node)->references)
+#define dns_rbtnode_refincrement0(node, refs)                   \
+        do {                                                    \
+                isc_refcount_increment0(&(node)->references, (refs)); \
+        } while (0)
+#define dns_rbtnode_refincrement(node, refs)                    \
+        do {                                                    \
+                isc_refcount_increment(&(node)->references, (refs)); \
+        } while (0)
+#define dns_rbtnode_refdecrement(node, refs)                    \
+        do {                                                    \
+                isc_refcount_decrement(&(node)->references, (refs)); \
+        } while (0)
 #else  /* DNS_RBT_USEISCREFCOUNT */
-#define dns_rbtnode_refinit(node, n)   ((node)->references = (n))
-#define dns_rbtnode_refdestroy(node)   (REQUIRE((node)->references == 0))
-#define dns_rbtnode_refcurrent(node)   ((node)->references)
-#define dns_rbtnode_refincrement0(node, refs)                  \
-       do {                                                    \
-               unsigned int *_tmp = (unsigned int *)(refs);    \
-               (node)->references++;                           \
-               if ((_tmp) != NULL)                             \
-                       (*_tmp) = (node)->references;           \
-       } while (0) 
-#define dns_rbtnode_refincrement(node, refs)                   \
-       do {                                                    \
-               REQUIRE((node)->references > 0);                \
-               (node)->references++;                           \
-               if ((refs) != NULL)                             \
-                       (*refs) = (node)->references;           \
-       } while (0) 
-#define dns_rbtnode_refdecrement(node, refs)                   \
-       do {                                                    \
-               REQUIRE((node)->references > 0);                \
-               (node)->references--;                           \
-               if ((refs) != NULL)                             \
-                       (*refs) = (node)->references;           \
-       } while (0) 
+#define dns_rbtnode_refinit(node, n)    ((node)->references = (n))
+#define dns_rbtnode_refdestroy(node)    (REQUIRE((node)->references == 0))
+#define dns_rbtnode_refcurrent(node)    ((node)->references)
+#define dns_rbtnode_refincrement0(node, refs)                   \
+        do {                                                    \
+                unsigned int *_tmp = (unsigned int *)(refs);    \
+                (node)->references++;                           \
+                if ((_tmp) != NULL)                             \
+                        (*_tmp) = (node)->references;           \
+        } while (0)
+#define dns_rbtnode_refincrement(node, refs)                    \
+        do {                                                    \
+                REQUIRE((node)->references > 0);                \
+                (node)->references++;                           \
+                if ((refs) != NULL)                             \
+                        (*refs) = (node)->references;           \
+        } while (0)
+#define dns_rbtnode_refdecrement(node, refs)                    \
+        do {                                                    \
+                REQUIRE((node)->references > 0);                \
+                (node)->references--;                           \
+                if ((refs) != NULL)                             \
+                        (*refs) = (node)->references;           \
+        } while (0)
 #endif /* DNS_RBT_USEISCREFCOUNT */
 
 ISC_LANG_ENDDECLS
index 5d695b6094353287d315649153fe4a0115a37944..e12b5f7539255cd2af843e1f079c82c76551db00 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: rbt.c,v 1.137 2007/06/19 23:47:16 tbox Exp $ */
+/* $Id: rbt.c,v 1.138 2007/10/19 17:15:53 explorer Exp $ */
 
 /*! \file */
 
 #define DNS_NAME_USEINLINE 1
 
 #include <dns/fixedname.h>
+#include <dns/log.h>
 #include <dns/rbt.h>
 #include <dns/result.h>
 
-#define RBT_MAGIC              ISC_MAGIC('R', 'B', 'T', '+')
-#define VALID_RBT(rbt)         ISC_MAGIC_VALID(rbt, RBT_MAGIC)
+#define RBT_MAGIC               ISC_MAGIC('R', 'B', 'T', '+')
+#define VALID_RBT(rbt)          ISC_MAGIC_VALID(rbt, RBT_MAGIC)
 
 /*
  * XXXDCL Since parent pointers were added in again, I could remove all of the
  * chain junk, and replace with dns_rbt_firstnode, _previousnode, _nextnode,
  * _lastnode.  This would involve pretty major change to the API.
  */
-#define CHAIN_MAGIC            ISC_MAGIC('0', '-', '0', '-')
-#define VALID_CHAIN(chain)     ISC_MAGIC_VALID(chain, CHAIN_MAGIC)
+#define CHAIN_MAGIC             ISC_MAGIC('0', '-', '0', '-')
+#define VALID_CHAIN(chain)      ISC_MAGIC_VALID(chain, CHAIN_MAGIC)
 
-#define RBT_HASH_SIZE          64
+#define RBT_HASH_SIZE           64
 
 #ifdef RBT_MEM_TEST
 #undef RBT_HASH_SIZE
-#define RBT_HASH_SIZE 2        /*%< To give the reallocation code a workout. */
+#define RBT_HASH_SIZE 2 /*%< To give the reallocation code a workout. */
 #endif
 
 struct dns_rbt {
-       unsigned int            magic;
-       isc_mem_t *             mctx;
-       dns_rbtnode_t *         root;
-       void                    (*data_deleter)(void *, void *);
-       void *                  deleter_arg;
-       unsigned int            nodecount;
-       unsigned int            hashsize;
-       dns_rbtnode_t **        hashtable;
+        unsigned int            magic;
+        isc_mem_t *             mctx;
+        dns_rbtnode_t *         root;
+        void                    (*data_deleter)(void *, void *);
+        void *                  deleter_arg;
+        unsigned int            nodecount;
+        unsigned int            hashsize;
+        dns_rbtnode_t **        hashtable;
 };
 
 #define RED 0
@@ -75,45 +76,45 @@ struct dns_rbt {
 /*%
  * Elements of the rbtnode structure.
  */
-#define PARENT(node)           ((node)->parent)
-#define LEFT(node)             ((node)->left)
-#define RIGHT(node)            ((node)->right)
-#define DOWN(node)             ((node)->down)
-#define DATA(node)             ((node)->data)
-#define HASHNEXT(node)         ((node)->hashnext)
-#define HASHVAL(node)          ((node)->hashval)
-#define COLOR(node)            ((node)->color)
-#define NAMELEN(node)          ((node)->namelen)
-#define OFFSETLEN(node)                ((node)->offsetlen)
-#define ATTRS(node)            ((node)->attributes)
-#define PADBYTES(node)         ((node)->padbytes)
-#define IS_ROOT(node)          ISC_TF((node)->is_root == 1)
-#define FINDCALLBACK(node)     ISC_TF((node)->find_callback == 1)
+#define PARENT(node)            ((node)->parent)
+#define LEFT(node)              ((node)->left)
+#define RIGHT(node)             ((node)->right)
+#define DOWN(node)              ((node)->down)
+#define DATA(node)              ((node)->data)
+#define HASHNEXT(node)          ((node)->hashnext)
+#define HASHVAL(node)           ((node)->hashval)
+#define COLOR(node)             ((node)->color)
+#define NAMELEN(node)           ((node)->namelen)
+#define OFFSETLEN(node)         ((node)->offsetlen)
+#define ATTRS(node)             ((node)->attributes)
+#define PADBYTES(node)          ((node)->padbytes)
+#define IS_ROOT(node)           ISC_TF((node)->is_root == 1)
+#define FINDCALLBACK(node)      ISC_TF((node)->find_callback == 1)
 
 /*%
  * Structure elements from the rbtdb.c, not
  * used as part of the rbt.c algorithms.
  */
-#define DIRTY(node)    ((node)->dirty)
-#define WILD(node)     ((node)->wild)
-#define LOCKNUM(node)  ((node)->locknum)
+#define DIRTY(node)     ((node)->dirty)
+#define WILD(node)      ((node)->wild)
+#define LOCKNUM(node)   ((node)->locknum)
 
 /*%
  * The variable length stuff stored after the node.
  */
-#define NAME(node)     ((unsigned char *)((node) + 1))
-#define OFFSETS(node)  (NAME(node) + NAMELEN(node))
+#define NAME(node)      ((unsigned char *)((node) + 1))
+#define OFFSETS(node)   (NAME(node) + NAMELEN(node))
 
-#define NODE_SIZE(node)        (sizeof(*node) + \
-                        NAMELEN(node) + OFFSETLEN(node) + PADBYTES(node))
+#define NODE_SIZE(node) (sizeof(*node) + \
+                         NAMELEN(node) + OFFSETLEN(node) + PADBYTES(node))
 
 /*%
  * Color management.
  */
-#define IS_RED(node)           ((node) != NULL && (node)->color == RED)
-#define IS_BLACK(node)         ((node) == NULL || (node)->color == BLACK)
-#define MAKE_RED(node)         ((node)->color = RED)
-#define MAKE_BLACK(node)       ((node)->color = BLACK)
+#define IS_RED(node)            ((node) != NULL && (node)->color == RED)
+#define IS_BLACK(node)          ((node) == NULL || (node)->color == BLACK)
+#define MAKE_RED(node)          ((node)->color = RED)
+#define MAKE_BLACK(node)        ((node)->color = BLACK)
 
 /*%
  * Chain management.
@@ -123,7 +124,7 @@ struct dns_rbt {
  * of memory concerns, when chains were first implemented).
  */
 #define ADD_LEVEL(chain, node) \
-                       (chain)->levels[(chain)->level_count++] = (node)
+                        (chain)->levels[(chain)->level_count++] = (node)
 
 /*%
  * The following macros directly access normally private name variables.
@@ -133,12 +134,12 @@ struct dns_rbt {
 
 #define NODENAME(node, name) \
 do { \
-       (name)->length = NAMELEN(node); \
-       (name)->labels = OFFSETLEN(node); \
-       (name)->ndata = NAME(node); \
-       (name)->offsets = OFFSETS(node); \
-       (name)->attributes = ATTRS(node); \
-       (name)->attributes |= DNS_NAMEATTR_READONLY; \
+        (name)->length = NAMELEN(node); \
+        (name)->labels = OFFSETLEN(node); \
+        (name)->ndata = NAME(node); \
+        (name)->offsets = OFFSETS(node); \
+        (name)->attributes = ATTRS(node); \
+        (name)->attributes |= DNS_NAMEATTR_READONLY; \
 } while (0)
 
 #ifdef DNS_RBT_USEHASH
@@ -154,13 +155,13 @@ inithash(dns_rbt_t *rbt);
 dns_name_t Name(dns_rbtnode_t *node);
 dns_name_t
 Name(dns_rbtnode_t *node) {
-       dns_name_t name;
+        dns_name_t name;
 
-       dns_name_init(&name, NULL);
-       if (node != NULL)
-               NODENAME(node, &name);
+        dns_name_init(&name, NULL);
+        if (node != NULL)
+                NODENAME(node, &name);
 
-       return (name);
+        return (name);
 }
 
 static void dns_rbt_printnodename(dns_rbtnode_t *node);
@@ -168,17 +169,17 @@ static void dns_rbt_printnodename(dns_rbtnode_t *node);
 
 static inline dns_rbtnode_t *
 find_up(dns_rbtnode_t *node) {
-       dns_rbtnode_t *root;
+        dns_rbtnode_t *root;
 
-       /*
-        * Return the node in the level above the argument node that points
-        * to the level the argument node is in.  If the argument node is in
-        * the top level, the return value is NULL.
-        */
-       for (root = node; ! IS_ROOT(root); root = PARENT(root))
-               ; /* Nothing. */
+        /*
+         * Return the node in the level above the argument node that points
+         * to the level the argument node is in.  If the argument node is in
+         * the top level, the return value is NULL.
+         */
+        for (root = node; ! IS_ROOT(root); root = PARENT(root))
+                ; /* Nothing. */
 
-       return (PARENT(root));
+        return (PARENT(root));
 }
 
 /*
@@ -203,8 +204,8 @@ static inline void
 rotate_right(dns_rbtnode_t *node, dns_rbtnode_t **rootp);
 
 static void
-dns_rbt_addonlevel(dns_rbtnode_t *node, dns_rbtnode_t *current, int order, 
-                  dns_rbtnode_t **rootp);
+dns_rbt_addonlevel(dns_rbtnode_t *node, dns_rbtnode_t *current, int order,
+                   dns_rbtnode_t **rootp);
 
 static void
 dns_rbt_deletefromlevel(dns_rbtnode_t *delete, dns_rbtnode_t **rootp);
@@ -214,48 +215,50 @@ dns_rbt_deletetree(dns_rbt_t *rbt, dns_rbtnode_t *node);
 
 static void
 dns_rbt_deletetreeflat(dns_rbt_t *rbt, unsigned int quantum,
-                      dns_rbtnode_t **nodep);
+                       dns_rbtnode_t **nodep);
 
 /*
  * Initialize a red/black tree of trees.
  */
 isc_result_t
 dns_rbt_create(isc_mem_t *mctx, void (*deleter)(void *, void *),
-              void *deleter_arg, dns_rbt_t **rbtp)
+               void *deleter_arg, dns_rbt_t **rbtp)
 {
 #ifdef DNS_RBT_USEHASH
-       isc_result_t result;
+        isc_result_t result;
 #endif
-       dns_rbt_t *rbt;
-       
-
-       REQUIRE(mctx != NULL);
-       REQUIRE(rbtp != NULL && *rbtp == NULL);
-       REQUIRE(deleter == NULL ? deleter_arg == NULL : 1);
-
-       rbt = (dns_rbt_t *)isc_mem_get(mctx, sizeof(*rbt));
-       if (rbt == NULL)
-               return (ISC_R_NOMEMORY);
-
-       rbt->mctx = mctx;
-       rbt->data_deleter = deleter;
-       rbt->deleter_arg = deleter_arg;
-       rbt->root = NULL;
-       rbt->nodecount = 0;
-       rbt->hashtable = NULL;
-       rbt->hashsize = 0;
+        dns_rbt_t *rbt;
+
+
+        REQUIRE(mctx != NULL);
+        REQUIRE(rbtp != NULL && *rbtp == NULL);
+        REQUIRE(deleter == NULL ? deleter_arg == NULL : 1);
+
+        rbt = (dns_rbt_t *)isc_mem_get(mctx, sizeof(*rbt));
+        if (rbt == NULL)
+                return (ISC_R_NOMEMORY);
+
+        rbt->mctx = mctx;
+        rbt->data_deleter = deleter;
+        rbt->deleter_arg = deleter_arg;
+        rbt->root = NULL;
+        rbt->nodecount = 0;
+        rbt->hashtable = NULL;
+        rbt->hashsize = 0;
+
 #ifdef DNS_RBT_USEHASH
-       result = inithash(rbt);
-       if (result != ISC_R_SUCCESS) {
-               isc_mem_put(mctx, rbt, sizeof(*rbt));
-               return (result);
-       }
+        result = inithash(rbt);
+        if (result != ISC_R_SUCCESS) {
+                isc_mem_put(mctx, rbt, sizeof(*rbt));
+                return (result);
+        }
 #endif
-       rbt->magic = RBT_MAGIC;
 
-       *rbtp = rbt;
+        rbt->magic = RBT_MAGIC;
+
+        *rbtp = rbt;
 
-       return (ISC_R_SUCCESS);
+        return (ISC_R_SUCCESS);
 }
 
 /*
@@ -263,88 +266,88 @@ dns_rbt_create(isc_mem_t *mctx, void (*deleter)(void *, void *),
  */
 void
 dns_rbt_destroy(dns_rbt_t **rbtp) {
-       RUNTIME_CHECK(dns_rbt_destroy2(rbtp, 0) == ISC_R_SUCCESS);
+        RUNTIME_CHECK(dns_rbt_destroy2(rbtp, 0) == ISC_R_SUCCESS);
 }
 
 isc_result_t
 dns_rbt_destroy2(dns_rbt_t **rbtp, unsigned int quantum) {
-       dns_rbt_t *rbt;
+        dns_rbt_t *rbt;
 
-       REQUIRE(rbtp != NULL && VALID_RBT(*rbtp));
+        REQUIRE(rbtp != NULL && VALID_RBT(*rbtp));
 
-       rbt = *rbtp;
+        rbt = *rbtp;
 
-       dns_rbt_deletetreeflat(rbt, quantum, &rbt->root);
-       if (rbt->root != NULL)
-               return (ISC_R_QUOTA);
+        dns_rbt_deletetreeflat(rbt, quantum, &rbt->root);
+        if (rbt->root != NULL)
+                return (ISC_R_QUOTA);
 
-       INSIST(rbt->nodecount == 0);
+        INSIST(rbt->nodecount == 0);
 
-       if (rbt->hashtable != NULL)
-               isc_mem_put(rbt->mctx, rbt->hashtable,
-                           rbt->hashsize * sizeof(dns_rbtnode_t *));
+        if (rbt->hashtable != NULL)
+                isc_mem_put(rbt->mctx, rbt->hashtable,
+                            rbt->hashsize * sizeof(dns_rbtnode_t *));
 
-       rbt->magic = 0;
+        rbt->magic = 0;
 
-       isc_mem_put(rbt->mctx, rbt, sizeof(*rbt));
-       *rbtp = NULL;
-       return (ISC_R_SUCCESS);
+        isc_mem_put(rbt->mctx, rbt, sizeof(*rbt));
+        *rbtp = NULL;
+        return (ISC_R_SUCCESS);
 }
 
 unsigned int
 dns_rbt_nodecount(dns_rbt_t *rbt) {
-       REQUIRE(VALID_RBT(rbt));
-       return (rbt->nodecount);
+        REQUIRE(VALID_RBT(rbt));
+        return (rbt->nodecount);
 }
 
 static inline isc_result_t
 chain_name(dns_rbtnodechain_t *chain, dns_name_t *name,
-          isc_boolean_t include_chain_end)
+           isc_boolean_t include_chain_end)
 {
-       dns_name_t nodename;
-       isc_result_t result = ISC_R_SUCCESS;
-       int i;
-
-       dns_name_init(&nodename, NULL);
-
-       if (include_chain_end && chain->end != NULL) {
-               NODENAME(chain->end, &nodename);
-               result = dns_name_copy(&nodename, name, NULL);
-               if (result != ISC_R_SUCCESS)
-                       return (result);
-       } else
-               dns_name_reset(name);
-
-       for (i = (int)chain->level_count - 1; i >= 0; i--) {
-               NODENAME(chain->levels[i], &nodename);
-               result = dns_name_concatenate(name, &nodename, name, NULL);
-
-               if (result != ISC_R_SUCCESS)
-                       return (result);
-       }
-       return (result);
+        dns_name_t nodename;
+        isc_result_t result = ISC_R_SUCCESS;
+        int i;
+
+        dns_name_init(&nodename, NULL);
+
+        if (include_chain_end && chain->end != NULL) {
+                NODENAME(chain->end, &nodename);
+                result = dns_name_copy(&nodename, name, NULL);
+                if (result != ISC_R_SUCCESS)
+                        return (result);
+        } else
+                dns_name_reset(name);
+
+        for (i = (int)chain->level_count - 1; i >= 0; i--) {
+                NODENAME(chain->levels[i], &nodename);
+                result = dns_name_concatenate(name, &nodename, name, NULL);
+
+                if (result != ISC_R_SUCCESS)
+                        return (result);
+        }
+        return (result);
 }
 
 static inline isc_result_t
 move_chain_to_last(dns_rbtnodechain_t *chain, dns_rbtnode_t *node) {
-       do {
-               /*
-                * Go as far right and then down as much as possible,
-                * as long as the rightmost node has a down pointer.
-                */
-               while (RIGHT(node) != NULL)
-                       node = RIGHT(node);
+        do {
+                /*
+                 * Go as far right and then down as much as possible,
+                 * as long as the rightmost node has a down pointer.
+                 */
+                while (RIGHT(node) != NULL)
+                        node = RIGHT(node);
 
-               if (DOWN(node) == NULL)
-                       break;
+                if (DOWN(node) == NULL)
+                        break;
 
-               ADD_LEVEL(chain, node);
-               node = DOWN(node);
-       } while (1);
+                ADD_LEVEL(chain, node);
+                node = DOWN(node);
+        } while (1);
 
-       chain->end = node;
+        chain->end = node;
 
-       return (ISC_R_SUCCESS);
+        return (ISC_R_SUCCESS);
 }
 
 /*
@@ -353,281 +356,281 @@ move_chain_to_last(dns_rbtnodechain_t *chain, dns_rbtnode_t *node) {
 
 isc_result_t
 dns_rbt_addnode(dns_rbt_t *rbt, dns_name_t *name, dns_rbtnode_t **nodep) {
-       /*
-        * Does this thing have too many variables or what?
-        */
-       dns_rbtnode_t **root, *parent, *child, *current, *new_current;
-       dns_name_t *add_name, *new_name, current_name, *prefix, *suffix;
-       dns_fixedname_t fixedcopy, fixedprefix, fixedsuffix, fnewname;
-       dns_offsets_t current_offsets;
-       dns_namereln_t compared;
-       isc_result_t result = ISC_R_SUCCESS;
-       dns_rbtnodechain_t chain;
-       unsigned int common_labels;
-       unsigned int nlabels, hlabels;
-       int order;
-
-       REQUIRE(VALID_RBT(rbt));
-       REQUIRE(dns_name_isabsolute(name));
-       REQUIRE(nodep != NULL && *nodep == NULL);
-
-       /*
-        * Create a copy of the name so the original name structure is
-        * not modified.
-        */
-       dns_fixedname_init(&fixedcopy);
-       add_name = dns_fixedname_name(&fixedcopy);
-       dns_name_clone(name, add_name);
-
-       if (rbt->root == NULL) {
-               result = create_node(rbt->mctx, add_name, &new_current);
-               if (result == ISC_R_SUCCESS) {
-                       rbt->nodecount++;
-                       new_current->is_root = 1;
-                       rbt->root = new_current;
-                       *nodep = new_current;
-                       hash_node(rbt, new_current, name);
-               }
-               return (result);
-       }
-
-       dns_rbtnodechain_init(&chain, rbt->mctx);
-
-       dns_fixedname_init(&fixedprefix);
-       dns_fixedname_init(&fixedsuffix);
-       prefix = dns_fixedname_name(&fixedprefix);
-       suffix = dns_fixedname_name(&fixedsuffix);
-
-       root = &rbt->root;
-       INSIST(IS_ROOT(*root));
-       parent = NULL;
-       current = NULL;
-       child = *root;
-       dns_name_init(&current_name, current_offsets);
-       dns_fixedname_init(&fnewname);
-       new_name = dns_fixedname_name(&fnewname);
-       nlabels = dns_name_countlabels(name);
-       hlabels = 0;
-
-       do {
-               current = child;
-
-               NODENAME(current, &current_name);
-               compared = dns_name_fullcompare(add_name, &current_name,
-                                               &order, &common_labels);
-
-               if (compared == dns_namereln_equal) {
-                       *nodep = current;
-                       result = ISC_R_EXISTS;
-                       break;
-
-               }
-
-               if (compared == dns_namereln_none) {
-
-                       if (order < 0) {
-                               parent = current;
-                               child = LEFT(current);
-
-                       } else if (order > 0) {
-                               parent = current;
-                               child = RIGHT(current);
-
-                       }
-
-               } else {
-                       /*
-                        * This name has some suffix in common with the
-                        * name at the current node.  If the name at
-                        * the current node is shorter, that means the
-                        * new name should be in a subtree.  If the
-                        * name at the current node is longer, that means
-                        * the down pointer to this tree should point
-                        * to a new tree that has the common suffix, and
-                        * the non-common parts of these two names should
-                        * start a new tree.
-                        */
-                       hlabels += common_labels;
-                       if (compared == dns_namereln_subdomain) {
-                               /*
-                                * All of the existing labels are in common,
-                                * so the new name is in a subtree.
-                                * Whack off the common labels for the
-                                * not-in-common part to be searched for
-                                * in the next level.
-                                */
-                               dns_name_split(add_name, common_labels,
-                                              add_name, NULL);
-
-                               /*
-                                * Follow the down pointer (possibly NULL).
-                                */
-                               root = &DOWN(current);
-
-                               INSIST(*root == NULL ||
-                                      (IS_ROOT(*root) &&
-                                       PARENT(*root) == current));
-
-                               parent = NULL;
-                               child = DOWN(current);
-                               ADD_LEVEL(&chain, current);
-
-                       } else {
-                               /*
-                                * The number of labels in common is fewer
-                                * than the number of labels at the current
-                                * node, so the current node must be adjusted
-                                * to have just the common suffix, and a down
-                                * pointer made to a new tree.
-                                */
-
-                               INSIST(compared == dns_namereln_commonancestor
-                                      || compared == dns_namereln_contains);
-
-                               /*
-                                * Ensure the number of levels in the tree
-                                * does not exceed the number of logical
-                                * levels allowed by DNSSEC.
-                                *
-                                * XXXDCL need a better error result?
-                                *
-                                * XXXDCL Since chain ancestors were removed,
-                                * no longer used by dns_rbt_addonlevel(),
-                                * this is the only real use of chains in the
-                                * function.  It could be done instead with
-                                * a simple integer variable, but I am pressed
-                                * for time.
-                                */
-                               if (chain.level_count ==
-                                   (sizeof(chain.levels) /
-                                    sizeof(*chain.levels))) {
-                                       result = ISC_R_NOSPACE;
-                                       break;
-                               }
-
-                               /*
-                                * Split the name into two parts, a prefix
-                                * which is the not-in-common parts of the
-                                * two names and a suffix that is the common
-                                * parts of them.
-                                */
-                               dns_name_split(&current_name, common_labels,
-                                              prefix, suffix);
-                               result = create_node(rbt->mctx, suffix,
-                                                    &new_current);
-
-                               if (result != ISC_R_SUCCESS)
-                                       break;
-
-                               /*
-                                * Reproduce the tree attributes of the
-                                * current node.
-                                */
-                               new_current->is_root = current->is_root;
-                               PARENT(new_current)  = PARENT(current);
-                               LEFT(new_current)    = LEFT(current);
-                               RIGHT(new_current)   = RIGHT(current);
-                               COLOR(new_current)   = COLOR(current);
-
-                               /*
-                                * Fix pointers that were to the current node.
-                                */
-                               if (parent != NULL) {
-                                       if (LEFT(parent) == current)
-                                               LEFT(parent) = new_current;
-                                       else
-                                               RIGHT(parent) = new_current;
-                               }
-                               if (LEFT(new_current) != NULL)
-                                       PARENT(LEFT(new_current)) =
-                                               new_current;
-                               if (RIGHT(new_current) != NULL)
-                                       PARENT(RIGHT(new_current)) =
-                                               new_current;
-                               if (*root == current)
-                                       *root = new_current;
-
-                               NAMELEN(current) = prefix->length;
-                               OFFSETLEN(current) = prefix->labels;
-                               memcpy(OFFSETS(current), prefix->offsets,
-                                      prefix->labels);
-                               PADBYTES(current) +=
-                                      (current_name.length - prefix->length) +
-                                      (current_name.labels - prefix->labels);
-
-                               /*
-                                * Set up the new root of the next level.
-                                * By definition it will not be the top
-                                * level tree, so clear DNS_NAMEATTR_ABSOLUTE.
-                                */
-                               current->is_root = 1;
-                               PARENT(current) = new_current;
-                               DOWN(new_current) = current;
-                               root = &DOWN(new_current);
-
-                               ADD_LEVEL(&chain, new_current);
-
-                               LEFT(current) = NULL;
-                               RIGHT(current) = NULL;
-
-                               MAKE_BLACK(current);
-                               ATTRS(current) &= ~DNS_NAMEATTR_ABSOLUTE;
-
-                               rbt->nodecount++;
-                               dns_name_getlabelsequence(name,
-                                                         nlabels - hlabels,
-                                                         hlabels, new_name);
-                               hash_node(rbt, new_current, new_name);
-
-                               if (common_labels ==
-                                   dns_name_countlabels(add_name)) {
-                                       /*
-                                        * The name has been added by pushing
-                                        * the not-in-common parts down to
-                                        * a new level.
-                                        */
-                                       *nodep = new_current;
-                                       return (ISC_R_SUCCESS);
-
-                               } else {
-                                       /*
-                                        * The current node has no data,
-                                        * because it is just a placeholder.
-                                        * Its data pointer is already NULL
-                                        * from create_node()), so there's
-                                        * nothing more to do to it.
-                                        */
-
-                                       /*
-                                        * The not-in-common parts of the new
-                                        * name will be inserted into the new
-                                        * level following this loop (unless
-                                        * result != ISC_R_SUCCESS, which
-                                        * is tested after the loop ends).
-                                        */
-                                       dns_name_split(add_name, common_labels,
-                                                      add_name, NULL);
-
-                                       break;
-                               }
-
-                       }
-
-               }
-
-       } while (child != NULL);
-
-       if (result == ISC_R_SUCCESS)
-               result = create_node(rbt->mctx, add_name, &new_current);
-
-       if (result == ISC_R_SUCCESS) {
-               dns_rbt_addonlevel(new_current, current, order, root);
-               rbt->nodecount++;
-               *nodep = new_current;
-               hash_node(rbt, new_current, name);
-       }
-
-       return (result);
+        /*
+         * Does this thing have too many variables or what?
+         */
+        dns_rbtnode_t **root, *parent, *child, *current, *new_current;
+        dns_name_t *add_name, *new_name, current_name, *prefix, *suffix;
+        dns_fixedname_t fixedcopy, fixedprefix, fixedsuffix, fnewname;
+        dns_offsets_t current_offsets;
+        dns_namereln_t compared;
+        isc_result_t result = ISC_R_SUCCESS;
+        dns_rbtnodechain_t chain;
+        unsigned int common_labels;
+        unsigned int nlabels, hlabels;
+        int order;
+
+        REQUIRE(VALID_RBT(rbt));
+        REQUIRE(dns_name_isabsolute(name));
+        REQUIRE(nodep != NULL && *nodep == NULL);
+
+        /*
+         * Create a copy of the name so the original name structure is
+         * not modified.
+         */
+        dns_fixedname_init(&fixedcopy);
+        add_name = dns_fixedname_name(&fixedcopy);
+        dns_name_clone(name, add_name);
+
+        if (rbt->root == NULL) {
+                result = create_node(rbt->mctx, add_name, &new_current);
+                if (result == ISC_R_SUCCESS) {
+                        rbt->nodecount++;
+                        new_current->is_root = 1;
+                        rbt->root = new_current;
+                        *nodep = new_current;
+                        hash_node(rbt, new_current, name);
+                }
+                return (result);
+        }
+
+        dns_rbtnodechain_init(&chain, rbt->mctx);
+
+        dns_fixedname_init(&fixedprefix);
+        dns_fixedname_init(&fixedsuffix);
+        prefix = dns_fixedname_name(&fixedprefix);
+        suffix = dns_fixedname_name(&fixedsuffix);
+
+        root = &rbt->root;
+        INSIST(IS_ROOT(*root));
+        parent = NULL;
+        current = NULL;
+        child = *root;
+        dns_name_init(&current_name, current_offsets);
+        dns_fixedname_init(&fnewname);
+        new_name = dns_fixedname_name(&fnewname);
+        nlabels = dns_name_countlabels(name);
+        hlabels = 0;
+
+        do {
+                current = child;
+
+                NODENAME(current, &current_name);
+                compared = dns_name_fullcompare(add_name, &current_name,
+                                                &order, &common_labels);
+
+                if (compared == dns_namereln_equal) {
+                        *nodep = current;
+                        result = ISC_R_EXISTS;
+                        break;
+
+                }
+
+                if (compared == dns_namereln_none) {
+
+                        if (order < 0) {
+                                parent = current;
+                                child = LEFT(current);
+
+                        } else if (order > 0) {
+                                parent = current;
+                                child = RIGHT(current);
+
+                        }
+
+                } else {
+                        /*
+                         * This name has some suffix in common with the
+                         * name at the current node.  If the name at
+                         * the current node is shorter, that means the
+                         * new name should be in a subtree.  If the
+                         * name at the current node is longer, that means
+                         * the down pointer to this tree should point
+                         * to a new tree that has the common suffix, and
+                         * the non-common parts of these two names should
+                         * start a new tree.
+                         */
+                        hlabels += common_labels;
+                        if (compared == dns_namereln_subdomain) {
+                                /*
+                                 * All of the existing labels are in common,
+                                 * so the new name is in a subtree.
+                                 * Whack off the common labels for the
+                                 * not-in-common part to be searched for
+                                 * in the next level.
+                                 */
+                                dns_name_split(add_name, common_labels,
+                                               add_name, NULL);
+
+                                /*
+                                 * Follow the down pointer (possibly NULL).
+                                 */
+                                root = &DOWN(current);
+
+                                INSIST(*root == NULL ||
+                                       (IS_ROOT(*root) &&
+                                        PARENT(*root) == current));
+
+                                parent = NULL;
+                                child = DOWN(current);
+                                ADD_LEVEL(&chain, current);
+
+                        } else {
+                                /*
+                                 * The number of labels in common is fewer
+                                 * than the number of labels at the current
+                                 * node, so the current node must be adjusted
+                                 * to have just the common suffix, and a down
+                                 * pointer made to a new tree.
+                                 */
+
+                                INSIST(compared == dns_namereln_commonancestor
+                                       || compared == dns_namereln_contains);
+
+                                /*
+                                 * Ensure the number of levels in the tree
+                                 * does not exceed the number of logical
+                                 * levels allowed by DNSSEC.
+                                 *
+                                 * XXXDCL need a better error result?
+                                 *
+                                 * XXXDCL Since chain ancestors were removed,
+                                 * no longer used by dns_rbt_addonlevel(),
+                                 * this is the only real use of chains in the
+                                 * function.  It could be done instead with
+                                 * a simple integer variable, but I am pressed
+                                 * for time.
+                                 */
+                                if (chain.level_count ==
+                                    (sizeof(chain.levels) /
+                                     sizeof(*chain.levels))) {
+                                        result = ISC_R_NOSPACE;
+                                        break;
+                                }
+
+                                /*
+                                 * Split the name into two parts, a prefix
+                                 * which is the not-in-common parts of the
+                                 * two names and a suffix that is the common
+                                 * parts of them.
+                                 */
+                                dns_name_split(&current_name, common_labels,
+                                               prefix, suffix);
+                                result = create_node(rbt->mctx, suffix,
+                                                     &new_current);
+
+                                if (result != ISC_R_SUCCESS)
+                                        break;
+
+                                /*
+                                 * Reproduce the tree attributes of the
+                                 * current node.
+                                 */
+                                new_current->is_root = current->is_root;
+                                PARENT(new_current)  = PARENT(current);
+                                LEFT(new_current)    = LEFT(current);
+                                RIGHT(new_current)   = RIGHT(current);
+                                COLOR(new_current)   = COLOR(current);
+
+                                /*
+                                 * Fix pointers that were to the current node.
+                                 */
+                                if (parent != NULL) {
+                                        if (LEFT(parent) == current)
+                                                LEFT(parent) = new_current;
+                                        else
+                                                RIGHT(parent) = new_current;
+                                }
+                                if (LEFT(new_current) != NULL)
+                                        PARENT(LEFT(new_current)) =
+                                                new_current;
+                                if (RIGHT(new_current) != NULL)
+                                        PARENT(RIGHT(new_current)) =
+                                                new_current;
+                                if (*root == current)
+                                        *root = new_current;
+
+                                NAMELEN(current) = prefix->length;
+                                OFFSETLEN(current) = prefix->labels;
+                                memcpy(OFFSETS(current), prefix->offsets,
+                                       prefix->labels);
+                                PADBYTES(current) +=
+                                       (current_name.length - prefix->length) +
+                                       (current_name.labels - prefix->labels);
+
+                                /*
+                                 * Set up the new root of the next level.
+                                 * By definition it will not be the top
+                                 * level tree, so clear DNS_NAMEATTR_ABSOLUTE.
+                                 */
+                                current->is_root = 1;
+                                PARENT(current) = new_current;
+                                DOWN(new_current) = current;
+                                root = &DOWN(new_current);
+
+                                ADD_LEVEL(&chain, new_current);
+
+                                LEFT(current) = NULL;
+                                RIGHT(current) = NULL;
+
+                                MAKE_BLACK(current);
+                                ATTRS(current) &= ~DNS_NAMEATTR_ABSOLUTE;
+
+                                rbt->nodecount++;
+                                dns_name_getlabelsequence(name,
+                                                          nlabels - hlabels,
+                                                          hlabels, new_name);
+                                hash_node(rbt, new_current, new_name);
+
+                                if (common_labels ==
+                                    dns_name_countlabels(add_name)) {
+                                        /*
+                                         * The name has been added by pushing
+                                         * the not-in-common parts down to
+                                         * a new level.
+                                         */
+                                        *nodep = new_current;
+                                        return (ISC_R_SUCCESS);
+
+                                } else {
+                                        /*
+                                         * The current node has no data,
+                                         * because it is just a placeholder.
+                                         * Its data pointer is already NULL
+                                         * from create_node()), so there's
+                                         * nothing more to do to it.
+                                         */
+
+                                        /*
+                                         * The not-in-common parts of the new
+                                         * name will be inserted into the new
+                                         * level following this loop (unless
+                                         * result != ISC_R_SUCCESS, which
+                                         * is tested after the loop ends).
+                                         */
+                                        dns_name_split(add_name, common_labels,
+                                                       add_name, NULL);
+
+                                        break;
+                                }
+
+                        }
+
+                }
+
+        } while (child != NULL);
+
+        if (result == ISC_R_SUCCESS)
+                result = create_node(rbt->mctx, add_name, &new_current);
+
+        if (result == ISC_R_SUCCESS) {
+                dns_rbt_addonlevel(new_current, current, order, root);
+                rbt->nodecount++;
+                *nodep = new_current;
+                hash_node(rbt, new_current, name);
+        }
+
+        return (result);
 }
 
 /*
@@ -635,29 +638,29 @@ dns_rbt_addnode(dns_rbt_t *rbt, dns_name_t *name, dns_rbtnode_t **nodep) {
  */
 isc_result_t
 dns_rbt_addname(dns_rbt_t *rbt, dns_name_t *name, void *data) {
-       isc_result_t result;
-       dns_rbtnode_t *node;
+        isc_result_t result;
+        dns_rbtnode_t *node;
 
-       REQUIRE(VALID_RBT(rbt));
-       REQUIRE(dns_name_isabsolute(name));
+        REQUIRE(VALID_RBT(rbt));
+        REQUIRE(dns_name_isabsolute(name));
 
-       node = NULL;
+        node = NULL;
 
-       result = dns_rbt_addnode(rbt, name, &node);
+        result = dns_rbt_addnode(rbt, name, &node);
 
-       /*
-        * dns_rbt_addnode will report the node exists even when
-        * it does not have data associated with it, but the
-        * dns_rbt_*name functions all behave depending on whether
-        * there is data associated with a node.
-        */
-       if (result == ISC_R_SUCCESS ||
-           (result == ISC_R_EXISTS && DATA(node) == NULL)) {
-               DATA(node) = data;
-               result = ISC_R_SUCCESS;
-       }
+        /*
+         * dns_rbt_addnode will report the node exists even when
+         * it does not have data associated with it, but the
+         * dns_rbt_*name functions all behave depending on whether
+         * there is data associated with a node.
+         */
+        if (result == ISC_R_SUCCESS ||
+            (result == ISC_R_EXISTS && DATA(node) == NULL)) {
+                DATA(node) = data;
+                result = ISC_R_SUCCESS;
+        }
 
-       return (result);
+        return (result);
 }
 
 /*
@@ -665,500 +668,500 @@ dns_rbt_addname(dns_rbt_t *rbt, dns_name_t *name, void *data) {
  */
 isc_result_t
 dns_rbt_findnode(dns_rbt_t *rbt, dns_name_t *name, dns_name_t *foundname,
-                dns_rbtnode_t **node, dns_rbtnodechain_t *chain,
-                unsigned int options, dns_rbtfindcallback_t callback,
-                void *callback_arg)
+                 dns_rbtnode_t **node, dns_rbtnodechain_t *chain,
+                 unsigned int options, dns_rbtfindcallback_t callback,
+                 void *callback_arg)
 {
-       dns_rbtnode_t *current, *last_compared, *current_root;
-       dns_rbtnodechain_t localchain;
-       dns_name_t *search_name, current_name, *callback_name;
-       dns_fixedname_t fixedcallbackname, fixedsearchname;
-       dns_namereln_t compared;
-       isc_result_t result, saved_result;
-       unsigned int common_labels;
-       unsigned int hlabels = 0;
-       int order;
-
-       REQUIRE(VALID_RBT(rbt));
-       REQUIRE(dns_name_isabsolute(name));
-       REQUIRE(node != NULL && *node == NULL);
-       REQUIRE((options & (DNS_RBTFIND_NOEXACT | DNS_RBTFIND_NOPREDECESSOR))
-               !=         (DNS_RBTFIND_NOEXACT | DNS_RBTFIND_NOPREDECESSOR));
-
-       /*
-        * If there is a chain it needs to appear to be in a sane state,
-        * otherwise a chain is still needed to generate foundname and
-        * callback_name.
-        */
-       if (chain == NULL) {
-               options |= DNS_RBTFIND_NOPREDECESSOR;
-               chain = &localchain;
-               dns_rbtnodechain_init(chain, rbt->mctx);
-       } else
-               dns_rbtnodechain_reset(chain);
-
-       if (rbt->root == NULL)
-               return (ISC_R_NOTFOUND);
-       else {
-               /*
-                * Appease GCC about variables it incorrectly thinks are
-                * possibly used uninitialized.
-                */
-               compared = dns_namereln_none;
-               last_compared = NULL;
-       }
-
-       dns_fixedname_init(&fixedcallbackname);
-       callback_name = dns_fixedname_name(&fixedcallbackname);
-
-       /*
-        * search_name is the name segment being sought in each tree level.
-        * By using a fixedname, the search_name will definitely have offsets
-        * for use by any splitting.
-        * By using dns_name_clone, no name data should be copied thanks to
-        * the lack of bitstring labels.
-        */
-       dns_fixedname_init(&fixedsearchname);
-       search_name = dns_fixedname_name(&fixedsearchname);
-       dns_name_clone(name, search_name);
-
-       dns_name_init(&current_name, NULL);
-
-       saved_result = ISC_R_SUCCESS;
-       current = rbt->root;
-       current_root = rbt->root;
-
-       while (current != NULL) {
-               NODENAME(current, &current_name);
-               compared = dns_name_fullcompare(search_name, &current_name,
-                                               &order, &common_labels);
-               last_compared = current;
-
-               if (compared == dns_namereln_equal)
-                       break;
-
-               if (compared == dns_namereln_none) {
+        dns_rbtnode_t *current, *last_compared, *current_root;
+        dns_rbtnodechain_t localchain;
+        dns_name_t *search_name, current_name, *callback_name;
+        dns_fixedname_t fixedcallbackname, fixedsearchname;
+        dns_namereln_t compared;
+        isc_result_t result, saved_result;
+        unsigned int common_labels;
+        unsigned int hlabels = 0;
+        int order;
+
+        REQUIRE(VALID_RBT(rbt));
+        REQUIRE(dns_name_isabsolute(name));
+        REQUIRE(node != NULL && *node == NULL);
+        REQUIRE((options & (DNS_RBTFIND_NOEXACT | DNS_RBTFIND_NOPREDECESSOR))
+                !=         (DNS_RBTFIND_NOEXACT | DNS_RBTFIND_NOPREDECESSOR));
+
+        /*
+         * If there is a chain it needs to appear to be in a sane state,
+         * otherwise a chain is still needed to generate foundname and
+         * callback_name.
+         */
+        if (chain == NULL) {
+                options |= DNS_RBTFIND_NOPREDECESSOR;
+                chain = &localchain;
+                dns_rbtnodechain_init(chain, rbt->mctx);
+        } else
+                dns_rbtnodechain_reset(chain);
+
+        if (rbt->root == NULL)
+                return (ISC_R_NOTFOUND);
+        else {
+                /*
+                 * Appease GCC about variables it incorrectly thinks are
+                 * possibly used uninitialized.
+                 */
+                compared = dns_namereln_none;
+                last_compared = NULL;
+        }
+
+        dns_fixedname_init(&fixedcallbackname);
+        callback_name = dns_fixedname_name(&fixedcallbackname);
+
+        /*
+         * search_name is the name segment being sought in each tree level.
+         * By using a fixedname, the search_name will definitely have offsets
+         * for use by any splitting.
+         * By using dns_name_clone, no name data should be copied thanks to
+         * the lack of bitstring labels.
+         */
+        dns_fixedname_init(&fixedsearchname);
+        search_name = dns_fixedname_name(&fixedsearchname);
+        dns_name_clone(name, search_name);
+
+        dns_name_init(&current_name, NULL);
+
+        saved_result = ISC_R_SUCCESS;
+        current = rbt->root;
+        current_root = rbt->root;
+
+        while (current != NULL) {
+                NODENAME(current, &current_name);
+                compared = dns_name_fullcompare(search_name, &current_name,
+                                                &order, &common_labels);
+                last_compared = current;
+
+                if (compared == dns_namereln_equal)
+                        break;
+
+                if (compared == dns_namereln_none) {
 #ifdef DNS_RBT_USEHASH
-                       dns_name_t hash_name;
-                       dns_rbtnode_t *hnode;
-                       dns_rbtnode_t *up_current;
-                       unsigned int nlabels;
-                       unsigned int tlabels = 1;
-                       unsigned int hash;
-
-                       /*
-                        * If there is no hash table, hashing can't be done.
-                        */
-                       if (rbt->hashtable == NULL)
-                               goto nohash;
-
-                       /*
-                        * The case of current != current_root, that
-                        * means a left or right pointer was followed,
-                        * only happens when the algorithm fell through to
-                        * the traditional binary search because of a
-                        * bitstring label.  Since we dropped the bitstring
-                        * support, this should not happen.
-                        */
-                       INSIST(current == current_root);
-
-                       nlabels = dns_name_countlabels(search_name);
-
-                       /*
-                        * current_root is the root of the current level, so
-                        * it's parent is the same as it's "up" pointer.
-                        */
-                       up_current = PARENT(current_root);
-                       dns_name_init(&hash_name, NULL);
-
-               hashagain:
-                       /* 
-                        * Hash includes tail.
-                        */
-                       dns_name_getlabelsequence(name,
-                                                 nlabels - tlabels,
-                                                 hlabels + tlabels,
-                                                 &hash_name);
-                       hash = dns_name_fullhash(&hash_name, ISC_FALSE);
-                       dns_name_getlabelsequence(search_name,
-                                                 nlabels - tlabels,
-                                                 tlabels, &hash_name);
-
-                       for (hnode = rbt->hashtable[hash % rbt->hashsize];
-                            hnode != NULL;
-                            hnode = hnode->hashnext)
-                       {
-                               dns_name_t hnode_name;
-
-                               if (hash != HASHVAL(hnode))
-                                       continue;
-                               if (find_up(hnode) != up_current)
-                                       continue;
-                               dns_name_init(&hnode_name, NULL);
-                               NODENAME(hnode, &hnode_name);
-                               if (dns_name_equal(&hnode_name, &hash_name))
-                                       break;
-                       }
-
-                       if (hnode != NULL) {
-                               current = hnode;
-                               /*
-                                * This is an optimization.  If hashing found
-                                * the right node, the next call to
-                                * dns_name_fullcompare() would obviously
-                                * return _equal or _subdomain.  Determine
-                                * which of those would be the case by
-                                * checking if the full name was hashed.  Then
-                                * make it look like dns_name_fullcompare
-                                * was called and jump to the right place.
-                                */
-                               if (tlabels == nlabels) {
-                                       compared = dns_namereln_equal;
-                                       break;
-                               } else {
-                                       common_labels = tlabels;
-                                       compared = dns_namereln_subdomain;
-                                       goto subdomain;
-                               }
-                       }
-
-                       if (tlabels++ < nlabels)
-                               goto hashagain;
-
-                       /*
-                        * All of the labels have been tried against the hash
-                        * table.  Since we dropped the support of bitstring
-                        * labels, the name isn't in the table.
-                        */
-                       current = NULL;
-                       continue;
-                           
-               nohash:
+                        dns_name_t hash_name;
+                        dns_rbtnode_t *hnode;
+                        dns_rbtnode_t *up_current;
+                        unsigned int nlabels;
+                        unsigned int tlabels = 1;
+                        unsigned int hash;
+
+                        /*
+                         * If there is no hash table, hashing can't be done.
+                         */
+                        if (rbt->hashtable == NULL)
+                                goto nohash;
+
+                        /*
+                         * The case of current != current_root, that
+                         * means a left or right pointer was followed,
+                         * only happens when the algorithm fell through to
+                         * the traditional binary search because of a
+                         * bitstring label.  Since we dropped the bitstring
+                         * support, this should not happen.
+                         */
+                        INSIST(current == current_root);
+
+                        nlabels = dns_name_countlabels(search_name);
+
+                        /*
+                         * current_root is the root of the current level, so
+                         * it's parent is the same as it's "up" pointer.
+                         */
+                        up_current = PARENT(current_root);
+                        dns_name_init(&hash_name, NULL);
+
+                hashagain:
+                        /*
+                         * Hash includes tail.
+                         */
+                        dns_name_getlabelsequence(name,
+                                                  nlabels - tlabels,
+                                                  hlabels + tlabels,
+                                                  &hash_name);
+                        hash = dns_name_fullhash(&hash_name, ISC_FALSE);
+                        dns_name_getlabelsequence(search_name,
+                                                  nlabels - tlabels,
+                                                  tlabels, &hash_name);
+
+                        for (hnode = rbt->hashtable[hash % rbt->hashsize];
+                             hnode != NULL;
+                             hnode = hnode->hashnext)
+                        {
+                                dns_name_t hnode_name;
+
+                                if (hash != HASHVAL(hnode))
+                                        continue;
+                                if (find_up(hnode) != up_current)
+                                        continue;
+                                dns_name_init(&hnode_name, NULL);
+                                NODENAME(hnode, &hnode_name);
+                                if (dns_name_equal(&hnode_name, &hash_name))
+                                        break;
+                        }
+
+                        if (hnode != NULL) {
+                                current = hnode;
+                                /*
+                                 * This is an optimization.  If hashing found
+                                 * the right node, the next call to
+                                 * dns_name_fullcompare() would obviously
+                                 * return _equal or _subdomain.  Determine
+                                 * which of those would be the case by
+                                 * checking if the full name was hashed.  Then
+                                 * make it look like dns_name_fullcompare
+                                 * was called and jump to the right place.
+                                 */
+                                if (tlabels == nlabels) {
+                                        compared = dns_namereln_equal;
+                                        break;
+                                } else {
+                                        common_labels = tlabels;
+                                        compared = dns_namereln_subdomain;
+                                        goto subdomain;
+                                }
+                        }
+
+                        if (tlabels++ < nlabels)
+                                goto hashagain;
+
+                        /*
+                         * All of the labels have been tried against the hash
+                         * table.  Since we dropped the support of bitstring
+                         * labels, the name isn't in the table.
+                         */
+                        current = NULL;
+                        continue;
+
+                nohash:
 #endif /* DNS_RBT_USEHASH */
-                       /*
-                        * Standard binary search tree movement.
-                        */
-                       if (order < 0)
-                               current = LEFT(current);
-                       else
-                               current = RIGHT(current);
-
-               } else {
-                       /*
-                        * The names have some common suffix labels.
-                        *
-                        * If the number in common are equal in length to
-                        * the current node's name length, then follow the
-                        * down pointer and search in the new tree.
-                        */
-                       if (compared == dns_namereln_subdomain) {
-               subdomain:
-                               /*
-                                * Whack off the current node's common parts
-                                * for the name to search in the next level.
-                                */
-                               dns_name_split(search_name, common_labels,
-                                              search_name, NULL);
-                               hlabels += common_labels;
-                               /*
-                                * This might be the closest enclosing name.
-                                */
-                               if (DATA(current) != NULL ||
-                                   (options & DNS_RBTFIND_EMPTYDATA) != 0)
-                                       *node = current;
-
-                               /*
-                                * Point the chain to the next level.   This
-                                * needs to be done before 'current' is pointed
-                                * there because the callback in the next
-                                * block of code needs the current 'current',
-                                * but in the event the callback requests that
-                                * the search be stopped then the
-                                * DNS_R_PARTIALMATCH code at the end of this
-                                * function needs the chain pointed to the
-                                * next level.
-                                */
-                               ADD_LEVEL(chain, current);
-
-                               /*
-                                * The caller may want to interrupt the
-                                * downward search when certain special nodes
-                                * are traversed.  If this is a special node,
-                                * the callback is used to learn what the
-                                * caller wants to do.
-                                */
-                               if (callback != NULL &&
-                                   FINDCALLBACK(current)) {
-                                       result = chain_name(chain,
-                                                           callback_name,
-                                                           ISC_FALSE);
-                                       if (result != ISC_R_SUCCESS) {
-                                               dns_rbtnodechain_reset(chain);
-                                               return (result);
-                                       }
-
-                                       result = (callback)(current,
-                                                           callback_name,
-                                                           callback_arg);
-                                       if (result != DNS_R_CONTINUE) {
-                                               saved_result = result;
-                                               /*
-                                                * Treat this node as if it
-                                                * had no down pointer.
-                                                */
-                                               current = NULL;
-                                               break;
-                                       }
-                               }
-
-                               /*
-                                * Finally, head to the next tree level.
-                                */
-                               current = DOWN(current);
-                               current_root = current;
-
-                       } else {
-                               /*
-                                * Though there are labels in common, the
-                                * entire name at this node is not common
-                                * with the search name so the search
-                                * name does not exist in the tree.
-                                */
-                               INSIST(compared == dns_namereln_commonancestor
-                                      || compared == dns_namereln_contains);
-
-                               current = NULL;
-                       }
-               }
-       }
-
-       /*
-        * If current is not NULL, NOEXACT is not disallowing exact matches,
-        * and either the node has data or an empty node is ok, return
-        * ISC_R_SUCCESS to indicate an exact match.
-        */
-       if (current != NULL && (options & DNS_RBTFIND_NOEXACT) == 0 &&
-           (DATA(current) != NULL ||
-            (options & DNS_RBTFIND_EMPTYDATA) != 0)) {
-               /*
-                * Found an exact match.
-                */
-               chain->end = current;
-               chain->level_matches = chain->level_count;
-
-               if (foundname != NULL)
-                       result = chain_name(chain, foundname, ISC_TRUE);
-               else
-                       result = ISC_R_SUCCESS;
-
-               if (result == ISC_R_SUCCESS) {
-                       *node = current;
-                       result = saved_result;
-               } else
-                       *node = NULL;
-       } else {
-               /*
-                * Did not find an exact match (or did not want one).
-                */
-               if (*node != NULL) {
-                       /*
-                        * ... but found a partially matching superdomain.
-                        * Unwind the chain to the partial match node
-                        * to set level_matches to the level above the node,
-                        * and then to derive the name.
-                        *
-                        * chain->level_count is guaranteed to be at least 1
-                        * here because by definition of finding a superdomain,
-                        * the chain is pointed to at least the first subtree.
-                        */
-                       chain->level_matches = chain->level_count - 1;
-
-                       while (chain->levels[chain->level_matches] != *node) {
-                               INSIST(chain->level_matches > 0);
-                               chain->level_matches--;
-                       }
-
-                       if (foundname != NULL) {
-                               unsigned int saved_count = chain->level_count;
-
-                               chain->level_count = chain->level_matches + 1;
-
-                               result = chain_name(chain, foundname,
-                                                   ISC_FALSE);
-
-                               chain->level_count = saved_count;
-                       } else
-                               result = ISC_R_SUCCESS;
-
-                       if (result == ISC_R_SUCCESS)
-                               result = DNS_R_PARTIALMATCH;
-
-               } else
-                       result = ISC_R_NOTFOUND;
-
-               if (current != NULL) {
-                       /*
-                        * There was an exact match but either
-                        * DNS_RBTFIND_NOEXACT was set, or
-                        * DNS_RBTFIND_EMPTYDATA was set and the node had no
-                        * data.  A policy decision was made to set the
-                        * chain to the exact match, but this is subject
-                        * to change if it becomes apparent that something
-                        * else would be more useful.  It is important that
-                        * this case is handled here, because the predecessor
-                        * setting code below assumes the match was not exact.
-                        */
-                       INSIST(((options & DNS_RBTFIND_NOEXACT) != 0) ||
-                              ((options & DNS_RBTFIND_EMPTYDATA) == 0 &&
-                               DATA(current) == NULL));
-                       chain->end = current;
-
-               } else if ((options & DNS_RBTFIND_NOPREDECESSOR) != 0) {
-                       /*
-                        * Ensure the chain points nowhere.
-                        */
-                       chain->end = NULL;
-
-               } else {
-                       /*
-                        * Since there was no exact match, the chain argument
-                        * needs to be pointed at the DNSSEC predecessor of
-                        * the search name.
-                        */
-                       if (compared == dns_namereln_subdomain) {
-                               /*
-                                * Attempted to follow a down pointer that was
-                                * NULL, which means the searched for name was
-                                * a subdomain of a terminal name in the tree.
-                                * Since there are no existing subdomains to
-                                * order against, the terminal name is the
-                                * predecessor.
-                                */
-                               INSIST(chain->level_count > 0);
-                               INSIST(chain->level_matches <
-                                      chain->level_count);
-                               chain->end =
-                                       chain->levels[--chain->level_count];
-
-                       } else {
-                               isc_result_t result2;
-
-                               /*
-                                * Point current to the node that stopped
-                                * the search.
-                                *
-                                * With the hashing modification that has been
-                                * added to the algorithm, the stop node of a
-                                * standard binary search is not known.  So it
-                                * has to be found.  There is probably a more
-                                * clever way of doing this.
-                                *
-                                * The assignment of current to NULL when
-                                * the relationship is *not* dns_namereln_none,
-                                * even though it later gets set to the same
-                                * last_compared anyway, is simply to not push
-                                * the while loop in one more level of
-                                * indentation.
-                                */
-                               if (compared == dns_namereln_none)
-                                       current = last_compared;
-                               else
-                                       current = NULL;
-
-                               while (current != NULL) {
-                                       NODENAME(current, &current_name);
-                                       compared = dns_name_fullcompare(
-                                                               search_name,
-                                                               &current_name,
-                                                               &order,
-                                                               &common_labels);
-
-                                       last_compared = current;
-
-                                       /*
-                                        * Standard binary search movement.
-                                        */
-                                       if (order < 0)
-                                               current = LEFT(current);
-                                       else
-                                               current = RIGHT(current);
-
-                               }
-
-                               current = last_compared;
-
-                               /*
-                                * Reached a point within a level tree that
-                                * positively indicates the name is not
-                                * present, but the stop node could be either
-                                * less than the desired name (order > 0) or
-                                * greater than the desired name (order < 0).
-                                *
-                                * If the stop node is less, it is not
-                                * necessarily the predecessor.  If the stop
-                                * node has a down pointer, then the real
-                                * predecessor is at the end of a level below
-                                * (not necessarily the next level).
-                                * Move down levels until the rightmost node
-                                * does not have a down pointer.
-                                *
-                                * When the stop node is greater, it is
-                                * the successor.  All the logic for finding
-                                * the predecessor is handily encapsulated
-                                * in dns_rbtnodechain_prev.  In the event
-                                * that the search name is less than anything
-                                * else in the tree, the chain is reset.
-                                * XXX DCL What is the best way for the caller
-                                *         to know that the search name has
-                                *         no predecessor?
-                                */
-
-
-                               if (order > 0) {
-                                       if (DOWN(current) != NULL) {
-                                               ADD_LEVEL(chain, current);
-
-                                               result2 =
-                                                     move_chain_to_last(chain,
-                                                               DOWN(current));
-
-                                               if (result2 != ISC_R_SUCCESS)
-                                                       result = result2;
-                                       } else
-                                               /*
-                                                * Ah, the pure and simple
-                                                * case.  The stop node is the
-                                                * predecessor.
-                                                */
-                                               chain->end = current;
-
-                               } else {
-                                       INSIST(order < 0);
-
-                                       chain->end = current;
-
-                                       result2 = dns_rbtnodechain_prev(chain,
-                                                                       NULL,
-                                                                       NULL);
-                                       if (result2 == ISC_R_SUCCESS ||
-                                           result2 == DNS_R_NEWORIGIN)
-                                               ;       /* Nothing. */
-                                       else if (result2 == ISC_R_NOMORE)
-                                               /*
-                                                * There is no predecessor.
-                                                */
-                                               dns_rbtnodechain_reset(chain);
-                                       else
-                                               result = result2;
-                               }
-
-                       }
-               }
-       }
-
-       ENSURE(*node == NULL || DNS_RBTNODE_VALID(*node));
-
-       return (result);
+                        /*
+                         * Standard binary search tree movement.
+                         */
+                        if (order < 0)
+                                current = LEFT(current);
+                        else
+                                current = RIGHT(current);
+
+                } else {
+                        /*
+                         * The names have some common suffix labels.
+                         *
+                         * If the number in common are equal in length to
+                         * the current node's name length, then follow the
+                         * down pointer and search in the new tree.
+                         */
+                        if (compared == dns_namereln_subdomain) {
+                subdomain:
+                                /*
+                                 * Whack off the current node's common parts
+                                 * for the name to search in the next level.
+                                 */
+                                dns_name_split(search_name, common_labels,
+                                               search_name, NULL);
+                                hlabels += common_labels;
+                                /*
+                                 * This might be the closest enclosing name.
+                                 */
+                                if (DATA(current) != NULL ||
+                                    (options & DNS_RBTFIND_EMPTYDATA) != 0)
+                                        *node = current;
+
+                                /*
+                                 * Point the chain to the next level.   This
+                                 * needs to be done before 'current' is pointed
+                                 * there because the callback in the next
+                                 * block of code needs the current 'current',
+                                 * but in the event the callback requests that
+                                 * the search be stopped then the
+                                 * DNS_R_PARTIALMATCH code at the end of this
+                                 * function needs the chain pointed to the
+                                 * next level.
+                                 */
+                                ADD_LEVEL(chain, current);
+
+                                /*
+                                 * The caller may want to interrupt the
+                                 * downward search when certain special nodes
+                                 * are traversed.  If this is a special node,
+                                 * the callback is used to learn what the
+                                 * caller wants to do.
+                                 */
+                                if (callback != NULL &&
+                                    FINDCALLBACK(current)) {
+                                        result = chain_name(chain,
+                                                            callback_name,
+                                                            ISC_FALSE);
+                                        if (result != ISC_R_SUCCESS) {
+                                                dns_rbtnodechain_reset(chain);
+                                                return (result);
+                                        }
+
+                                        result = (callback)(current,
+                                                            callback_name,
+                                                            callback_arg);
+                                        if (result != DNS_R_CONTINUE) {
+                                                saved_result = result;
+                                                /*
+                                                 * Treat this node as if it
+                                                 * had no down pointer.
+                                                 */
+                                                current = NULL;
+                                                break;
+                                        }
+                                }
+
+                                /*
+                                 * Finally, head to the next tree level.
+                                 */
+                                current = DOWN(current);
+                                current_root = current;
+
+                        } else {
+                                /*
+                                 * Though there are labels in common, the
+                                 * entire name at this node is not common
+                                 * with the search name so the search
+                                 * name does not exist in the tree.
+                                 */
+                                INSIST(compared == dns_namereln_commonancestor
+                                       || compared == dns_namereln_contains);
+
+                                current = NULL;
+                        }
+                }
+        }
+
+        /*
+         * If current is not NULL, NOEXACT is not disallowing exact matches,
+         * and either the node has data or an empty node is ok, return
+         * ISC_R_SUCCESS to indicate an exact match.
+         */
+        if (current != NULL && (options & DNS_RBTFIND_NOEXACT) == 0 &&
+            (DATA(current) != NULL ||
+             (options & DNS_RBTFIND_EMPTYDATA) != 0)) {
+                /*
+                 * Found an exact match.
+                 */
+                chain->end = current;
+                chain->level_matches = chain->level_count;
+
+                if (foundname != NULL)
+                        result = chain_name(chain, foundname, ISC_TRUE);
+                else
+                        result = ISC_R_SUCCESS;
+
+                if (result == ISC_R_SUCCESS) {
+                        *node = current;
+                        result = saved_result;
+                } else
+                        *node = NULL;
+        } else {
+                /*
+                 * Did not find an exact match (or did not want one).
+                 */
+                if (*node != NULL) {
+                        /*
+                         * ... but found a partially matching superdomain.
+                         * Unwind the chain to the partial match node
+                         * to set level_matches to the level above the node,
+                         * and then to derive the name.
+                         *
+                         * chain->level_count is guaranteed to be at least 1
+                         * here because by definition of finding a superdomain,
+                         * the chain is pointed to at least the first subtree.
+                         */
+                        chain->level_matches = chain->level_count - 1;
+
+                        while (chain->levels[chain->level_matches] != *node) {
+                                INSIST(chain->level_matches > 0);
+                                chain->level_matches--;
+                        }
+
+                        if (foundname != NULL) {
+                                unsigned int saved_count = chain->level_count;
+
+                                chain->level_count = chain->level_matches + 1;
+
+                                result = chain_name(chain, foundname,
+                                                    ISC_FALSE);
+
+                                chain->level_count = saved_count;
+                        } else
+                                result = ISC_R_SUCCESS;
+
+                        if (result == ISC_R_SUCCESS)
+                                result = DNS_R_PARTIALMATCH;
+
+                } else
+                        result = ISC_R_NOTFOUND;
+
+                if (current != NULL) {
+                        /*
+                         * There was an exact match but either
+                         * DNS_RBTFIND_NOEXACT was set, or
+                         * DNS_RBTFIND_EMPTYDATA was set and the node had no
+                         * data.  A policy decision was made to set the
+                         * chain to the exact match, but this is subject
+                         * to change if it becomes apparent that something
+                         * else would be more useful.  It is important that
+                         * this case is handled here, because the predecessor
+                         * setting code below assumes the match was not exact.
+                         */
+                        INSIST(((options & DNS_RBTFIND_NOEXACT) != 0) ||
+                               ((options & DNS_RBTFIND_EMPTYDATA) == 0 &&
+                                DATA(current) == NULL));
+                        chain->end = current;
+
+                } else if ((options & DNS_RBTFIND_NOPREDECESSOR) != 0) {
+                        /*
+                         * Ensure the chain points nowhere.
+                         */
+                        chain->end = NULL;
+
+                } else {
+                        /*
+                         * Since there was no exact match, the chain argument
+                         * needs to be pointed at the DNSSEC predecessor of
+                         * the search name.
+                         */
+                        if (compared == dns_namereln_subdomain) {
+                                /*
+                                 * Attempted to follow a down pointer that was
+                                 * NULL, which means the searched for name was
+                                 * a subdomain of a terminal name in the tree.
+                                 * Since there are no existing subdomains to
+                                 * order against, the terminal name is the
+                                 * predecessor.
+                                 */
+                                INSIST(chain->level_count > 0);
+                                INSIST(chain->level_matches <
+                                       chain->level_count);
+                                chain->end =
+                                        chain->levels[--chain->level_count];
+
+                        } else {
+                                isc_result_t result2;
+
+                                /*
+                                 * Point current to the node that stopped
+                                 * the search.
+                                 *
+                                 * With the hashing modification that has been
+                                 * added to the algorithm, the stop node of a
+                                 * standard binary search is not known.  So it
+                                 * has to be found.  There is probably a more
+                                 * clever way of doing this.
+                                 *
+                                 * The assignment of current to NULL when
+                                 * the relationship is *not* dns_namereln_none,
+                                 * even though it later gets set to the same
+                                 * last_compared anyway, is simply to not push
+                                 * the while loop in one more level of
+                                 * indentation.
+                                 */
+                                if (compared == dns_namereln_none)
+                                        current = last_compared;
+                                else
+                                        current = NULL;
+
+                                while (current != NULL) {
+                                        NODENAME(current, &current_name);
+                                        compared = dns_name_fullcompare(
+                                                                search_name,
+                                                                &current_name,
+                                                                &order,
+                                                                &common_labels);
+
+                                        last_compared = current;
+
+                                        /*
+                                         * Standard binary search movement.
+                                         */
+                                        if (order < 0)
+                                                current = LEFT(current);
+                                        else
+                                                current = RIGHT(current);
+
+                                }
+
+                                current = last_compared;
+
+                                /*
+                                 * Reached a point within a level tree that
+                                 * positively indicates the name is not
+                                 * present, but the stop node could be either
+                                 * less than the desired name (order > 0) or
+                                 * greater than the desired name (order < 0).
+                                 *
+                                 * If the stop node is less, it is not
+                                 * necessarily the predecessor.  If the stop
+                                 * node has a down pointer, then the real
+                                 * predecessor is at the end of a level below
+                                 * (not necessarily the next level).
+                                 * Move down levels until the rightmost node
+                                 * does not have a down pointer.
+                                 *
+                                 * When the stop node is greater, it is
+                                 * the successor.  All the logic for finding
+                                 * the predecessor is handily encapsulated
+                                 * in dns_rbtnodechain_prev.  In the event
+                                 * that the search name is less than anything
+                                 * else in the tree, the chain is reset.
+                                 * XXX DCL What is the best way for the caller
+                                 *         to know that the search name has
+                                 *         no predecessor?
+                                 */
+
+
+                                if (order > 0) {
+                                        if (DOWN(current) != NULL) {
+                                                ADD_LEVEL(chain, current);
+
+                                                result2 =
+                                                      move_chain_to_last(chain,
+                                                                DOWN(current));
+
+                                                if (result2 != ISC_R_SUCCESS)
+                                                        result = result2;
+                                        } else
+                                                /*
+                                                 * Ah, the pure and simple
+                                                 * case.  The stop node is the
+                                                 * predecessor.
+                                                 */
+                                                chain->end = current;
+
+                                } else {
+                                        INSIST(order < 0);
+
+                                        chain->end = current;
+
+                                        result2 = dns_rbtnodechain_prev(chain,
+                                                                        NULL,
+                                                                        NULL);
+                                        if (result2 == ISC_R_SUCCESS ||
+                                            result2 == DNS_R_NEWORIGIN)
+                                                ;       /* Nothing. */
+                                        else if (result2 == ISC_R_NOMORE)
+                                                /*
+                                                 * There is no predecessor.
+                                                 */
+                                                dns_rbtnodechain_reset(chain);
+                                        else
+                                                result = result2;
+                                }
+
+                        }
+                }
+        }
+
+        ENSURE(*node == NULL || DNS_RBTNODE_VALID(*node));
+
+        return (result);
 }
 
 /*
@@ -1166,22 +1169,22 @@ dns_rbt_findnode(dns_rbt_t *rbt, dns_name_t *name, dns_name_t *foundname,
  */
 isc_result_t
 dns_rbt_findname(dns_rbt_t *rbt, dns_name_t *name, unsigned int options,
-                dns_name_t *foundname, void **data) {
-       dns_rbtnode_t *node = NULL;
-       isc_result_t result;
+                 dns_name_t *foundname, void **data) {
+        dns_rbtnode_t *node = NULL;
+        isc_result_t result;
 
-       REQUIRE(data != NULL && *data == NULL);
+        REQUIRE(data != NULL && *data == NULL);
 
-       result = dns_rbt_findnode(rbt, name, foundname, &node, NULL,
-                                 options, NULL, NULL);
+        result = dns_rbt_findnode(rbt, name, foundname, &node, NULL,
+                                  options, NULL, NULL);
 
-       if (node != NULL &&
-           (DATA(node) != NULL || (options & DNS_RBTFIND_EMPTYDATA) != 0))
-               *data = DATA(node);
-       else
-               result = ISC_R_NOTFOUND;
+        if (node != NULL &&
+            (DATA(node) != NULL || (options & DNS_RBTFIND_EMPTYDATA) != 0))
+                *data = DATA(node);
+        else
+                result = ISC_R_NOTFOUND;
 
-       return (result);
+        return (result);
 }
 
 /*
@@ -1189,39 +1192,39 @@ dns_rbt_findname(dns_rbt_t *rbt, dns_name_t *name, unsigned int options,
  */
 isc_result_t
 dns_rbt_deletename(dns_rbt_t *rbt, dns_name_t *name, isc_boolean_t recurse) {
-       dns_rbtnode_t *node = NULL;
-       isc_result_t result;
-
-       REQUIRE(VALID_RBT(rbt));
-       REQUIRE(dns_name_isabsolute(name));
-
-       /*
-        * First, find the node.
-        *
-        * When searching, the name might not have an exact match:
-        * consider a.b.a.com, b.b.a.com and c.b.a.com as the only
-        * elements of a tree, which would make layer 1 a single
-        * node tree of "b.a.com" and layer 2 a three node tree of
-        * a, b, and c.  Deleting a.com would find only a partial depth
-        * match in the first layer.  Should it be a requirement that
-        * that the name to be deleted have data?  For now, it is.
-        *
-        * ->dirty, ->locknum and ->references are ignored; they are
-        * solely the province of rbtdb.c.
-        */
-       result = dns_rbt_findnode(rbt, name, NULL, &node, NULL,
-                                 DNS_RBTFIND_NOOPTIONS, NULL, NULL);
-
-       if (result == ISC_R_SUCCESS) {
-               if (DATA(node) != NULL)
-                       result = dns_rbt_deletenode(rbt, node, recurse);
-               else
-                       result = ISC_R_NOTFOUND;
-
-       } else if (result == DNS_R_PARTIALMATCH)
-               result = ISC_R_NOTFOUND;
-
-       return (result);
+        dns_rbtnode_t *node = NULL;
+        isc_result_t result;
+
+        REQUIRE(VALID_RBT(rbt));
+        REQUIRE(dns_name_isabsolute(name));
+
+        /*
+         * First, find the node.
+         *
+         * When searching, the name might not have an exact match:
+         * consider a.b.a.com, b.b.a.com and c.b.a.com as the only
+         * elements of a tree, which would make layer 1 a single
+         * node tree of "b.a.com" and layer 2 a three node tree of
+         * a, b, and c.  Deleting a.com would find only a partial depth
+         * match in the first layer.  Should it be a requirement that
+         * that the name to be deleted have data?  For now, it is.
+         *
+         * ->dirty, ->locknum and ->references are ignored; they are
+         * solely the province of rbtdb.c.
+         */
+        result = dns_rbt_findnode(rbt, name, NULL, &node, NULL,
+                                  DNS_RBTFIND_NOOPTIONS, NULL, NULL);
+
+        if (result == ISC_R_SUCCESS) {
+                if (DATA(node) != NULL)
+                        result = dns_rbt_deletenode(rbt, node, recurse);
+                else
+                        result = ISC_R_NOTFOUND;
+
+        } else if (result == DNS_R_PARTIALMATCH)
+                result = ISC_R_NOTFOUND;
+
+        return (result);
 }
 
 /*
@@ -1263,378 +1266,379 @@ dns_rbt_deletename(dns_rbt_t *rbt, dns_name_t *name, isc_boolean_t recurse) {
 isc_result_t
 dns_rbt_deletenode(dns_rbt_t *rbt, dns_rbtnode_t *node, isc_boolean_t recurse)
 {
-       dns_rbtnode_t *parent;
-
-       REQUIRE(VALID_RBT(rbt));
-       REQUIRE(DNS_RBTNODE_VALID(node));
-
-       if (DOWN(node) != NULL) {
-               if (recurse)
-                       RUNTIME_CHECK(dns_rbt_deletetree(rbt, DOWN(node))
-                                     == ISC_R_SUCCESS);
-               else {
-                       if (DATA(node) != NULL && rbt->data_deleter != NULL)
-                               rbt->data_deleter(DATA(node),
-                                                 rbt->deleter_arg);
-                       DATA(node) = NULL;
-
-                       /*
-                        * Since there is at least one node below this one and
-                        * no recursion was requested, the deletion is
-                        * complete.  The down node from this node might be all
-                        * by itself on a single level, so join_nodes() could
-                        * be used to collapse the tree (with all the caveats
-                        * of the comment at the start of this function).
-                        */
-                       return (ISC_R_SUCCESS);
-               }
-       }
-
-       /*
-        * Note the node that points to the level of the node that is being
-        * deleted.  If the deleted node is the top level, parent will be set
-        * to NULL.
-        */
-       parent = find_up(node);
-
-       /*
-        * This node now has no down pointer (either because it didn't
-        * have one to start, or because it was recursively removed).
-        * So now the node needs to be removed from this level.
-        */
-       dns_rbt_deletefromlevel(node, parent == NULL ? &rbt->root :
-                                                      &DOWN(parent));
-
-       if (DATA(node) != NULL && rbt->data_deleter != NULL)
-               rbt->data_deleter(DATA(node), rbt->deleter_arg);
-
-       unhash_node(rbt, node);
+        dns_rbtnode_t *parent;
+
+        REQUIRE(VALID_RBT(rbt));
+        REQUIRE(DNS_RBTNODE_VALID(node));
+
+        if (DOWN(node) != NULL) {
+                if (recurse)
+                        RUNTIME_CHECK(dns_rbt_deletetree(rbt, DOWN(node))
+                                      == ISC_R_SUCCESS);
+                else {
+                        if (DATA(node) != NULL && rbt->data_deleter != NULL)
+                                rbt->data_deleter(DATA(node), rbt->deleter_arg);
+                        DATA(node) = NULL;
+
+                        /*
+                         * Since there is at least one node below this one and
+                         * no recursion was requested, the deletion is
+                         * complete.  The down node from this node might be all
+                         * by itself on a single level, so join_nodes() could
+                         * be used to collapse the tree (with all the caveats
+                         * of the comment at the start of this function).
+                         */
+                        return (ISC_R_SUCCESS);
+                }
+        }
+
+        /*
+         * Note the node that points to the level of the node that is being
+         * deleted.  If the deleted node is the top level, parent will be set
+         * to NULL.
+         */
+        parent = find_up(node);
+
+        /*
+         * This node now has no down pointer (either because it didn't
+         * have one to start, or because it was recursively removed).
+         * So now the node needs to be removed from this level.
+         */
+        dns_rbt_deletefromlevel(node, parent == NULL ? &rbt->root :
+                                                       &DOWN(parent));
+
+        if (DATA(node) != NULL && rbt->data_deleter != NULL)
+                rbt->data_deleter(DATA(node), rbt->deleter_arg);
+
+        unhash_node(rbt, node);
 #if DNS_RBT_USEMAGIC
-       node->magic = 0;
+        node->magic = 0;
 #endif
-       dns_rbtnode_refdestroy(node);
-       isc_mem_put(rbt->mctx, node, NODE_SIZE(node));
-       rbt->nodecount--;
-
-       /*
-        * There are now two special cases that can exist that would
-        * not have existed if the tree had been created using only
-        * the names that now exist in it.  (This is all related to
-        * join_nodes() as described in this function's introductory comment.)
-        * Both cases exist when the deleted node's parent (the node
-        * that pointed to the deleted node's level) is not null but
-        * it has no data:  parent != NULL && DATA(parent) == NULL.
-        *
-        * The first case is that the deleted node was the last on its level:
-        * DOWN(parent) == NULL.  This case can only exist if the parent was
-        * previously deleted -- and so now, apparently, the parent should go
-        * away.  That can't be done though because there might be external
-        * references to it, such as through a nodechain.
-        *
-        * The other case also involves a parent with no data, but with the
-        * deleted node being the next-to-last node instead of the last:
-        * LEFT(DOWN(parent)) == NULL && RIGHT(DOWN(parent)) == NULL.
-        * Presumably now the remaining node on the level should be joined
-        * with the parent, but it's already been described why that can't be
-        * done.
-        */
-
-       /*
-        * This function never fails.
-        */
-       return (ISC_R_SUCCESS);
+        dns_rbtnode_refdestroy(node);
+        isc_mem_put(rbt->mctx, node, NODE_SIZE(node));
+        rbt->nodecount--;
+
+        /*
+         * There are now two special cases that can exist that would
+         * not have existed if the tree had been created using only
+         * the names that now exist in it.  (This is all related to
+         * join_nodes() as described in this function's introductory comment.)
+         * Both cases exist when the deleted node's parent (the node
+         * that pointed to the deleted node's level) is not null but
+         * it has no data:  parent != NULL && DATA(parent) == NULL.
+         *
+         * The first case is that the deleted node was the last on its level:
+         * DOWN(parent) == NULL.  This case can only exist if the parent was
+         * previously deleted -- and so now, apparently, the parent should go
+         * away.  That can't be done though because there might be external
+         * references to it, such as through a nodechain.
+         *
+         * The other case also involves a parent with no data, but with the
+         * deleted node being the next-to-last node instead of the last:
+         * LEFT(DOWN(parent)) == NULL && RIGHT(DOWN(parent)) == NULL.
+         * Presumably now the remaining node on the level should be joined
+         * with the parent, but it's already been described why that can't be
+         * done.
+         */
+
+        /*
+         * This function never fails.
+         */
+        return (ISC_R_SUCCESS);
 }
 
 void
 dns_rbt_namefromnode(dns_rbtnode_t *node, dns_name_t *name) {
 
-       REQUIRE(DNS_RBTNODE_VALID(node));
-       REQUIRE(name != NULL);
-       REQUIRE(name->offsets == NULL);
+        REQUIRE(DNS_RBTNODE_VALID(node));
+        REQUIRE(name != NULL);
+        REQUIRE(name->offsets == NULL);
 
-       NODENAME(node, name);
+        NODENAME(node, name);
 }
 
 isc_result_t
 dns_rbt_fullnamefromnode(dns_rbtnode_t *node, dns_name_t *name) {
-       dns_name_t current;
-       isc_result_t result;
+        dns_name_t current;
+        isc_result_t result;
 
-       REQUIRE(DNS_RBTNODE_VALID(node));
-       REQUIRE(name != NULL);
-       REQUIRE(name->buffer != NULL);
+        REQUIRE(DNS_RBTNODE_VALID(node));
+        REQUIRE(name != NULL);
+        REQUIRE(name->buffer != NULL);
 
-       dns_name_init(&current, NULL);
-       dns_name_reset(name);
+        dns_name_init(&current, NULL);
+        dns_name_reset(name);
 
-       do {
-               INSIST(node != NULL);
+        do {
+                INSIST(node != NULL);
 
-               NODENAME(node, &current);
+                NODENAME(node, &current);
 
-               result = dns_name_concatenate(name, &current, name, NULL);
-               if (result != ISC_R_SUCCESS)
-                       break;
-               
-               node = find_up(node);
-       } while (! dns_name_isabsolute(name));
+                result = dns_name_concatenate(name, &current, name, NULL);
+                if (result != ISC_R_SUCCESS)
+                        break;
 
-       return (result);
+                node = find_up(node);
+        } while (! dns_name_isabsolute(name));
+
+        return (result);
 }
 
 char *
 dns_rbt_formatnodename(dns_rbtnode_t *node, char *printname, unsigned int size)
 {
-       dns_fixedname_t fixedname;
-       dns_name_t *name;
-       isc_result_t result;
-
-       REQUIRE(DNS_RBTNODE_VALID(node));
-       REQUIRE(printname != NULL);
-
-       dns_fixedname_init(&fixedname);
-       name = dns_fixedname_name(&fixedname);
-       result = dns_rbt_fullnamefromnode(node, name);
-       if (result == ISC_R_SUCCESS)
-               dns_name_format(name, printname, size);
-       else
-               snprintf(printname, size, "<error building name: %s>",
-                        dns_result_totext(result));
-
-       return (printname);
+        dns_fixedname_t fixedname;
+        dns_name_t *name;
+        isc_result_t result;
+
+        REQUIRE(DNS_RBTNODE_VALID(node));
+        REQUIRE(printname != NULL);
+
+        dns_fixedname_init(&fixedname);
+        name = dns_fixedname_name(&fixedname);
+        result = dns_rbt_fullnamefromnode(node, name);
+        if (result == ISC_R_SUCCESS)
+                dns_name_format(name, printname, size);
+        else
+                snprintf(printname, size, "<error building name: %s>",
+                         dns_result_totext(result));
+
+        return (printname);
 }
 
 static isc_result_t
 create_node(isc_mem_t *mctx, dns_name_t *name, dns_rbtnode_t **nodep) {
-       dns_rbtnode_t *node;
-       isc_region_t region;
-       unsigned int labels;
-
-       REQUIRE(name->offsets != NULL);
-
-       dns_name_toregion(name, &region);
-       labels = dns_name_countlabels(name);
-       ENSURE(labels > 0);
-
-       /*
-        * Allocate space for the node structure, the name, and the offsets.
-        */
-       node = (dns_rbtnode_t *)isc_mem_get(mctx, sizeof(*node) +
-                                           region.length + labels);
-
-       if (node == NULL)
-               return (ISC_R_NOMEMORY);
-
-       node->is_root = 0;
-       PARENT(node) = NULL;
-       RIGHT(node) = NULL;
-       LEFT(node) = NULL;
-       DOWN(node) = NULL;
-       DATA(node) = NULL;
+        dns_rbtnode_t *node;
+        isc_region_t region;
+        unsigned int labels;
+
+        REQUIRE(name->offsets != NULL);
+
+        dns_name_toregion(name, &region);
+        labels = dns_name_countlabels(name);
+        ENSURE(labels > 0);
+
+        /*
+         * Allocate space for the node structure, the name, and the offsets.
+         */
+        node = (dns_rbtnode_t *)isc_mem_get(mctx, sizeof(*node) +
+                                            region.length + labels);
+
+        if (node == NULL)
+                return (ISC_R_NOMEMORY);
+
+        node->is_root = 0;
+        PARENT(node) = NULL;
+        RIGHT(node) = NULL;
+        LEFT(node) = NULL;
+        DOWN(node) = NULL;
+        DATA(node) = NULL;
 #ifdef DNS_RBT_USEHASH
-       HASHNEXT(node) = NULL;
-       HASHVAL(node) = 0;
+        HASHNEXT(node) = NULL;
+        HASHVAL(node) = 0;
 #endif
 
-       LOCKNUM(node) = 0;
-       WILD(node) = 0;
-       DIRTY(node) = 0;
-       dns_rbtnode_refinit(node, 0);
-       node->find_callback = 0;
-
-       MAKE_BLACK(node);
-
-       /*
-        * The following is stored to make reconstructing a name from the
-        * stored value in the node easy:  the length of the name, the number
-        * of labels, whether the name is absolute or not, the name itself,
-        * and the name's offsets table.
-        *
-        * XXX RTH
-        *      The offsets table could be made smaller by eliminating the
-        *      first offset, which is always 0.  This requires changes to
-        *      lib/dns/name.c.
-        */
-       NAMELEN(node) = region.length;
-       PADBYTES(node) = 0;
-       OFFSETLEN(node) = labels;
-       ATTRS(node) = name->attributes;
-
-       memcpy(NAME(node), region.base, region.length);
-       memcpy(OFFSETS(node), name->offsets, labels);
+        ISC_LINK_INIT(node, deadlink);
+
+        LOCKNUM(node) = 0;
+        WILD(node) = 0;
+        DIRTY(node) = 0;
+        dns_rbtnode_refinit(node, 0);
+        node->find_callback = 0;
+
+        MAKE_BLACK(node);
+
+        /*
+         * The following is stored to make reconstructing a name from the
+         * stored value in the node easy:  the length of the name, the number
+         * of labels, whether the name is absolute or not, the name itself,
+         * and the name's offsets table.
+         *
+         * XXX RTH
+         *      The offsets table could be made smaller by eliminating the
+         *      first offset, which is always 0.  This requires changes to
+         *      lib/dns/name.c.
+         */
+        NAMELEN(node) = region.length;
+        PADBYTES(node) = 0;
+        OFFSETLEN(node) = labels;
+        ATTRS(node) = name->attributes;
+
+        memcpy(NAME(node), region.base, region.length);
+        memcpy(OFFSETS(node), name->offsets, labels);
 
 #if DNS_RBT_USEMAGIC
-       node->magic = DNS_RBTNODE_MAGIC;
+        node->magic = DNS_RBTNODE_MAGIC;
 #endif
-       *nodep = node;
+        *nodep = node;
 
-       return (ISC_R_SUCCESS);
+        return (ISC_R_SUCCESS);
 }
 
 #ifdef DNS_RBT_USEHASH
 static inline void
 hash_add_node(dns_rbt_t *rbt, dns_rbtnode_t *node, dns_name_t *name) {
-       unsigned int hash;
+        unsigned int hash;
 
-       HASHVAL(node) = dns_name_fullhash(name, ISC_FALSE);
+        HASHVAL(node) = dns_name_fullhash(name, ISC_FALSE);
 
-       hash = HASHVAL(node) % rbt->hashsize;
-       HASHNEXT(node) = rbt->hashtable[hash];
+        hash = HASHVAL(node) % rbt->hashsize;
+        HASHNEXT(node) = rbt->hashtable[hash];
 
-       rbt->hashtable[hash] = node;
+        rbt->hashtable[hash] = node;
 }
 
 static isc_result_t
 inithash(dns_rbt_t *rbt) {
-       unsigned int bytes;
+        unsigned int bytes;
 
-       rbt->hashsize = RBT_HASH_SIZE;
-       bytes = rbt->hashsize * sizeof(dns_rbtnode_t *);
-       rbt->hashtable = isc_mem_get(rbt->mctx, bytes);
+        rbt->hashsize = RBT_HASH_SIZE;
+        bytes = rbt->hashsize * sizeof(dns_rbtnode_t *);
+        rbt->hashtable = isc_mem_get(rbt->mctx, bytes);
 
-       if (rbt->hashtable == NULL)
-               return (ISC_R_NOMEMORY);
+        if (rbt->hashtable == NULL)
+                return (ISC_R_NOMEMORY);
 
-       memset(rbt->hashtable, 0, bytes);
+        memset(rbt->hashtable, 0, bytes);
 
-       return (ISC_R_SUCCESS);
+        return (ISC_R_SUCCESS);
 }
 
 static void
 rehash(dns_rbt_t *rbt) {
-       unsigned int oldsize;
-       dns_rbtnode_t **oldtable;
-       dns_rbtnode_t *node;
-       unsigned int hash;
-       unsigned int i;
-
-       oldsize = rbt->hashsize;
-       oldtable = rbt->hashtable;
-       rbt->hashsize *= 2 + 1;
-       rbt->hashtable = isc_mem_get(rbt->mctx,
-                                    rbt->hashsize * sizeof(dns_rbtnode_t *));
-       if (rbt->hashtable == NULL) {
-               rbt->hashtable = oldtable;
-               rbt->hashsize = oldsize;
-               return;
-       }
-
-       for (i = 0; i < rbt->hashsize; i++)
-               rbt->hashtable[i] = NULL;
-
-       for (i = 0; i < oldsize; i++) {
-               node = oldtable[i];
-               while (node != NULL) {
-                       hash = HASHVAL(node) % rbt->hashsize;
-                       oldtable[i] = HASHNEXT(node);
-                       HASHNEXT(node) = rbt->hashtable[hash];
-                       rbt->hashtable[hash] = node;
-                       node = oldtable[i];
-               }
-       }
-
-       isc_mem_put(rbt->mctx, oldtable, oldsize * sizeof(dns_rbtnode_t *));
+        unsigned int oldsize;
+        dns_rbtnode_t **oldtable;
+        dns_rbtnode_t *node;
+        unsigned int hash;
+        unsigned int i;
+
+        oldsize = rbt->hashsize;
+        oldtable = rbt->hashtable;
+        rbt->hashsize *= 2 + 1;
+        rbt->hashtable = isc_mem_get(rbt->mctx,
+                                     rbt->hashsize * sizeof(dns_rbtnode_t *));
+        if (rbt->hashtable == NULL) {
+                rbt->hashtable = oldtable;
+                rbt->hashsize = oldsize;
+                return;
+        }
+
+        for (i = 0; i < rbt->hashsize; i++)
+                rbt->hashtable[i] = NULL;
+
+        for (i = 0; i < oldsize; i++) {
+                node = oldtable[i];
+                while (node != NULL) {
+                        hash = HASHVAL(node) % rbt->hashsize;
+                        oldtable[i] = HASHNEXT(node);
+                        HASHNEXT(node) = rbt->hashtable[hash];
+                        rbt->hashtable[hash] = node;
+                        node = oldtable[i];
+                }
+        }
+
+        isc_mem_put(rbt->mctx, oldtable, oldsize * sizeof(dns_rbtnode_t *));
 }
 
 static inline void
 hash_node(dns_rbt_t *rbt, dns_rbtnode_t *node, dns_name_t *name) {
 
-       REQUIRE(DNS_RBTNODE_VALID(node));
+        REQUIRE(DNS_RBTNODE_VALID(node));
 
-       if (rbt->nodecount >= (rbt->hashsize *3))
-               rehash(rbt);
+        if (rbt->nodecount >= (rbt->hashsize *3))
+                rehash(rbt);
 
-       hash_add_node(rbt, node, name);
+        hash_add_node(rbt, node, name);
 }
 
 static inline void
 unhash_node(dns_rbt_t *rbt, dns_rbtnode_t *node) {
-       unsigned int bucket;
-       dns_rbtnode_t *bucket_node;
-
-       REQUIRE(DNS_RBTNODE_VALID(node));
-
-       if (rbt->hashtable != NULL) {
-               bucket = HASHVAL(node) % rbt->hashsize;
-               bucket_node = rbt->hashtable[bucket];
-
-               if (bucket_node == node)
-                       rbt->hashtable[bucket] = HASHNEXT(node);
-               else {
-                       while (HASHNEXT(bucket_node) != node) {
-                               INSIST(HASHNEXT(bucket_node) != NULL);
-                               bucket_node = HASHNEXT(bucket_node);
-                       }
-                       HASHNEXT(bucket_node) = HASHNEXT(node);
-               }
-       }
+        unsigned int bucket;
+        dns_rbtnode_t *bucket_node;
+
+        REQUIRE(DNS_RBTNODE_VALID(node));
+
+        if (rbt->hashtable != NULL) {
+                bucket = HASHVAL(node) % rbt->hashsize;
+                bucket_node = rbt->hashtable[bucket];
+
+                if (bucket_node == node)
+                        rbt->hashtable[bucket] = HASHNEXT(node);
+                else {
+                        while (HASHNEXT(bucket_node) != node) {
+                                INSIST(HASHNEXT(bucket_node) != NULL);
+                                bucket_node = HASHNEXT(bucket_node);
+                        }
+                        HASHNEXT(bucket_node) = HASHNEXT(node);
+                }
+        }
 }
 #endif /* DNS_RBT_USEHASH */
 
 static inline void
 rotate_left(dns_rbtnode_t *node, dns_rbtnode_t **rootp) {
-       dns_rbtnode_t *child;
+        dns_rbtnode_t *child;
 
-       REQUIRE(DNS_RBTNODE_VALID(node));
-       REQUIRE(rootp != NULL);
+        REQUIRE(DNS_RBTNODE_VALID(node));
+        REQUIRE(rootp != NULL);
 
-       child = RIGHT(node);
-       INSIST(child != NULL);
+        child = RIGHT(node);
+        INSIST(child != NULL);
 
-       RIGHT(node) = LEFT(child);
-       if (LEFT(child) != NULL)
-               PARENT(LEFT(child)) = node;
-       LEFT(child) = node;
+        RIGHT(node) = LEFT(child);
+        if (LEFT(child) != NULL)
+                PARENT(LEFT(child)) = node;
+        LEFT(child) = node;
 
-       if (child != NULL)
-               PARENT(child) = PARENT(node);
+        if (child != NULL)
+                PARENT(child) = PARENT(node);
 
-       if (IS_ROOT(node)) {
-               *rootp = child;
-               child->is_root = 1;
-               node->is_root = 0;
+        if (IS_ROOT(node)) {
+                *rootp = child;
+                child->is_root = 1;
+                node->is_root = 0;
 
-       } else {
-               if (LEFT(PARENT(node)) == node)
-                       LEFT(PARENT(node)) = child;
-               else
-                       RIGHT(PARENT(node)) = child;
-       }
+        } else {
+                if (LEFT(PARENT(node)) == node)
+                        LEFT(PARENT(node)) = child;
+                else
+                        RIGHT(PARENT(node)) = child;
+        }
 
-       PARENT(node) = child;
+        PARENT(node) = child;
 }
 
 static inline void
 rotate_right(dns_rbtnode_t *node, dns_rbtnode_t **rootp) {
-       dns_rbtnode_t *child;
+        dns_rbtnode_t *child;
 
-       REQUIRE(DNS_RBTNODE_VALID(node));
-       REQUIRE(rootp != NULL);
+        REQUIRE(DNS_RBTNODE_VALID(node));
+        REQUIRE(rootp != NULL);
 
-       child = LEFT(node);
-       INSIST(child != NULL);
+        child = LEFT(node);
+        INSIST(child != NULL);
 
-       LEFT(node) = RIGHT(child);
-       if (RIGHT(child) != NULL)
-               PARENT(RIGHT(child)) = node;
-       RIGHT(child) = node;
+        LEFT(node) = RIGHT(child);
+        if (RIGHT(child) != NULL)
+                PARENT(RIGHT(child)) = node;
+        RIGHT(child) = node;
 
-       if (child != NULL)
-               PARENT(child) = PARENT(node);
+        if (child != NULL)
+                PARENT(child) = PARENT(node);
 
-       if (IS_ROOT(node)) {
-               *rootp = child;
-               child->is_root = 1;
-               node->is_root = 0;
+        if (IS_ROOT(node)) {
+                *rootp = child;
+                child->is_root = 1;
+                node->is_root = 0;
 
-       } else {
-               if (LEFT(PARENT(node)) == node)
-                       LEFT(PARENT(node)) = child;
-               else
-                       RIGHT(PARENT(node)) = child;
-       }
+        } else {
+                if (LEFT(PARENT(node)) == node)
+                        LEFT(PARENT(node)) = child;
+                else
+                        RIGHT(PARENT(node)) = child;
+        }
 
-       PARENT(node) = child;
+        PARENT(node) = child;
 }
 
 /*
@@ -1642,105 +1646,105 @@ rotate_right(dns_rbtnode_t *node, dns_rbtnode_t **rootp) {
  * true red/black tree on a single level.
  */
 static void
-dns_rbt_addonlevel(dns_rbtnode_t *node, dns_rbtnode_t *current, int order, 
-                  dns_rbtnode_t **rootp)
+dns_rbt_addonlevel(dns_rbtnode_t *node, dns_rbtnode_t *current, int order,
+                   dns_rbtnode_t **rootp)
 {
-       dns_rbtnode_t *child, *root, *parent, *grandparent;
-       dns_name_t add_name, current_name;
-       dns_offsets_t add_offsets, current_offsets;
-
-       REQUIRE(rootp != NULL);
-       REQUIRE(DNS_RBTNODE_VALID(node) && LEFT(node) == NULL &&
-               RIGHT(node) == NULL);
-       REQUIRE(current != NULL);
-
-       root = *rootp;
-       if (root == NULL) {
-               /*
-                * First node of a level.
-                */
-               MAKE_BLACK(node);
-               node->is_root = 1;
-               PARENT(node) = current;
-               *rootp = node;
-               return;
-       }
-
-       child = root;
-
-       dns_name_init(&add_name, add_offsets);
-       NODENAME(node, &add_name);
-
-       dns_name_init(&current_name, current_offsets);
-       NODENAME(current, &current_name);
-
-       if (order < 0) {
-               INSIST(LEFT(current) == NULL);
-               LEFT(current) = node;
-       } else {
-               INSIST(RIGHT(current) == NULL);
-               RIGHT(current) = node;
-       }
-
-       INSIST(PARENT(node) == NULL);
-       PARENT(node) = current;
-
-       MAKE_RED(node);
-
-       while (node != root && IS_RED(PARENT(node))) {
-               /*
-                * XXXDCL could do away with separate parent and grandparent
-                * variables.  They are vestiges of the days before parent
-                * pointers.  However, they make the code a little clearer.
-                */
-
-               parent = PARENT(node);
-               grandparent = PARENT(parent);
-
-               if (parent == LEFT(grandparent)) {
-                       child = RIGHT(grandparent);
-                       if (child != NULL && IS_RED(child)) {
-                               MAKE_BLACK(parent);
-                               MAKE_BLACK(child);
-                               MAKE_RED(grandparent);
-                               node = grandparent;
-                       } else {
-                               if (node == RIGHT(parent)) {
-                                       rotate_left(parent, &root);
-                                       node = parent;
-                                       parent = PARENT(node);
-                                       grandparent = PARENT(parent);
-                               }
-                               MAKE_BLACK(parent);
-                               MAKE_RED(grandparent);
-                               rotate_right(grandparent, &root);
-                       }
-               } else {
-                       child = LEFT(grandparent);
-                       if (child != NULL && IS_RED(child)) {
-                               MAKE_BLACK(parent);
-                               MAKE_BLACK(child);
-                               MAKE_RED(grandparent);
-                               node = grandparent;
-                       } else {
-                               if (node == LEFT(parent)) {
-                                       rotate_right(parent, &root);
-                                       node = parent;
-                                       parent = PARENT(node);
-                                       grandparent = PARENT(parent);
-                               }
-                               MAKE_BLACK(parent);
-                               MAKE_RED(grandparent);
-                               rotate_left(grandparent, &root);
-                       }
-               }
-       }
-
-       MAKE_BLACK(root);
-       ENSURE(IS_ROOT(root));
-       *rootp = root;
-
-       return;
+        dns_rbtnode_t *child, *root, *parent, *grandparent;
+        dns_name_t add_name, current_name;
+        dns_offsets_t add_offsets, current_offsets;
+
+        REQUIRE(rootp != NULL);
+        REQUIRE(DNS_RBTNODE_VALID(node) && LEFT(node) == NULL &&
+                RIGHT(node) == NULL);
+        REQUIRE(current != NULL);
+
+        root = *rootp;
+        if (root == NULL) {
+                /*
+                 * First node of a level.
+                 */
+                MAKE_BLACK(node);
+                node->is_root = 1;
+                PARENT(node) = current;
+                *rootp = node;
+                return;
+        }
+
+        child = root;
+
+        dns_name_init(&add_name, add_offsets);
+        NODENAME(node, &add_name);
+
+        dns_name_init(&current_name, current_offsets);
+        NODENAME(current, &current_name);
+
+        if (order < 0) {
+                INSIST(LEFT(current) == NULL);
+                LEFT(current) = node;
+        } else {
+                INSIST(RIGHT(current) == NULL);
+                RIGHT(current) = node;
+        }
+
+        INSIST(PARENT(node) == NULL);
+        PARENT(node) = current;
+
+        MAKE_RED(node);
+
+        while (node != root && IS_RED(PARENT(node))) {
+                /*
+                 * XXXDCL could do away with separate parent and grandparent
+                 * variables.  They are vestiges of the days before parent
+                 * pointers.  However, they make the code a little clearer.
+                 */
+
+                parent = PARENT(node);
+                grandparent = PARENT(parent);
+
+                if (parent == LEFT(grandparent)) {
+                        child = RIGHT(grandparent);
+                        if (child != NULL && IS_RED(child)) {
+                                MAKE_BLACK(parent);
+                                MAKE_BLACK(child);
+                                MAKE_RED(grandparent);
+                                node = grandparent;
+                        } else {
+                                if (node == RIGHT(parent)) {
+                                        rotate_left(parent, &root);
+                                        node = parent;
+                                        parent = PARENT(node);
+                                        grandparent = PARENT(parent);
+                                }
+                                MAKE_BLACK(parent);
+                                MAKE_RED(grandparent);
+                                rotate_right(grandparent, &root);
+                        }
+                } else {
+                        child = LEFT(grandparent);
+                        if (child != NULL && IS_RED(child)) {
+                                MAKE_BLACK(parent);
+                                MAKE_BLACK(child);
+                                MAKE_RED(grandparent);
+                                node = grandparent;
+                        } else {
+                                if (node == LEFT(parent)) {
+                                        rotate_right(parent, &root);
+                                        node = parent;
+                                        parent = PARENT(node);
+                                        grandparent = PARENT(parent);
+                                }
+                                MAKE_BLACK(parent);
+                                MAKE_RED(grandparent);
+                                rotate_left(grandparent, &root);
+                        }
+                }
+        }
+
+        MAKE_BLACK(root);
+        ENSURE(IS_ROOT(root));
+        *rootp = root;
+
+        return;
 }
 
 /*
@@ -1749,230 +1753,230 @@ dns_rbt_addonlevel(dns_rbtnode_t *node, dns_rbtnode_t *current, int order,
  */
 static void
 dns_rbt_deletefromlevel(dns_rbtnode_t *delete, dns_rbtnode_t **rootp) {
-       dns_rbtnode_t *child, *sibling, *parent;
-       dns_rbtnode_t *successor;
-
-       REQUIRE(delete != NULL);
-
-       /*
-        * Verify that the parent history is (apparently) correct.
-        */
-       INSIST((IS_ROOT(delete) && *rootp == delete) ||
-              (! IS_ROOT(delete) &&
-               (LEFT(PARENT(delete)) == delete ||
-                RIGHT(PARENT(delete)) == delete)));
-
-       child = NULL;
-
-       if (LEFT(delete) == NULL) {
-               if (RIGHT(delete) == NULL) {
-                       if (IS_ROOT(delete)) {
-                               /*
-                                * This is the only item in the tree.
-                                */
-                               *rootp = NULL;
-                               return;
-                       }
-               } else
-                       /*
-                        * This node has one child, on the right.
-                        */
-                       child = RIGHT(delete);
-
-       } else if (RIGHT(delete) == NULL)
-               /*
-                * This node has one child, on the left.
-                */
-               child = LEFT(delete);
-       else {
-               dns_rbtnode_t holder, *tmp = &holder;
-
-               /*
-                * This node has two children, so it cannot be directly
-                * deleted.  Find its immediate in-order successor and
-                * move it to this location, then do the deletion at the
-                * old site of the successor.
-                */
-               successor = RIGHT(delete);
-               while (LEFT(successor) != NULL)
-                       successor = LEFT(successor);
-
-               /*
-                * The successor cannot possibly have a left child;
-                * if there is any child, it is on the right.
-                */
-               if (RIGHT(successor) != NULL)
-                       child = RIGHT(successor);
-
-               /*
-                * Swap the two nodes; it would be simpler to just replace
-                * the value being deleted with that of the successor,
-                * but this rigamarole is done so the caller has complete
-                * control over the pointers (and memory allocation) of
-                * all of nodes.  If just the key value were removed from
-                * the tree, the pointer to the node would be unchanged.
-                */
-
-               /*
-                * First, put the successor in the tree location of the
-                * node to be deleted.  Save its existing tree pointer
-                * information, which will be needed when linking up
-                * delete to the successor's old location.
-                */
-               memcpy(tmp, successor, sizeof(dns_rbtnode_t));
-
-               if (IS_ROOT(delete)) {
-                       *rootp = successor;
-                       successor->is_root = ISC_TRUE;
-                       delete->is_root = ISC_FALSE;
-
-               } else
-                       if (LEFT(PARENT(delete)) == delete)
-                               LEFT(PARENT(delete)) = successor;
-                       else
-                               RIGHT(PARENT(delete)) = successor;
-
-               PARENT(successor) = PARENT(delete);
-               LEFT(successor)   = LEFT(delete);
-               RIGHT(successor)  = RIGHT(delete);
-               COLOR(successor)  = COLOR(delete);
-
-               if (LEFT(successor) != NULL)
-                       PARENT(LEFT(successor)) = successor;
-               if (RIGHT(successor) != successor)
-                       PARENT(RIGHT(successor)) = successor;
-
-               /*
-                * Now relink the node to be deleted into the
-                * successor's previous tree location.  PARENT(tmp)
-                * is the successor's original parent.
-                */
-               INSIST(! IS_ROOT(delete));
-
-               if (PARENT(tmp) == delete) {
-                       /*
-                        * Node being deleted was successor's parent.
-                        */
-                       RIGHT(successor) = delete;
-                       PARENT(delete) = successor;
-
-               } else {
-                       LEFT(PARENT(tmp)) = delete;
-                       PARENT(delete) = PARENT(tmp);
-               }
-
-               /*
-                * Original location of successor node has no left.
-                */
-               LEFT(delete)   = NULL;
-               RIGHT(delete)  = RIGHT(tmp);
-               COLOR(delete)  = COLOR(tmp);
-       }
-
-       /*
-        * Remove the node by removing the links from its parent.
-        */
-       if (! IS_ROOT(delete)) {
-               if (LEFT(PARENT(delete)) == delete)
-                       LEFT(PARENT(delete)) = child;
-               else
-                       RIGHT(PARENT(delete)) = child;
-
-               if (child != NULL)
-                       PARENT(child) = PARENT(delete);
-
-       } else {
-               /*
-                * This is the root being deleted, and at this point
-                * it is known to have just one child.
-                */
-               *rootp = child;
-               child->is_root = 1;
-               PARENT(child) = PARENT(delete);
-       }
-
-       /*
-        * Fix color violations.
-        */
-       if (IS_BLACK(delete)) {
-               parent = PARENT(delete);
-
-               while (child != *rootp && IS_BLACK(child)) {
-                       INSIST(child == NULL || ! IS_ROOT(child));
-
-                       if (LEFT(parent) == child) {
-                               sibling = RIGHT(parent);
-
-                               if (IS_RED(sibling)) {
-                                       MAKE_BLACK(sibling);
-                                       MAKE_RED(parent);
-                                       rotate_left(parent, rootp);
-                                       sibling = RIGHT(parent);
-                               }
-
-                               if (IS_BLACK(LEFT(sibling)) &&
-                                   IS_BLACK(RIGHT(sibling))) {
-                                       MAKE_RED(sibling);
-                                       child = parent;
-
-                               } else {
-
-                                       if (IS_BLACK(RIGHT(sibling))) {
-                                               MAKE_BLACK(LEFT(sibling));
-                                               MAKE_RED(sibling);
-                                               rotate_right(sibling, rootp);
-                                               sibling = RIGHT(parent);
-                                       }
-
-                                       COLOR(sibling) = COLOR(parent);
-                                       MAKE_BLACK(parent);
-                                       MAKE_BLACK(RIGHT(sibling));
-                                       rotate_left(parent, rootp);
-                                       child = *rootp;
-                               }
-
-                       } else {
-                               /*
-                                * Child is parent's right child.
-                                * Everything is doen the same as above,
-                                * except mirrored.
-                                */
-                               sibling = LEFT(parent);
-
-                               if (IS_RED(sibling)) {
-                                       MAKE_BLACK(sibling);
-                                       MAKE_RED(parent);
-                                       rotate_right(parent, rootp);
-                                       sibling = LEFT(parent);
-                               }
-
-                               if (IS_BLACK(LEFT(sibling)) &&
-                                   IS_BLACK(RIGHT(sibling))) {
-                                       MAKE_RED(sibling);
-                                       child = parent;
-
-                               } else {
-                                       if (IS_BLACK(LEFT(sibling))) {
-                                               MAKE_BLACK(RIGHT(sibling));
-                                               MAKE_RED(sibling);
-                                               rotate_left(sibling, rootp);
-                                               sibling = LEFT(parent);
-                                       }
-
-                                       COLOR(sibling) = COLOR(parent);
-                                       MAKE_BLACK(parent);
-                                       MAKE_BLACK(LEFT(sibling));
-                                       rotate_right(parent, rootp);
-                                       child = *rootp;
-                               }
-                       }
-
-                       parent = PARENT(child);
-               }
-
-               if (IS_RED(child))
-                       MAKE_BLACK(child);
-       }
+        dns_rbtnode_t *child, *sibling, *parent;
+        dns_rbtnode_t *successor;
+
+        REQUIRE(delete != NULL);
+
+        /*
+         * Verify that the parent history is (apparently) correct.
+         */
+        INSIST((IS_ROOT(delete) && *rootp == delete) ||
+               (! IS_ROOT(delete) &&
+                (LEFT(PARENT(delete)) == delete ||
+                 RIGHT(PARENT(delete)) == delete)));
+
+        child = NULL;
+
+        if (LEFT(delete) == NULL) {
+                if (RIGHT(delete) == NULL) {
+                        if (IS_ROOT(delete)) {
+                                /*
+                                 * This is the only item in the tree.
+                                 */
+                                *rootp = NULL;
+                                return;
+                        }
+                } else
+                        /*
+                         * This node has one child, on the right.
+                         */
+                        child = RIGHT(delete);
+
+        } else if (RIGHT(delete) == NULL)
+                /*
+                 * This node has one child, on the left.
+                 */
+                child = LEFT(delete);
+        else {
+                dns_rbtnode_t holder, *tmp = &holder;
+
+                /*
+                 * This node has two children, so it cannot be directly
+                 * deleted.  Find its immediate in-order successor and
+                 * move it to this location, then do the deletion at the
+                 * old site of the successor.
+                 */
+                successor = RIGHT(delete);
+                while (LEFT(successor) != NULL)
+                        successor = LEFT(successor);
+
+                /*
+                 * The successor cannot possibly have a left child;
+                 * if there is any child, it is on the right.
+                 */
+                if (RIGHT(successor) != NULL)
+                        child = RIGHT(successor);
+
+                /*
+                 * Swap the two nodes; it would be simpler to just replace
+                 * the value being deleted with that of the successor,
+                 * but this rigamarole is done so the caller has complete
+                 * control over the pointers (and memory allocation) of
+                 * all of nodes.  If just the key value were removed from
+                 * the tree, the pointer to the node would be unchanged.
+                 */
+
+                /*
+                 * First, put the successor in the tree location of the
+                 * node to be deleted.  Save its existing tree pointer
+                 * information, which will be needed when linking up
+                 * delete to the successor's old location.
+                 */
+                memcpy(tmp, successor, sizeof(dns_rbtnode_t));
+
+                if (IS_ROOT(delete)) {
+                        *rootp = successor;
+                        successor->is_root = ISC_TRUE;
+                        delete->is_root = ISC_FALSE;
+
+                } else
+                        if (LEFT(PARENT(delete)) == delete)
+                                LEFT(PARENT(delete)) = successor;
+                        else
+                                RIGHT(PARENT(delete)) = successor;
+
+                PARENT(successor) = PARENT(delete);
+                LEFT(successor)   = LEFT(delete);
+                RIGHT(successor)  = RIGHT(delete);
+                COLOR(successor)  = COLOR(delete);
+
+                if (LEFT(successor) != NULL)
+                        PARENT(LEFT(successor)) = successor;
+                if (RIGHT(successor) != successor)
+                        PARENT(RIGHT(successor)) = successor;
+
+                /*
+                 * Now relink the node to be deleted into the
+                 * successor's previous tree location.  PARENT(tmp)
+                 * is the successor's original parent.
+                 */
+                INSIST(! IS_ROOT(delete));
+
+                if (PARENT(tmp) == delete) {
+                        /*
+                         * Node being deleted was successor's parent.
+                         */
+                        RIGHT(successor) = delete;
+                        PARENT(delete) = successor;
+
+                } else {
+                        LEFT(PARENT(tmp)) = delete;
+                        PARENT(delete) = PARENT(tmp);
+                }
+
+                /*
+                 * Original location of successor node has no left.
+                 */
+                LEFT(delete)   = NULL;
+                RIGHT(delete)  = RIGHT(tmp);
+                COLOR(delete)  = COLOR(tmp);
+        }
+
+        /*
+         * Remove the node by removing the links from its parent.
+         */
+        if (! IS_ROOT(delete)) {
+                if (LEFT(PARENT(delete)) == delete)
+                        LEFT(PARENT(delete)) = child;
+                else
+                        RIGHT(PARENT(delete)) = child;
+
+                if (child != NULL)
+                        PARENT(child) = PARENT(delete);
+
+        } else {
+                /*
+                 * This is the root being deleted, and at this point
+                 * it is known to have just one child.
+                 */
+                *rootp = child;
+                child->is_root = 1;
+                PARENT(child) = PARENT(delete);
+        }
+
+        /*
+         * Fix color violations.
+         */
+        if (IS_BLACK(delete)) {
+                parent = PARENT(delete);
+
+                while (child != *rootp && IS_BLACK(child)) {
+                        INSIST(child == NULL || ! IS_ROOT(child));
+
+                        if (LEFT(parent) == child) {
+                                sibling = RIGHT(parent);
+
+                                if (IS_RED(sibling)) {
+                                        MAKE_BLACK(sibling);
+                                        MAKE_RED(parent);
+                                        rotate_left(parent, rootp);
+                                        sibling = RIGHT(parent);
+                                }
+
+                                if (IS_BLACK(LEFT(sibling)) &&
+                                    IS_BLACK(RIGHT(sibling))) {
+                                        MAKE_RED(sibling);
+                                        child = parent;
+
+                                } else {
+
+                                        if (IS_BLACK(RIGHT(sibling))) {
+                                                MAKE_BLACK(LEFT(sibling));
+                                                MAKE_RED(sibling);
+                                                rotate_right(sibling, rootp);
+                                                sibling = RIGHT(parent);
+                                        }
+
+                                        COLOR(sibling) = COLOR(parent);
+                                        MAKE_BLACK(parent);
+                                        MAKE_BLACK(RIGHT(sibling));
+                                        rotate_left(parent, rootp);
+                                        child = *rootp;
+                                }
+
+                        } else {
+                                /*
+                                 * Child is parent's right child.
+                                 * Everything is doen the same as above,
+                                 * except mirrored.
+                                 */
+                                sibling = LEFT(parent);
+
+                                if (IS_RED(sibling)) {
+                                        MAKE_BLACK(sibling);
+                                        MAKE_RED(parent);
+                                        rotate_right(parent, rootp);
+                                        sibling = LEFT(parent);
+                                }
+
+                                if (IS_BLACK(LEFT(sibling)) &&
+                                    IS_BLACK(RIGHT(sibling))) {
+                                        MAKE_RED(sibling);
+                                        child = parent;
+
+                                } else {
+                                        if (IS_BLACK(LEFT(sibling))) {
+                                                MAKE_BLACK(RIGHT(sibling));
+                                                MAKE_RED(sibling);
+                                                rotate_left(sibling, rootp);
+                                                sibling = LEFT(parent);
+                                        }
+
+                                        COLOR(sibling) = COLOR(parent);
+                                        MAKE_BLACK(parent);
+                                        MAKE_BLACK(LEFT(sibling));
+                                        rotate_right(parent, rootp);
+                                        child = *rootp;
+                                }
+                        }
+
+                        parent = PARENT(child);
+                }
+
+                if (IS_RED(child))
+                        MAKE_BLACK(child);
+        }
 }
 
 /*
@@ -1992,187 +1996,189 @@ dns_rbt_deletefromlevel(dns_rbtnode_t *delete, dns_rbtnode_t **rootp) {
  */
 static isc_result_t
 dns_rbt_deletetree(dns_rbt_t *rbt, dns_rbtnode_t *node) {
-       isc_result_t result = ISC_R_SUCCESS;
-       REQUIRE(VALID_RBT(rbt));
-
-       if (node == NULL)
-               return (result);
-
-       if (LEFT(node) != NULL) {
-               result = dns_rbt_deletetree(rbt, LEFT(node));
-               if (result != ISC_R_SUCCESS)
-                       goto done;
-               LEFT(node) = NULL;
-       }
-       if (RIGHT(node) != NULL) {
-               result = dns_rbt_deletetree(rbt, RIGHT(node));
-               if (result != ISC_R_SUCCESS)
-                       goto done;
-               RIGHT(node) = NULL;
-       }
-       if (DOWN(node) != NULL) {
-               result = dns_rbt_deletetree(rbt, DOWN(node));
-               if (result != ISC_R_SUCCESS)
-                       goto done;
-               DOWN(node) = NULL;
-       }
+        isc_result_t result = ISC_R_SUCCESS;
+        REQUIRE(VALID_RBT(rbt));
+
+        if (node == NULL)
+                return (result);
+
+        if (LEFT(node) != NULL) {
+                result = dns_rbt_deletetree(rbt, LEFT(node));
+                if (result != ISC_R_SUCCESS)
+                        goto done;
+                LEFT(node) = NULL;
+        }
+        if (RIGHT(node) != NULL) {
+                result = dns_rbt_deletetree(rbt, RIGHT(node));
+                if (result != ISC_R_SUCCESS)
+                        goto done;
+                RIGHT(node) = NULL;
+        }
+        if (DOWN(node) != NULL) {
+                result = dns_rbt_deletetree(rbt, DOWN(node));
+                if (result != ISC_R_SUCCESS)
+                        goto done;
+                DOWN(node) = NULL;
+        }
  done:
-       if (result != ISC_R_SUCCESS)
-               return (result);
+        if (result != ISC_R_SUCCESS)
+                return (result);
 
-       if (DATA(node) != NULL && rbt->data_deleter != NULL)
-               rbt->data_deleter(DATA(node), rbt->deleter_arg);
+        if (DATA(node) != NULL && rbt->data_deleter != NULL)
+                rbt->data_deleter(DATA(node), rbt->deleter_arg);
 
-       unhash_node(rbt, node);
+        unhash_node(rbt, node);
 #if DNS_RBT_USEMAGIC
-       node->magic = 0;
+        node->magic = 0;
 #endif
-       isc_mem_put(rbt->mctx, node, NODE_SIZE(node));
-       rbt->nodecount--;
-       return (result);
+
+        isc_mem_put(rbt->mctx, node, NODE_SIZE(node));
+        rbt->nodecount--;
+        return (result);
 }
 
 static void
 dns_rbt_deletetreeflat(dns_rbt_t *rbt, unsigned int quantum,
-                      dns_rbtnode_t **nodep)
+                       dns_rbtnode_t **nodep)
 {
-       dns_rbtnode_t *parent;
-       dns_rbtnode_t *node = *nodep;
-       REQUIRE(VALID_RBT(rbt));
+        dns_rbtnode_t *parent;
+        dns_rbtnode_t *node = *nodep;
+        REQUIRE(VALID_RBT(rbt));
 
  again:
-       if (node == NULL) {
-               *nodep = NULL;
-               return;
-       }
+        if (node == NULL) {
+                *nodep = NULL;
+                return;
+        }
 
  traverse:
-       if (LEFT(node) != NULL) {
-               node = LEFT(node);
-               goto traverse;
-       }
-       if (RIGHT(node) != NULL) {
-               node = RIGHT(node);
-               goto traverse;
-       }
-       if (DOWN(node) != NULL) {
-               node = DOWN(node);
-               goto traverse;
-       }
-
-       if (DATA(node) != NULL && rbt->data_deleter != NULL)
-               rbt->data_deleter(DATA(node), rbt->deleter_arg);
-
-       /*
-        * Note: we don't call unhash_node() here as we are destroying
-        * the complete rbt tree. 
+        if (LEFT(node) != NULL) {
+                node = LEFT(node);
+                goto traverse;
+        }
+        if (RIGHT(node) != NULL) {
+                node = RIGHT(node);
+                goto traverse;
+        }
+        if (DOWN(node) != NULL) {
+                node = DOWN(node);
+                goto traverse;
+        }
+
+        if (DATA(node) != NULL && rbt->data_deleter != NULL)
+                rbt->data_deleter(DATA(node), rbt->deleter_arg);
+
+        /*
+         * Note: we don't call unhash_node() here as we are destroying
+         * the complete rbt tree.
          */
 #if DNS_RBT_USEMAGIC
-       node->magic = 0;
+        node->magic = 0;
 #endif
-       parent = PARENT(node);
-       if (parent != NULL) {
-               if (LEFT(parent) == node)
-                       LEFT(parent) = NULL;
-               else if (DOWN(parent) == node)
-                       DOWN(parent) = NULL;
-               else if (RIGHT(parent) == node)
-                       RIGHT(parent) = NULL;
-       }
-       isc_mem_put(rbt->mctx, node, NODE_SIZE(node));
-       rbt->nodecount--;
-       node = parent;
-       if (quantum != 0 && --quantum == 0) {
-               *nodep = node;
-               return;
-       }
-       goto again;
+        parent = PARENT(node);
+        if (parent != NULL) {
+                if (LEFT(parent) == node)
+                        LEFT(parent) = NULL;
+                else if (DOWN(parent) == node)
+                        DOWN(parent) = NULL;
+                else if (RIGHT(parent) == node)
+                        RIGHT(parent) = NULL;
+        }
+
+        isc_mem_put(rbt->mctx, node, NODE_SIZE(node));
+        rbt->nodecount--;
+        node = parent;
+        if (quantum != 0 && --quantum == 0) {
+                *nodep = node;
+                return;
+        }
+        goto again;
 }
 
 static void
 dns_rbt_indent(int depth) {
-       int i;
+        int i;
 
-       for (i = 0; i < depth; i++)
-               putchar('\t');
+        for (i = 0; i < depth; i++)
+                putchar('\t');
 }
 
 static void
 dns_rbt_printnodename(dns_rbtnode_t *node) {
-       isc_region_t r;
-       dns_name_t name;
-       char buffer[DNS_NAME_FORMATSIZE];
-       dns_offsets_t offsets;
+        isc_region_t r;
+        dns_name_t name;
+        char buffer[DNS_NAME_FORMATSIZE];
+        dns_offsets_t offsets;
 
-       r.length = NAMELEN(node);
-       r.base = NAME(node);
+        r.length = NAMELEN(node);
+        r.base = NAME(node);
 
-       dns_name_init(&name, offsets);
-       dns_name_fromregion(&name, &r);
+        dns_name_init(&name, offsets);
+        dns_name_fromregion(&name, &r);
 
-       dns_name_format(&name, buffer, sizeof(buffer));
+        dns_name_format(&name, buffer, sizeof(buffer));
 
-       printf("%s", buffer);
+        printf("%s", buffer);
 }
 
 static void
 dns_rbt_printtree(dns_rbtnode_t *root, dns_rbtnode_t *parent, int depth) {
-       dns_rbt_indent(depth);
-
-       if (root != NULL) {
-               dns_rbt_printnodename(root);
-               printf(" (%s", IS_RED(root) ? "RED" : "black");
-               if (parent) {
-                       printf(" from ");
-                       dns_rbt_printnodename(parent);
-               }
-
-               if ((! IS_ROOT(root) && PARENT(root) != parent) ||
-                   (  IS_ROOT(root) && depth > 0 &&
-                      DOWN(PARENT(root)) != root)) {
-
-                       printf(" (BAD parent pointer! -> ");
-                       if (PARENT(root) != NULL)
-                               dns_rbt_printnodename(PARENT(root));
-                       else
-                               printf("NULL");
-                       printf(")");
-               }
-
-               printf(")\n");
-
-
-               depth++;
-
-               if (DOWN(root)) {
-                       dns_rbt_indent(depth);
-                       printf("++ BEG down from ");
-                       dns_rbt_printnodename(root);
-                       printf("\n");
-                       dns_rbt_printtree(DOWN(root), NULL, depth);
-                       dns_rbt_indent(depth);
-                       printf("-- END down from ");
-                       dns_rbt_printnodename(root);
-                       printf("\n");
-               }
-
-               if (IS_RED(root) && IS_RED(LEFT(root)))
-                   printf("** Red/Red color violation on left\n");
-               dns_rbt_printtree(LEFT(root), root, depth);
-
-               if (IS_RED(root) && IS_RED(RIGHT(root)))
-                   printf("** Red/Red color violation on right\n");
-               dns_rbt_printtree(RIGHT(root), root, depth);
-
-       } else
-               printf("NULL\n");
+        dns_rbt_indent(depth);
+
+        if (root != NULL) {
+                dns_rbt_printnodename(root);
+                printf(" (%s", IS_RED(root) ? "RED" : "black");
+                if (parent) {
+                        printf(" from ");
+                        dns_rbt_printnodename(parent);
+                }
+
+                if ((! IS_ROOT(root) && PARENT(root) != parent) ||
+                    (  IS_ROOT(root) && depth > 0 &&
+                       DOWN(PARENT(root)) != root)) {
+
+                        printf(" (BAD parent pointer! -> ");
+                        if (PARENT(root) != NULL)
+                                dns_rbt_printnodename(PARENT(root));
+                        else
+                                printf("NULL");
+                        printf(")");
+                }
+
+                printf(")\n");
+
+
+                depth++;
+
+                if (DOWN(root)) {
+                        dns_rbt_indent(depth);
+                        printf("++ BEG down from ");
+                        dns_rbt_printnodename(root);
+                        printf("\n");
+                        dns_rbt_printtree(DOWN(root), NULL, depth);
+                        dns_rbt_indent(depth);
+                        printf("-- END down from ");
+                        dns_rbt_printnodename(root);
+                        printf("\n");
+                }
+
+                if (IS_RED(root) && IS_RED(LEFT(root)))
+                    printf("** Red/Red color violation on left\n");
+                dns_rbt_printtree(LEFT(root), root, depth);
+
+                if (IS_RED(root) && IS_RED(RIGHT(root)))
+                    printf("** Red/Red color violation on right\n");
+                dns_rbt_printtree(RIGHT(root), root, depth);
+
+        } else
+                printf("NULL\n");
 }
 
 void
 dns_rbt_printall(dns_rbt_t *rbt) {
-       REQUIRE(VALID_RBT(rbt));
+        REQUIRE(VALID_RBT(rbt));
 
-       dns_rbt_printtree(rbt->root, NULL, 0);
+        dns_rbt_printtree(rbt->root, NULL, 0);
 }
 
 /*
@@ -2181,364 +2187,364 @@ dns_rbt_printall(dns_rbt_t *rbt) {
 
 void
 dns_rbtnodechain_init(dns_rbtnodechain_t *chain, isc_mem_t *mctx) {
-       /*
-        * Initialize 'chain'.
-        */
+        /*
+         * Initialize 'chain'.
+         */
 
-       REQUIRE(chain != NULL);
+        REQUIRE(chain != NULL);
 
-       chain->mctx = mctx;
-       chain->end = NULL;
-       chain->level_count = 0;
-       chain->level_matches = 0;
+        chain->mctx = mctx;
+        chain->end = NULL;
+        chain->level_count = 0;
+        chain->level_matches = 0;
 
-       chain->magic = CHAIN_MAGIC;
+        chain->magic = CHAIN_MAGIC;
 }
 
 isc_result_t
 dns_rbtnodechain_current(dns_rbtnodechain_t *chain, dns_name_t *name,
-                        dns_name_t *origin, dns_rbtnode_t **node)
+                         dns_name_t *origin, dns_rbtnode_t **node)
 {
-       isc_result_t result = ISC_R_SUCCESS;
-
-       REQUIRE(VALID_CHAIN(chain));
-
-       if (node != NULL)
-               *node = chain->end;
-
-       if (chain->end == NULL)
-               return (ISC_R_NOTFOUND);
-
-       if (name != NULL) {
-               NODENAME(chain->end, name);
-
-               if (chain->level_count == 0) {
-                       /*
-                        * Names in the top level tree are all absolute.
-                        * Always make 'name' relative.
-                        */
-                       INSIST(dns_name_isabsolute(name));
-
-                       /*
-                        * This is cheaper than dns_name_getlabelsequence().
-                        */
-                       name->labels--;
-                       name->length--;
-                       name->attributes &= ~DNS_NAMEATTR_ABSOLUTE;
-               }
-       }
-
-       if (origin != NULL) {
-               if (chain->level_count > 0)
-                       result = chain_name(chain, origin, ISC_FALSE);
-               else
-                       result = dns_name_copy(dns_rootname, origin, NULL);
-       }
-
-       return (result);
+        isc_result_t result = ISC_R_SUCCESS;
+
+        REQUIRE(VALID_CHAIN(chain));
+
+        if (node != NULL)
+                *node = chain->end;
+
+        if (chain->end == NULL)
+                return (ISC_R_NOTFOUND);
+
+        if (name != NULL) {
+                NODENAME(chain->end, name);
+
+                if (chain->level_count == 0) {
+                        /*
+                         * Names in the top level tree are all absolute.
+                         * Always make 'name' relative.
+                         */
+                        INSIST(dns_name_isabsolute(name));
+
+                        /*
+                         * This is cheaper than dns_name_getlabelsequence().
+                         */
+                        name->labels--;
+                        name->length--;
+                        name->attributes &= ~DNS_NAMEATTR_ABSOLUTE;
+                }
+        }
+
+        if (origin != NULL) {
+                if (chain->level_count > 0)
+                        result = chain_name(chain, origin, ISC_FALSE);
+                else
+                        result = dns_name_copy(dns_rootname, origin, NULL);
+        }
+
+        return (result);
 }
 
 isc_result_t
 dns_rbtnodechain_prev(dns_rbtnodechain_t *chain, dns_name_t *name,
-                     dns_name_t *origin)
+                      dns_name_t *origin)
 {
-       dns_rbtnode_t *current, *previous, *predecessor;
-       isc_result_t result = ISC_R_SUCCESS;
-       isc_boolean_t new_origin = ISC_FALSE;
-
-       REQUIRE(VALID_CHAIN(chain) && chain->end != NULL);
-
-       predecessor = NULL;
-
-       current = chain->end;
-
-       if (LEFT(current) != NULL) {
-               /*
-                * Moving left one then right as far as possible is the
-                * previous node, at least for this level.
-                */
-               current = LEFT(current);
-
-               while (RIGHT(current) != NULL)
-                       current = RIGHT(current);
-
-               predecessor = current;
-
-       } else {
-               /*
-                * No left links, so move toward the root.  If at any point on
-                * the way there the link from parent to child is a right
-                * link, then the parent is the previous node, at least
-                * for this level.
-                */
-               while (! IS_ROOT(current)) {
-                       previous = current;
-                       current = PARENT(current);
-
-                       if (RIGHT(current) == previous) {
-                               predecessor = current;
-                               break;
-                       }
-               }
-       }
-
-       if (predecessor != NULL) {
-               /*
-                * Found a predecessor node in this level.  It might not
-                * really be the predecessor, however.
-                */
-               if (DOWN(predecessor) != NULL) {
-                       /*
-                        * The predecessor is really down at least one level.
-                        * Go down and as far right as possible, and repeat
-                        * as long as the rightmost node has a down pointer.
-                        */
-                       do {
-                               /*
-                                * XXX DCL Need to do something about origins
-                                * here. See whether to go down, and if so
-                                * whether it is truly what Bob calls a
-                                * new origin.
-                                */
-                               ADD_LEVEL(chain, predecessor);
-                               predecessor = DOWN(predecessor);
-
-                               /* XXX DCL duplicated from above; clever
-                                * way to unduplicate? */
-
-                               while (RIGHT(predecessor) != NULL)
-                                       predecessor = RIGHT(predecessor);
-                       } while (DOWN(predecessor) != NULL);
-
-                       /* XXX DCL probably needs work on the concept */
-                       if (origin != NULL)
-                               new_origin = ISC_TRUE;
-               }
-
-       } else if (chain->level_count > 0) {
-               /*
-                * Dang, didn't find a predecessor in this level.
-                * Got to the root of this level without having traversed
-                * any right links.  Ascend the tree one level; the
-                * node that points to this tree is the predecessor.
-                */
-               INSIST(chain->level_count > 0 && IS_ROOT(current));
-               predecessor = chain->levels[--chain->level_count];
-
-               /* XXX DCL probably needs work on the concept */
-               /*
-                * Don't declare an origin change when the new origin is "."
-                * at the top level tree, because "." is declared as the origin
-                * for the second level tree.
-                */
-               if (origin != NULL &&
-                   (chain->level_count > 0 || OFFSETLEN(predecessor) > 1))
-                       new_origin = ISC_TRUE;
-       }
-
-       if (predecessor != NULL) {
-               chain->end = predecessor;
-
-               if (new_origin) {
-                       result = dns_rbtnodechain_current(chain, name, origin,
-                                                         NULL);
-                       if (result == ISC_R_SUCCESS)
-                               result = DNS_R_NEWORIGIN;
-
-               } else
-                       result = dns_rbtnodechain_current(chain, name, NULL,
-                                                         NULL);
-
-       } else
-               result = ISC_R_NOMORE;
-
-       return (result);
+        dns_rbtnode_t *current, *previous, *predecessor;
+        isc_result_t result = ISC_R_SUCCESS;
+        isc_boolean_t new_origin = ISC_FALSE;
+
+        REQUIRE(VALID_CHAIN(chain) && chain->end != NULL);
+
+        predecessor = NULL;
+
+        current = chain->end;
+
+        if (LEFT(current) != NULL) {
+                /*
+                 * Moving left one then right as far as possible is the
+                 * previous node, at least for this level.
+                 */
+                current = LEFT(current);
+
+                while (RIGHT(current) != NULL)
+                        current = RIGHT(current);
+
+                predecessor = current;
+
+        } else {
+                /*
+                 * No left links, so move toward the root.  If at any point on
+                 * the way there the link from parent to child is a right
+                 * link, then the parent is the previous node, at least
+                 * for this level.
+                 */
+                while (! IS_ROOT(current)) {
+                        previous = current;
+                        current = PARENT(current);
+
+                        if (RIGHT(current) == previous) {
+                                predecessor = current;
+                                break;
+                        }
+                }
+        }
+
+        if (predecessor != NULL) {
+                /*
+                 * Found a predecessor node in this level.  It might not
+                 * really be the predecessor, however.
+                 */
+                if (DOWN(predecessor) != NULL) {
+                        /*
+                         * The predecessor is really down at least one level.
+                         * Go down and as far right as possible, and repeat
+                         * as long as the rightmost node has a down pointer.
+                         */
+                        do {
+                                /*
+                                 * XXX DCL Need to do something about origins
+                                 * here. See whether to go down, and if so
+                                 * whether it is truly what Bob calls a
+                                 * new origin.
+                                 */
+                                ADD_LEVEL(chain, predecessor);
+                                predecessor = DOWN(predecessor);
+
+                                /* XXX DCL duplicated from above; clever
+                                 * way to unduplicate? */
+
+                                while (RIGHT(predecessor) != NULL)
+                                        predecessor = RIGHT(predecessor);
+                        } while (DOWN(predecessor) != NULL);
+
+                        /* XXX DCL probably needs work on the concept */
+                        if (origin != NULL)
+                                new_origin = ISC_TRUE;
+                }
+
+        } else if (chain->level_count > 0) {
+                /*
+                 * Dang, didn't find a predecessor in this level.
+                 * Got to the root of this level without having traversed
+                 * any right links.  Ascend the tree one level; the
+                 * node that points to this tree is the predecessor.
+                 */
+                INSIST(chain->level_count > 0 && IS_ROOT(current));
+                predecessor = chain->levels[--chain->level_count];
+
+                /* XXX DCL probably needs work on the concept */
+                /*
+                 * Don't declare an origin change when the new origin is "."
+                 * at the top level tree, because "." is declared as the origin
+                 * for the second level tree.
+                 */
+                if (origin != NULL &&
+                    (chain->level_count > 0 || OFFSETLEN(predecessor) > 1))
+                        new_origin = ISC_TRUE;
+        }
+
+        if (predecessor != NULL) {
+                chain->end = predecessor;
+
+                if (new_origin) {
+                        result = dns_rbtnodechain_current(chain, name, origin,
+                                                          NULL);
+                        if (result == ISC_R_SUCCESS)
+                                result = DNS_R_NEWORIGIN;
+
+                } else
+                        result = dns_rbtnodechain_current(chain, name, NULL,
+                                                          NULL);
+
+        } else
+                result = ISC_R_NOMORE;
+
+        return (result);
 }
 
 isc_result_t
 dns_rbtnodechain_next(dns_rbtnodechain_t *chain, dns_name_t *name,
-                     dns_name_t *origin)
+                      dns_name_t *origin)
 {
-       dns_rbtnode_t *current, *previous, *successor;
-       isc_result_t result = ISC_R_SUCCESS;
-       isc_boolean_t new_origin = ISC_FALSE;
-
-       REQUIRE(VALID_CHAIN(chain) && chain->end != NULL);
-
-       successor = NULL;
-
-       current = chain->end;
-
-       /*
-        * If there is a level below this node, the next node is the leftmost
-        * node of the next level.
-        */
-       if (DOWN(current) != NULL) {
-               /*
-                * Don't declare an origin change when the new origin is "."
-                * at the second level tree, because "." is already declared
-                * as the origin for the top level tree.
-                */
-               if (chain->level_count > 0 ||
-                   OFFSETLEN(current) > 1)
-                       new_origin = ISC_TRUE;
-
-               ADD_LEVEL(chain, current);
-               current = DOWN(current);
-
-               while (LEFT(current) != NULL)
-                       current = LEFT(current);
-
-               successor = current;
-
-       } else if (RIGHT(current) == NULL) {
-               /*
-                * The successor is up, either in this level or a previous one.
-                * Head back toward the root of the tree, looking for any path
-                * that was via a left link; the successor is the node that has
-                * that left link.  In the event the root of the level is
-                * reached without having traversed any left links, ascend one
-                * level and look for either a right link off the point of
-                * ascent, or search for a left link upward again, repeating
-                * ascents until either case is true.
-                */
-               do {
-                       while (! IS_ROOT(current)) {
-                               previous = current;
-                               current = PARENT(current);
-
-                               if (LEFT(current) == previous) {
-                                       successor = current;
-                                       break;
-                               }
-                       }
-
-                       if (successor == NULL) {
-                               /*
-                                * Reached the root without having traversed
-                                * any left pointers, so this level is done.
-                                */
-                               if (chain->level_count == 0)
-                                       break;
-
-                               current = chain->levels[--chain->level_count];
-                               new_origin = ISC_TRUE;
-
-                               if (RIGHT(current) != NULL)
-                                       break;
-                       }
-               } while (successor == NULL);
-       }
-
-       if (successor == NULL && RIGHT(current) != NULL) {
-               current = RIGHT(current);
-
-               while (LEFT(current) != NULL)
-                       current = LEFT(current);
-
-               successor = current;
-       }
-
-       if (successor != NULL) {
-               chain->end = successor;
-
-               /*
-                * It is not necessary to use dns_rbtnodechain_current like
-                * the other functions because this function will never
-                * find a node in the topmost level.  This is because the
-                * root level will never be more than one name, and everything
-                * in the megatree is a successor to that node, down at
-                * the second level or below.
-                */
-
-               if (name != NULL)
-                       NODENAME(chain->end, name);
-
-               if (new_origin) {
-                       if (origin != NULL)
-                               result = chain_name(chain, origin, ISC_FALSE);
-
-                       if (result == ISC_R_SUCCESS)
-                               result = DNS_R_NEWORIGIN;
-
-               } else
-                       result = ISC_R_SUCCESS;
-
-       } else
-               result = ISC_R_NOMORE;
-
-       return (result);
+        dns_rbtnode_t *current, *previous, *successor;
+        isc_result_t result = ISC_R_SUCCESS;
+        isc_boolean_t new_origin = ISC_FALSE;
+
+        REQUIRE(VALID_CHAIN(chain) && chain->end != NULL);
+
+        successor = NULL;
+
+        current = chain->end;
+
+        /*
+         * If there is a level below this node, the next node is the leftmost
+         * node of the next level.
+         */
+        if (DOWN(current) != NULL) {
+                /*
+                 * Don't declare an origin change when the new origin is "."
+                 * at the second level tree, because "." is already declared
+                 * as the origin for the top level tree.
+                 */
+                if (chain->level_count > 0 ||
+                    OFFSETLEN(current) > 1)
+                        new_origin = ISC_TRUE;
+
+                ADD_LEVEL(chain, current);
+                current = DOWN(current);
+
+                while (LEFT(current) != NULL)
+                        current = LEFT(current);
+
+                successor = current;
+
+        } else if (RIGHT(current) == NULL) {
+                /*
+                 * The successor is up, either in this level or a previous one.
+                 * Head back toward the root of the tree, looking for any path
+                 * that was via a left link; the successor is the node that has
+                 * that left link.  In the event the root of the level is
+                 * reached without having traversed any left links, ascend one
+                 * level and look for either a right link off the point of
+                 * ascent, or search for a left link upward again, repeating
+                 * ascents until either case is true.
+                 */
+                do {
+                        while (! IS_ROOT(current)) {
+                                previous = current;
+                                current = PARENT(current);
+
+                                if (LEFT(current) == previous) {
+                                        successor = current;
+                                        break;
+                                }
+                        }
+
+                        if (successor == NULL) {
+                                /*
+                                 * Reached the root without having traversed
+                                 * any left pointers, so this level is done.
+                                 */
+                                if (chain->level_count == 0)
+                                        break;
+
+                                current = chain->levels[--chain->level_count];
+                                new_origin = ISC_TRUE;
+
+                                if (RIGHT(current) != NULL)
+                                        break;
+                        }
+                } while (successor == NULL);
+        }
+
+        if (successor == NULL && RIGHT(current) != NULL) {
+                current = RIGHT(current);
+
+                while (LEFT(current) != NULL)
+                        current = LEFT(current);
+
+                successor = current;
+        }
+
+        if (successor != NULL) {
+                chain->end = successor;
+
+                /*
+                 * It is not necessary to use dns_rbtnodechain_current like
+                 * the other functions because this function will never
+                 * find a node in the topmost level.  This is because the
+                 * root level will never be more than one name, and everything
+                 * in the megatree is a successor to that node, down at
+                 * the second level or below.
+                 */
+
+                if (name != NULL)
+                        NODENAME(chain->end, name);
+
+                if (new_origin) {
+                        if (origin != NULL)
+                                result = chain_name(chain, origin, ISC_FALSE);
+
+                        if (result == ISC_R_SUCCESS)
+                                result = DNS_R_NEWORIGIN;
+
+                } else
+                        result = ISC_R_SUCCESS;
+
+        } else
+                result = ISC_R_NOMORE;
+
+        return (result);
 }
 
 isc_result_t
 dns_rbtnodechain_first(dns_rbtnodechain_t *chain, dns_rbt_t *rbt,
-                      dns_name_t *name, dns_name_t *origin)
+                       dns_name_t *name, dns_name_t *origin)
 
 {
-       isc_result_t result;
+        isc_result_t result;
 
-       REQUIRE(VALID_RBT(rbt));
-       REQUIRE(VALID_CHAIN(chain));
+        REQUIRE(VALID_RBT(rbt));
+        REQUIRE(VALID_CHAIN(chain));
 
-       dns_rbtnodechain_reset(chain);
+        dns_rbtnodechain_reset(chain);
 
-       chain->end = rbt->root;
+        chain->end = rbt->root;
 
-       result = dns_rbtnodechain_current(chain, name, origin, NULL);
+        result = dns_rbtnodechain_current(chain, name, origin, NULL);
 
-       if (result == ISC_R_SUCCESS)
-               result = DNS_R_NEWORIGIN;
+        if (result == ISC_R_SUCCESS)
+                result = DNS_R_NEWORIGIN;
 
-       return (result);
+        return (result);
 }
 
 isc_result_t
 dns_rbtnodechain_last(dns_rbtnodechain_t *chain, dns_rbt_t *rbt,
-                      dns_name_t *name, dns_name_t *origin)
+                       dns_name_t *name, dns_name_t *origin)
 
 {
-       isc_result_t result;
+        isc_result_t result;
 
-       REQUIRE(VALID_RBT(rbt));
-       REQUIRE(VALID_CHAIN(chain));
+        REQUIRE(VALID_RBT(rbt));
+        REQUIRE(VALID_CHAIN(chain));
 
-       dns_rbtnodechain_reset(chain);
+        dns_rbtnodechain_reset(chain);
 
-       result = move_chain_to_last(chain, rbt->root);
-       if (result != ISC_R_SUCCESS)
-               return (result);
+        result = move_chain_to_last(chain, rbt->root);
+        if (result != ISC_R_SUCCESS)
+                return (result);
 
-       result = dns_rbtnodechain_current(chain, name, origin, NULL);
+        result = dns_rbtnodechain_current(chain, name, origin, NULL);
 
-       if (result == ISC_R_SUCCESS)
-               result = DNS_R_NEWORIGIN;
+        if (result == ISC_R_SUCCESS)
+                result = DNS_R_NEWORIGIN;
 
-       return (result);
+        return (result);
 }
 
 
 void
 dns_rbtnodechain_reset(dns_rbtnodechain_t *chain) {
-       /*
-        * Free any dynamic storage associated with 'chain', and then
-        * reinitialize 'chain'.
-        */
+        /*
+         * Free any dynamic storage associated with 'chain', and then
+         * reinitialize 'chain'.
+         */
 
-       REQUIRE(VALID_CHAIN(chain));
+        REQUIRE(VALID_CHAIN(chain));
 
-       chain->end = NULL;
-       chain->level_count = 0;
-       chain->level_matches = 0;
+        chain->end = NULL;
+        chain->level_count = 0;
+        chain->level_matches = 0;
 }
 
 void
 dns_rbtnodechain_invalidate(dns_rbtnodechain_t *chain) {
-       /*
-        * Free any dynamic storage associated with 'chain', and then
-        * invalidate 'chain'.
-        */
+        /*
+         * Free any dynamic storage associated with 'chain', and then
+         * invalidate 'chain'.
+         */
 
-       dns_rbtnodechain_reset(chain);
+        dns_rbtnodechain_reset(chain);
 
-       chain->magic = 0;
+        chain->magic = 0;
 }
index 6b7d6403eeb99352464e3bacea93bb17a16302b1..f6b06dabd3c90ae5ab2b68c2abef1af144ea6c71 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: rbtdb.c,v 1.246 2007/06/19 06:19:29 marka Exp $ */
+/* $Id: rbtdb.c,v 1.247 2007/10/19 17:15:53 explorer Exp $ */
 
 /*! \file */
 
 
 #include <config.h>
 
+#include <isc/heap.h>
 #include <isc/event.h>
 #include <isc/mem.h>
+#include <isc/platform.h>
 #include <isc/print.h>
 #include <isc/mutex.h>
 #include <isc/random.h>
 #endif
 
 #ifdef DNS_RBTDB_VERSION64
-#define RBTDB_MAGIC                    ISC_MAGIC('R', 'B', 'D', '8')
+#define RBTDB_MAGIC                     ISC_MAGIC('R', 'B', 'D', '8')
 #else
-#define RBTDB_MAGIC                    ISC_MAGIC('R', 'B', 'D', '4')
+#define RBTDB_MAGIC                     ISC_MAGIC('R', 'B', 'D', '4')
 #endif
 
 /*%
  * Note that "impmagic" is not the first four bytes of the struct, so
  * ISC_MAGIC_VALID cannot be used.
  */
-#define VALID_RBTDB(rbtdb)     ((rbtdb) != NULL && \
-                                (rbtdb)->common.impmagic == RBTDB_MAGIC)
+#define VALID_RBTDB(rbtdb)      ((rbtdb) != NULL && \
+                                 (rbtdb)->common.impmagic == RBTDB_MAGIC)
 
 #ifdef DNS_RBTDB_VERSION64
-typedef isc_uint64_t                   rbtdb_serial_t;
+typedef isc_uint64_t                    rbtdb_serial_t;
 /*%
  * Make casting easier in symbolic debuggers by using different names
  * for the 64 bit version.
@@ -84,25 +86,25 @@ typedef isc_uint64_t                        rbtdb_serial_t;
 #define rdatasetheader_t rdatasetheader64_t
 #define rbtdb_version_t rbtdb_version64_t
 #else
-typedef isc_uint32_t                   rbtdb_serial_t;
+typedef isc_uint32_t                    rbtdb_serial_t;
 #endif
 
-typedef isc_uint32_t                   rbtdb_rdatatype_t;
+typedef isc_uint32_t                    rbtdb_rdatatype_t;
 
-#define RBTDB_RDATATYPE_BASE(type)     ((dns_rdatatype_t)((type) & 0xFFFF))
-#define RBTDB_RDATATYPE_EXT(type)      ((dns_rdatatype_t)((type) >> 16))
-#define RBTDB_RDATATYPE_VALUE(b, e)    (((e) << 16) | (b))
+#define RBTDB_RDATATYPE_BASE(type)      ((dns_rdatatype_t)((type) & 0xFFFF))
+#define RBTDB_RDATATYPE_EXT(type)       ((dns_rdatatype_t)((type) >> 16))
+#define RBTDB_RDATATYPE_VALUE(b, e)     (((e) << 16) | (b))
 
 #define RBTDB_RDATATYPE_SIGNSEC \
-               RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_nsec)
+                RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_nsec)
 #define RBTDB_RDATATYPE_SIGNS \
-               RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_ns)
+                RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_ns)
 #define RBTDB_RDATATYPE_SIGCNAME \
-               RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_cname)
+                RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_cname)
 #define RBTDB_RDATATYPE_SIGDNAME \
-               RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_dname)
+                RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_dname)
 #define RBTDB_RDATATYPE_NCACHEANY \
-               RBTDB_RDATATYPE_VALUE(0, dns_rdatatype_any)
+                RBTDB_RDATATYPE_VALUE(0, dns_rdatatype_any)
 
 /*
  * We use rwlock for DB lock only when ISC_RWLOCK_USEATOMIC is non 0.
@@ -119,15 +121,15 @@ typedef isc_uint32_t                      rbtdb_rdatatype_t;
 #endif
 
 #if DNS_RBTDB_USERWLOCK
-#define RBTDB_INITLOCK(l)      isc_rwlock_init((l), 0, 0)
-#define RBTDB_DESTROYLOCK(l)   isc_rwlock_destroy(l)
-#define RBTDB_LOCK(l, t)       RWLOCK((l), (t))
-#define RBTDB_UNLOCK(l, t)     RWUNLOCK((l), (t))
+#define RBTDB_INITLOCK(l)       isc_rwlock_init((l), 0, 0)
+#define RBTDB_DESTROYLOCK(l)    isc_rwlock_destroy(l)
+#define RBTDB_LOCK(l, t)        RWLOCK((l), (t))
+#define RBTDB_UNLOCK(l, t)      RWUNLOCK((l), (t))
 #else
-#define RBTDB_INITLOCK(l)      isc_mutex_init(l)
-#define RBTDB_DESTROYLOCK(l)   DESTROYLOCK(l)
-#define RBTDB_LOCK(l, t)       LOCK(l)
-#define RBTDB_UNLOCK(l, t)     UNLOCK(l)
+#define RBTDB_INITLOCK(l)       isc_mutex_init(l)
+#define RBTDB_DESTROYLOCK(l)    DESTROYLOCK(l)
+#define RBTDB_LOCK(l, t)        LOCK(l)
+#define RBTDB_UNLOCK(l, t)      UNLOCK(l)
 #endif
 
 /*
@@ -152,31 +154,31 @@ typedef isc_uint32_t                      rbtdb_rdatatype_t;
 #if defined(ISC_RWLOCK_USEATOMIC) && defined(DNS_RBT_USEISCREFCOUNT)
 typedef isc_rwlock_t nodelock_t;
 
-#define NODE_INITLOCK(l)       isc_rwlock_init((l), 0, 0)
-#define NODE_DESTROYLOCK(l)    isc_rwlock_destroy(l)
-#define NODE_LOCK(l, t)                RWLOCK((l), (t))
-#define NODE_UNLOCK(l, t)      RWUNLOCK((l), (t))
-#define NODE_TRYUPGRADE(l)     isc_rwlock_tryupgrade(l)
-
-#define NODE_STRONGLOCK(l)     ((void)0)
-#define NODE_STRONGUNLOCK(l)   ((void)0)
-#define NODE_WEAKLOCK(l, t)    NODE_LOCK(l, t)
-#define NODE_WEAKUNLOCK(l, t)  NODE_UNLOCK(l, t)
-#define NODE_WEAKDOWNGRADE(l)  isc_rwlock_downgrade(l)
+#define NODE_INITLOCK(l)        isc_rwlock_init((l), 0, 0)
+#define NODE_DESTROYLOCK(l)     isc_rwlock_destroy(l)
+#define NODE_LOCK(l, t)         RWLOCK((l), (t))
+#define NODE_UNLOCK(l, t)       RWUNLOCK((l), (t))
+#define NODE_TRYUPGRADE(l)      isc_rwlock_tryupgrade(l)
+
+#define NODE_STRONGLOCK(l)      ((void)0)
+#define NODE_STRONGUNLOCK(l)    ((void)0)
+#define NODE_WEAKLOCK(l, t)     NODE_LOCK(l, t)
+#define NODE_WEAKUNLOCK(l, t)   NODE_UNLOCK(l, t)
+#define NODE_WEAKDOWNGRADE(l)   isc_rwlock_downgrade(l)
 #else
 typedef isc_mutex_t nodelock_t;
 
-#define NODE_INITLOCK(l)       isc_mutex_init(l)
-#define NODE_DESTROYLOCK(l)    DESTROYLOCK(l)
-#define NODE_LOCK(l, t)                LOCK(l)
-#define NODE_UNLOCK(l, t)      UNLOCK(l)
-#define NODE_TRYUPGRADE(l)     ISC_R_SUCCESS
-
-#define NODE_STRONGLOCK(l)     LOCK(l)
-#define NODE_STRONGUNLOCK(l)   UNLOCK(l)
-#define NODE_WEAKLOCK(l, t)    ((void)0)
-#define NODE_WEAKUNLOCK(l, t)  ((void)0)
-#define NODE_WEAKDOWNGRADE(l)  ((void)0)
+#define NODE_INITLOCK(l)        isc_mutex_init(l)
+#define NODE_DESTROYLOCK(l)     DESTROYLOCK(l)
+#define NODE_LOCK(l, t)         LOCK(l)
+#define NODE_UNLOCK(l, t)       UNLOCK(l)
+#define NODE_TRYUPGRADE(l)      ISC_R_SUCCESS
+
+#define NODE_STRONGLOCK(l)      LOCK(l)
+#define NODE_STRONGUNLOCK(l)    UNLOCK(l)
+#define NODE_WEAKLOCK(l, t)     ((void)0)
+#define NODE_WEAKUNLOCK(l, t)   ((void)0)
+#define NODE_WEAKDOWNGRADE(l)   ((void)0)
 #endif
 
 #ifndef DNS_RDATASET_FIXED
@@ -184,78 +186,105 @@ typedef isc_mutex_t nodelock_t;
 #endif
 
 /*
- * Allow clients with a virtual time of upto 5 minutes in the past to see
+ * Allow clients with a virtual time of up to 5 minutes in the past to see
  * records that would have otherwise have expired.
  */
 #define RBTDB_VIRTUAL 300
 
 struct noqname {
-       dns_name_t name;
-       void *     nsec;
-       void *     nsecsig;
+        dns_name_t name;
+        void *     nsec;
+        void *     nsecsig;
 };
 
-typedef struct acachectl acachectl_t;  
+typedef struct acachectl acachectl_t;
 
 typedef struct rdatasetheader {
-       /*%
-        * Locked by the owning node's lock.
-        */
-       rbtdb_serial_t                  serial;
-       dns_ttl_t                       ttl;
-       rbtdb_rdatatype_t               type;
-       isc_uint16_t                    attributes;
-       dns_trust_t                     trust;
-       struct noqname                  *noqname;
-       /*%<
-        * We don't use the LIST macros, because the LIST structure has
-        * both head and tail pointers, and is doubly linked.
-        */
-
-       struct rdatasetheader           *next;
-       /*%<
-        * If this is the top header for an rdataset, 'next' points
-        * to the top header for the next rdataset (i.e., the next type).
-        * Otherwise, it points up to the header whose down pointer points
-        * at this header.
-        */
-         
-       struct rdatasetheader           *down;
-       /*%<
-        * Points to the header for the next older version of
-        * this rdataset.
-        */
-
-       isc_uint32_t                    count;
-       /*%<
-        * Monotonously increased every time this rdataset is bound so that
-        * it is used as the base of the starting point in DNS responses
-        * when the "cyclic" rrset-order is required.  Since the ordering
-        * should not be so crucial, no lock is set for the counter for
-        * performance reasons.
-        */
-
-       acachectl_t                     *additional_auth;
-       acachectl_t                     *additional_glue;
+        /*%
+         * Locked by the owning node's lock.
+         */
+        rbtdb_serial_t                  serial;
+        dns_ttl_t                       rdh_ttl;
+        rbtdb_rdatatype_t               type;
+        isc_uint16_t                    attributes;
+        dns_trust_t                     trust;
+        struct noqname                  *noqname;
+        /*%<
+         * We don't use the LIST macros, because the LIST structure has
+         * both head and tail pointers, and is doubly linked.
+         */
+
+        struct rdatasetheader           *next;
+        /*%<
+         * If this is the top header for an rdataset, 'next' points
+         * to the top header for the next rdataset (i.e., the next type).
+         * Otherwise, it points up to the header whose down pointer points
+         * at this header.
+         */
+
+        struct rdatasetheader           *down;
+        /*%<
+         * Points to the header for the next older version of
+         * this rdataset.
+         */
+
+        isc_uint32_t                    count;
+        /*%<
+         * Monotonously increased every time this rdataset is bound so that
+         * it is used as the base of the starting point in DNS responses
+         * when the "cyclic" rrset-order is required.  Since the ordering
+         * should not be so crucial, no lock is set for the counter for
+         * performance reasons.
+         */
+
+        acachectl_t                     *additional_auth;
+        acachectl_t                     *additional_glue;
+
+        dns_rbtnode_t                   *node;
+        isc_stdtime_t                   last_used;
+        ISC_LINK(struct rdatasetheader) lru_link;
+        /*%<
+         * Used for LRU-based cache management.  We should probably make
+         * these cache-DB specific.  We might also make it a pointer and
+         * ensure only the top header has a valid link to save memory.
+         * The linked-list is locked by the rbtdb->lrulock.
+         */
+
+        /*
+         * It's possible this should not be here anymore, but instead
+         * referenced from the bucket's heap directly.
+         */
+#if 0
+        isc_heap_t                      *heap;
+#endif
+        unsigned int                    heap_index;
+        /*%<
+         * Used for TTL-based cache cleaning.
+         */
 } rdatasetheader_t;
 
-#define RDATASET_ATTR_NONEXISTENT      0x0001
-#define RDATASET_ATTR_STALE            0x0002
-#define RDATASET_ATTR_IGNORE           0x0004
-#define RDATASET_ATTR_RETAIN           0x0008
-#define RDATASET_ATTR_NXDOMAIN         0x0010
+typedef ISC_LIST(rdatasetheader_t)      rdatasetheaderlist_t;
+typedef ISC_LIST(dns_rbtnode_t)         rbtnodelist_t;
+
+#define RDATASET_ATTR_NONEXISTENT       0x0001
+#define RDATASET_ATTR_STALE             0x0002
+#define RDATASET_ATTR_IGNORE            0x0004
+#define RDATASET_ATTR_RETAIN            0x0008
+#define RDATASET_ATTR_NXDOMAIN          0x0010
+#define RDATASET_ATTR_CACHE             0x1000 /* for debug */
+#define RDATASET_ATTR_CANCELED          0x2000 /* for debug */
 
 typedef struct acache_cbarg {
-       dns_rdatasetadditional_t        type;
-       unsigned int                    count;
-       dns_db_t                        *db;
-       dns_dbnode_t                    *node;
-       rdatasetheader_t                *header;
+        dns_rdatasetadditional_t        type;
+        unsigned int                    count;
+        dns_db_t                        *db;
+        dns_dbnode_t                    *node;
+        rdatasetheader_t                *header;
 } acache_cbarg_t;
 
 struct acachectl {
-       dns_acacheentry_t               *entry;
-       acache_cbarg_t                  *cbarg;
+        dns_acacheentry_t               *entry;
+        acache_cbarg_t                  *cbarg;
 };
 
 /*
@@ -266,118 +295,162 @@ struct acachectl {
  * expired.
  */
 
-#undef IGNORE                  /* WIN32 winbase.h defines this. */
+#undef IGNORE                   /* WIN32 winbase.h defines this. */
 
 #define EXISTS(header) \
-       (((header)->attributes & RDATASET_ATTR_NONEXISTENT) == 0)
+        (((header)->attributes & RDATASET_ATTR_NONEXISTENT) == 0)
 #define NONEXISTENT(header) \
-       (((header)->attributes & RDATASET_ATTR_NONEXISTENT) != 0)
+        (((header)->attributes & RDATASET_ATTR_NONEXISTENT) != 0)
 #define IGNORE(header) \
-       (((header)->attributes & RDATASET_ATTR_IGNORE) != 0)
+        (((header)->attributes & RDATASET_ATTR_IGNORE) != 0)
 #define RETAIN(header) \
-       (((header)->attributes & RDATASET_ATTR_RETAIN) != 0)
+        (((header)->attributes & RDATASET_ATTR_RETAIN) != 0)
 #define NXDOMAIN(header) \
-       (((header)->attributes & RDATASET_ATTR_NXDOMAIN) != 0)
+        (((header)->attributes & RDATASET_ATTR_NXDOMAIN) != 0)
 
-#define DEFAULT_NODE_LOCK_COUNT                7       /*%< Should be prime. */
-#define DEFAULT_CACHE_NODE_LOCK_COUNT  1009    /*%< Should be prime. */
+#define DEFAULT_NODE_LOCK_COUNT         7       /*%< Should be prime. */
+#define DEFAULT_CACHE_NODE_LOCK_COUNT   1009    /*%< Should be prime. */
 
 typedef struct {
-       nodelock_t                      lock;
-       /* Protected in the refcount routines. */
-       isc_refcount_t                  references;
-       /* Locked by lock. */
-       isc_boolean_t                   exiting;
+        nodelock_t                      lock;
+        /* Protected in the refcount routines. */
+        isc_refcount_t                  references;
+        /* Locked by lock. */
+        isc_boolean_t                   exiting;
 } rbtdb_nodelock_t;
 
 typedef struct rbtdb_changed {
-       dns_rbtnode_t *                 node;
-       isc_boolean_t                   dirty;
-       ISC_LINK(struct rbtdb_changed)  link;
+        dns_rbtnode_t *                 node;
+        isc_boolean_t                   dirty;
+        ISC_LINK(struct rbtdb_changed)  link;
 } rbtdb_changed_t;
 
-typedef ISC_LIST(rbtdb_changed_t)      rbtdb_changedlist_t;
+typedef ISC_LIST(rbtdb_changed_t)       rbtdb_changedlist_t;
 
 typedef struct rbtdb_version {
-       /* Not locked */
-       rbtdb_serial_t                  serial;
-       /*
-        * Protected in the refcount routines.
-        * XXXJT: should we change the lock policy based on the refcount
-        * performance?
-        */
-       isc_refcount_t                  references;
-       /* Locked by database lock. */
-       isc_boolean_t                   writer;
-       isc_boolean_t                   commit_ok;
-       rbtdb_changedlist_t             changed_list;
-       ISC_LINK(struct rbtdb_version)  link;
+        /* Not locked */
+        rbtdb_serial_t                  serial;
+        /*
+         * Protected in the refcount routines.
+         * XXXJT: should we change the lock policy based on the refcount
+         * performance?
+         */
+        isc_refcount_t                  references;
+        /* Locked by database lock. */
+        isc_boolean_t                   writer;
+        isc_boolean_t                   commit_ok;
+        rbtdb_changedlist_t             changed_list;
+        ISC_LINK(struct rbtdb_version)  link;
 } rbtdb_version_t;
 
-typedef ISC_LIST(rbtdb_version_t)      rbtdb_versionlist_t;
+typedef ISC_LIST(rbtdb_version_t)       rbtdb_versionlist_t;
+
+#ifdef LRU_DEBUG
+/* statistics info for testing */
+struct cachestat {
+        unsigned int    cache_total;
+        int             cache_current;
+        unsigned int    ncache_total;
+        int             ncache_current;
+        unsigned int    a_total;
+        int             a_current;
+        unsigned int    aaaa_total;
+        int             aaaa_current;
+        unsigned int    ns_total;
+        int             ns_current;
+        unsigned int    ptr_total;
+        int             ptr_current;
+        unsigned int    glue_total;
+        int             glue_current;
+        unsigned int    additional_total;
+        int             additional_current;
+
+        unsigned int    stale_purge;
+        unsigned int    stale_scan;
+        unsigned int    stale_expire;
+        unsigned int    stale_lru;
+};
+#endif
 
 typedef struct {
-       /* Unlocked. */
-       dns_db_t                        common;
+        /* Unlocked. */
+        dns_db_t                        common;
 #if DNS_RBTDB_USERWLOCK
-       isc_rwlock_t                    lock;
+        isc_rwlock_t                    lock;
 #else
-       isc_mutex_t                     lock;
+        isc_mutex_t                     lock;
+#endif
+        isc_rwlock_t                    tree_lock;
+        unsigned int                    node_lock_count;
+        rbtdb_nodelock_t *              node_locks;
+        dns_rbtnode_t *                 origin_node;
+        /* Locked by lock. */
+        unsigned int                    active;
+        isc_refcount_t                  references;
+        unsigned int                    attributes;
+        rbtdb_serial_t                  current_serial;
+        rbtdb_serial_t                  least_serial;
+        rbtdb_serial_t                  next_serial;
+        rbtdb_version_t *               current_version;
+        rbtdb_version_t *               future_version;
+        rbtdb_versionlist_t             open_versions;
+        isc_boolean_t                   overmem;
+        isc_task_t *                    task;
+        dns_dbnode_t                    *soanode;
+        dns_dbnode_t                    *nsnode;
+
+        /*
+         * This is a linked list used to implement the LRU cache.  There will
+         * be node_lock_count linked lists here.  Nodes in bucket 1 will be
+         * placed on the linked list rdatasets[1].
+         */
+        rdatasetheaderlist_t            *rdatasets;
+        rbtnodelist_t                   *deadnodes;
+
+        /*
+         * Heaps.  Each of these is used for TTL based expiry.
+         */
+        isc_heap_t                      **heaps;
+
+        /* Locked by tree_lock. */
+        dns_rbt_t *                     tree;
+        isc_boolean_t                   secure;
+
+        /* Unlocked */
+        unsigned int                    quantum;
+#ifdef LRU_DEBUG
+        struct cachestat                cachestat;
 #endif
-       isc_rwlock_t                    tree_lock;
-       unsigned int                    node_lock_count;
-       rbtdb_nodelock_t *              node_locks;
-       dns_rbtnode_t *                 origin_node;
-       /* Locked by lock. */
-       unsigned int                    active;
-       isc_refcount_t                  references;
-       unsigned int                    attributes;
-       rbtdb_serial_t                  current_serial;
-       rbtdb_serial_t                  least_serial;
-       rbtdb_serial_t                  next_serial;
-       rbtdb_version_t *               current_version;
-       rbtdb_version_t *               future_version;
-       rbtdb_versionlist_t             open_versions;
-       isc_boolean_t                   overmem;
-       isc_task_t *                    task;
-       dns_dbnode_t                    *soanode;
-       dns_dbnode_t                    *nsnode;
-       /* Locked by tree_lock. */
-       dns_rbt_t *                     tree;
-       isc_boolean_t                   secure;
-
-       /* Unlocked */
-       unsigned int                    quantum;
 } dns_rbtdb_t;
 
-#define RBTDB_ATTR_LOADED              0x01
-#define RBTDB_ATTR_LOADING             0x02
+#define RBTDB_ATTR_LOADED               0x01
+#define RBTDB_ATTR_LOADING              0x02
 
 /*%
  * Search Context
  */
 typedef struct {
-       dns_rbtdb_t *           rbtdb;
-       rbtdb_version_t *       rbtversion;
-       rbtdb_serial_t          serial;
-       unsigned int            options;
-       dns_rbtnodechain_t      chain;
-       isc_boolean_t           copy_name;
-       isc_boolean_t           need_cleanup;
-       isc_boolean_t           wild;
-       dns_rbtnode_t *         zonecut;
-       rdatasetheader_t *      zonecut_rdataset;
-       rdatasetheader_t *      zonecut_sigrdataset;
-       dns_fixedname_t         zonecut_name;
-       isc_stdtime_t           now;
+        dns_rbtdb_t *           rbtdb;
+        rbtdb_version_t *       rbtversion;
+        rbtdb_serial_t          serial;
+        unsigned int            options;
+        dns_rbtnodechain_t      chain;
+        isc_boolean_t           copy_name;
+        isc_boolean_t           need_cleanup;
+        isc_boolean_t           wild;
+        dns_rbtnode_t *         zonecut;
+        rdatasetheader_t *      zonecut_rdataset;
+        rdatasetheader_t *      zonecut_sigrdataset;
+        dns_fixedname_t         zonecut_name;
+        isc_stdtime_t           now;
 } rbtdb_search_t;
 
 /*%
  * Load Context
  */
 typedef struct {
-       dns_rbtdb_t *           rbtdb;
-       isc_stdtime_t           now;
+        dns_rbtdb_t *           rbtdb;
+        isc_stdtime_t           now;
 } rbtdb_load_t;
 
 static void rdataset_disassociate(dns_rdataset_t *rdataset);
@@ -387,90 +460,96 @@ static void rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata);
 static void rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target);
 static unsigned int rdataset_count(dns_rdataset_t *rdataset);
 static isc_result_t rdataset_getnoqname(dns_rdataset_t *rdataset,
-                                       dns_name_t *name,
-                                       dns_rdataset_t *nsec,
-                                       dns_rdataset_t *nsecsig);
+                                        dns_name_t *name,
+                                        dns_rdataset_t *nsec,
+                                        dns_rdataset_t *nsecsig);
 static isc_result_t rdataset_getadditional(dns_rdataset_t *rdataset,
-                                          dns_rdatasetadditional_t type,
-                                          dns_rdatatype_t qtype,
-                                          dns_acache_t *acache,
-                                          dns_zone_t **zonep,
-                                          dns_db_t **dbp,
-                                          dns_dbversion_t **versionp,
-                                          dns_dbnode_t **nodep,
-                                          dns_name_t *fname,
-                                          dns_message_t *msg,
-                                          isc_stdtime_t now);
+                                           dns_rdatasetadditional_t type,
+                                           dns_rdatatype_t qtype,
+                                           dns_acache_t *acache,
+                                           dns_zone_t **zonep,
+                                           dns_db_t **dbp,
+                                           dns_dbversion_t **versionp,
+                                           dns_dbnode_t **nodep,
+                                           dns_name_t *fname,
+                                           dns_message_t *msg,
+                                           isc_stdtime_t now);
 static isc_result_t rdataset_setadditional(dns_rdataset_t *rdataset,
-                                          dns_rdatasetadditional_t type,
-                                          dns_rdatatype_t qtype,
-                                          dns_acache_t *acache,
-                                          dns_zone_t *zone,
-                                          dns_db_t *db,
-                                          dns_dbversion_t *version,
-                                          dns_dbnode_t *node,
-                                          dns_name_t *fname);
+                                           dns_rdatasetadditional_t type,
+                                           dns_rdatatype_t qtype,
+                                           dns_acache_t *acache,
+                                           dns_zone_t *zone,
+                                           dns_db_t *db,
+                                           dns_dbversion_t *version,
+                                           dns_dbnode_t *node,
+                                           dns_name_t *fname);
 static isc_result_t rdataset_putadditional(dns_acache_t *acache,
-                                          dns_rdataset_t *rdataset,
-                                          dns_rdatasetadditional_t type,
-                                          dns_rdatatype_t qtype);
+                                           dns_rdataset_t *rdataset,
+                                           dns_rdatasetadditional_t type,
+                                           dns_rdatatype_t qtype);
+static inline isc_boolean_t need_headerupdate(rdatasetheader_t *header,
+                                              isc_stdtime_t now);
+static void update_header(dns_rbtdb_t *rbtdb, rdatasetheader_t *header,
+                          isc_stdtime_t now);
+static void check_stale_cache(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode,
+                              isc_stdtime_t now, isc_boolean_t tree_locked);
 
 static dns_rdatasetmethods_t rdataset_methods = {
-       rdataset_disassociate,
-       rdataset_first,
-       rdataset_next,
-       rdataset_current,
-       rdataset_clone,
-       rdataset_count,
-       NULL,
-       rdataset_getnoqname,
-       rdataset_getadditional,
-       rdataset_setadditional,
-       rdataset_putadditional
+        rdataset_disassociate,
+        rdataset_first,
+        rdataset_next,
+        rdataset_current,
+        rdataset_clone,
+        rdataset_count,
+        NULL,
+        rdataset_getnoqname,
+        rdataset_getadditional,
+        rdataset_setadditional,
+        rdataset_putadditional
 };
 
 static void rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp);
 static isc_result_t rdatasetiter_first(dns_rdatasetiter_t *iterator);
 static isc_result_t rdatasetiter_next(dns_rdatasetiter_t *iterator);
 static void rdatasetiter_current(dns_rdatasetiter_t *iterator,
-                                dns_rdataset_t *rdataset);
+                                 dns_rdataset_t *rdataset);
 
 static dns_rdatasetitermethods_t rdatasetiter_methods = {
-       rdatasetiter_destroy,
-       rdatasetiter_first,
-       rdatasetiter_next,
-       rdatasetiter_current
+        rdatasetiter_destroy,
+        rdatasetiter_first,
+        rdatasetiter_next,
+        rdatasetiter_current
 };
 
 typedef struct rbtdb_rdatasetiter {
-       dns_rdatasetiter_t              common;
-       rdatasetheader_t *              current;
+        dns_rdatasetiter_t              common;
+        rdatasetheader_t *              current;
 } rbtdb_rdatasetiter_t;
 
-static void            dbiterator_destroy(dns_dbiterator_t **iteratorp);
-static isc_result_t    dbiterator_first(dns_dbiterator_t *iterator);
-static isc_result_t    dbiterator_last(dns_dbiterator_t *iterator);
-static isc_result_t    dbiterator_seek(dns_dbiterator_t *iterator,
-                                       dns_name_t *name);
-static isc_result_t    dbiterator_prev(dns_dbiterator_t *iterator);
-static isc_result_t    dbiterator_next(dns_dbiterator_t *iterator);
-static isc_result_t    dbiterator_current(dns_dbiterator_t *iterator,
-                                          dns_dbnode_t **nodep,
-                                          dns_name_t *name);
-static isc_result_t    dbiterator_pause(dns_dbiterator_t *iterator);
-static isc_result_t    dbiterator_origin(dns_dbiterator_t *iterator,
-                                         dns_name_t *name);
+static void             dbiterator_destroy(dns_dbiterator_t **iteratorp);
+static isc_result_t     dbiterator_first(dns_dbiterator_t *iterator);
+static isc_result_t     dbiterator_last(dns_dbiterator_t *iterator);
+static isc_result_t     dbiterator_seek(dns_dbiterator_t *iterator,
+                                        dns_name_t *name);
+static isc_result_t     dbiterator_prev(dns_dbiterator_t *iterator);
+static isc_result_t     dbiterator_next(dns_dbiterator_t *iterator);
+static isc_result_t     dbiterator_current(dns_dbiterator_t *iterator,
+                                           dns_dbnode_t **nodep,
+                                           dns_name_t *name);
+static isc_result_t     dbiterator_pause(dns_dbiterator_t *iterator);
+static isc_result_t     dbiterator_origin(dns_dbiterator_t *iterator,
+                                          dns_name_t *name);
 
 static dns_dbiteratormethods_t dbiterator_methods = {
-       dbiterator_destroy,
-       dbiterator_first,
-       dbiterator_last,
-       dbiterator_seek,
-       dbiterator_prev,
-       dbiterator_next,
-       dbiterator_current,
-       dbiterator_pause,
-       dbiterator_origin
+        dbiterator_destroy,
+        dbiterator_first,
+        dbiterator_last,
+        dbiterator_seek,
+        dbiterator_prev,
+        dbiterator_next,
+        dbiterator_current,
+        dbiterator_pause,
+        dbiterator_origin
 };
 
 #define DELETION_BATCH_MAX 64
@@ -479,17 +558,17 @@ static dns_dbiteratormethods_t dbiterator_methods = {
  * If 'paused' is ISC_TRUE, then the tree lock is not being held.
  */
 typedef struct rbtdb_dbiterator {
-       dns_dbiterator_t                common;
-       isc_boolean_t                   paused;
-       isc_boolean_t                   new_origin;
-       isc_rwlocktype_t                tree_locked;
-       isc_result_t                    result;
-       dns_fixedname_t                 name;
-       dns_fixedname_t                 origin;
-       dns_rbtnodechain_t              chain;
-       dns_rbtnode_t                   *node;
-       dns_rbtnode_t                   *deletions[DELETION_BATCH_MAX];
-       int                             delete;
+        dns_dbiterator_t                common;
+        isc_boolean_t                   paused;
+        isc_boolean_t                   new_origin;
+        isc_rwlocktype_t                tree_locked;
+        isc_result_t                    result;
+        dns_fixedname_t                 name;
+        dns_fixedname_t                 origin;
+        dns_rbtnodechain_t              chain;
+        dns_rbtnode_t                   *node;
+        dns_rbtnode_t                   *deletions[DELETION_BATCH_MAX];
+        int                             delete;
 } rbtdb_dbiterator_t;
 
 
@@ -497,7 +576,8 @@ typedef struct rbtdb_dbiterator {
 #define IS_CACHE(rbtdb) (((rbtdb)->common.attributes & DNS_DBATTR_CACHE) != 0)
 
 static void free_rbtdb(dns_rbtdb_t *rbtdb, isc_boolean_t log,
-                      isc_event_t *event);
+                       isc_event_t *event);
+static void overmem(dns_db_t *db, isc_boolean_t overmem);
 
 /*%
  * 'init_count' is used to initialize 'newheader->count' which inturn
@@ -505,10 +585,10 @@ static void free_rbtdb(dns_rbtdb_t *rbtdb, isc_boolean_t log,
  * We don't lock this as we don't care about simultanious updates.
  *
  * Note:
- *     Both init_count and header->count can be ISC_UINT32_MAX.
+ *      Both init_count and header->count can be ISC_UINT32_MAX.
  *      The count on the returned rdataset however can't be as
- *     that indicates that the database does not implement cyclic
- *     processing.
+ *      that indicates that the database does not implement cyclic
+ *      processing.
  */
 static unsigned int init_count;
 
@@ -518,12 +598,12 @@ static unsigned int init_count;
  * If a routine is going to lock more than one lock in this module, then
  * the locking must be done in the following order:
  *
- *     Tree Lock
+ *      Tree Lock
  *
- *     Node Lock       (Only one from the set may be locked at one time by
- *                      any caller)
+ *      Node Lock       (Only one from the set may be locked at one time by
+ *                       any caller)
  *
- *     Database Lock
+ *      Database Lock
  *
  * Failure to follow this hierarchy can result in deadlock.
  */
@@ -531,11 +611,7 @@ static unsigned int init_count;
 /*
  * Deleting Nodes
  *
- * Currently there is no deletion of nodes from the database, except when
- * the database is being destroyed.
- *
- * If node deletion is added in the future, then for zone databases the node
- * for the origin of the zone MUST NOT be deleted.
+ * For zone databases the node for the origin of the zone MUST NOT be deleted.
  */
 
 
@@ -545,22 +621,73 @@ static unsigned int init_count;
 
 static void
 attach(dns_db_t *source, dns_db_t **targetp) {
-       dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)source;
+        dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)source;
 
-       REQUIRE(VALID_RBTDB(rbtdb));
+        REQUIRE(VALID_RBTDB(rbtdb));
 
-       isc_refcount_increment(&rbtdb->references, NULL);
+        isc_refcount_increment(&rbtdb->references, NULL);
 
-       *targetp = source;
+        *targetp = source;
 }
 
 static void
 free_rbtdb_callback(isc_task_t *task, isc_event_t *event) {
-       dns_rbtdb_t *rbtdb = event->ev_arg;
+        dns_rbtdb_t *rbtdb = event->ev_arg;
 
-       UNUSED(task);
+        UNUSED(task);
 
-       free_rbtdb(rbtdb, ISC_TRUE, event);
+        free_rbtdb(rbtdb, ISC_TRUE, event);
+}
+
+static void
+set_ttl(dns_rbtdb_t *rbtdb, rdatasetheader_t *header, dns_ttl_t newttl) {
+        int idx;
+        isc_heap_t *heap;
+        dns_ttl_t oldttl;
+
+        oldttl = header->rdh_ttl;
+        header->rdh_ttl = newttl;
+
+        /*
+         * It's possible the rbtdb is not a cache.  If this is the case,
+         * we will not have a heap, and we move on.  If we do, though,
+         * we might need to adjust things.
+         */
+        if (header->heap_index == 0 || newttl == oldttl)
+                return;
+        idx = header->node->locknum;
+        if (rbtdb->heaps == NULL || rbtdb->heaps[idx] == NULL)
+            return;
+        heap = rbtdb->heaps[idx];
+
+        if (newttl < oldttl)
+                isc_heap_increased(heap, header->heap_index);
+        else
+                isc_heap_decreased(heap, header->heap_index);
+}
+
+/*%
+ * This function allows the heap code to rank the priority of each
+ * element.  It returns ISC_TRUE if v1 happens "sooner" than v2.
+ */
+static isc_boolean_t
+ttl_sooner(void *v1, void *v2) {
+        rdatasetheader_t *h1 = v1;
+        rdatasetheader_t *h2 = v2;
+
+        if (h1->rdh_ttl < h2->rdh_ttl)
+                return (ISC_TRUE);
+        return (ISC_FALSE);
+}
+
+/*%
+ * This function sets the heap index into the header.
+ */
+static void
+ttl_set_index(void *what, unsigned int index) {
+        rdatasetheader_t *h = what;
+
+        h->heap_index = index;
 }
 
 /*%
@@ -571,562 +698,792 @@ free_rbtdb_callback(isc_task_t *task, isc_event_t *event) {
  */
 static unsigned int
 adjust_quantum(unsigned int old, isc_time_t *start) {
-       unsigned int pps = dns_pps;     /* packets per second */
-       unsigned int interval;
-       isc_uint64_t usecs;
-       isc_time_t end;
-       unsigned int new;
-
-       if (pps < 100)
-               pps = 100;
-       isc_time_now(&end);
-
-       interval = 1000000 / pps;       /* interval in usec */
-       if (interval == 0)
-               interval = 1;
-       usecs = isc_time_microdiff(&end, start);
-       if (usecs == 0) {
-               /*
-                * We were unable to measure the amount of time taken.
-                * Double the nodes deleted next time.
-                */
-               old *= 2;
-               if (old > 1000)
-                       old = 1000;
-               return (old);
-       }
-       new = old * interval;
-       new /= (unsigned int)usecs;
-       if (new == 0)
-               new = 1;
-       else if (new > 1000)
-               new = 1000;
-
-       /* Smooth */
-       new = (new + old * 3) / 4;
-       
-       isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_CACHE,
-                     ISC_LOG_DEBUG(1), "adjust_quantum -> %d", new);
-
-       return (new);
+        unsigned int pps = dns_pps;     /* packets per second */
+        unsigned int interval;
+        isc_uint64_t usecs;
+        isc_time_t end;
+        unsigned int new;
+
+        if (pps < 100)
+                pps = 100;
+        isc_time_now(&end);
+
+        interval = 1000000 / pps;       /* interval in usec */
+        if (interval == 0)
+                interval = 1;
+        usecs = isc_time_microdiff(&end, start);
+        if (usecs == 0) {
+                /*
+                 * We were unable to measure the amount of time taken.
+                 * Double the nodes deleted next time.
+                 */
+                old *= 2;
+                if (old > 1000)
+                        old = 1000;
+                return (old);
+        }
+        new = old * interval;
+        new /= (unsigned int)usecs;
+        if (new == 0)
+                new = 1;
+        else if (new > 1000)
+                new = 1000;
+
+        /* Smooth */
+        new = (new + old * 3) / 4;
+
+        isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_CACHE,
+                      ISC_LOG_DEBUG(1), "adjust_quantum -> %d", new);
+
+        return (new);
 }
-               
+
 static void
 free_rbtdb(dns_rbtdb_t *rbtdb, isc_boolean_t log, isc_event_t *event) {
-       unsigned int i;
-       isc_ondestroy_t ondest;
-       isc_result_t result;
-       char buf[DNS_NAME_FORMATSIZE];
-       isc_time_t start;
-
-       REQUIRE(rbtdb->current_version != NULL || EMPTY(rbtdb->open_versions));
-       REQUIRE(rbtdb->future_version == NULL);
-
-       if (rbtdb->current_version != NULL) {
-               unsigned int refs;
-
-               isc_refcount_decrement(&rbtdb->current_version->references,
-                                      &refs);
-               INSIST(refs == 0);
-               UNLINK(rbtdb->open_versions, rbtdb->current_version, link);
-               isc_refcount_destroy(&rbtdb->current_version->references);
-               isc_mem_put(rbtdb->common.mctx, rbtdb->current_version,
-                           sizeof(rbtdb_version_t));
-       }
-       if (event == NULL)
-               rbtdb->quantum = (rbtdb->task != NULL) ? 100 : 0;
+        unsigned int i;
+        isc_ondestroy_t ondest;
+        isc_result_t result;
+        char buf[DNS_NAME_FORMATSIZE];
+        isc_time_t start;
+
+        if (IS_CACHE(rbtdb) && rbtdb->common.rdclass == dns_rdataclass_in)
+                overmem((dns_db_t *)rbtdb, (isc_boolean_t)-1);
+
+        REQUIRE(rbtdb->current_version != NULL || EMPTY(rbtdb->open_versions));
+        REQUIRE(rbtdb->future_version == NULL);
+
+        if (rbtdb->current_version != NULL) {
+                unsigned int refs;
+
+                isc_refcount_decrement(&rbtdb->current_version->references,
+                                       &refs);
+                INSIST(refs == 0);
+                UNLINK(rbtdb->open_versions, rbtdb->current_version, link);
+                isc_refcount_destroy(&rbtdb->current_version->references);
+                isc_mem_put(rbtdb->common.mctx, rbtdb->current_version,
+                            sizeof(rbtdb_version_t));
+        }
+        if (IS_CACHE(rbtdb)) {
+                /*
+                 * We assume the number of remaining dead nodes is reasonably
+                 * small; the overhead of unlinking all nodes here should be
+                 * negligible.
+                 */
+                for (i = 0; i < rbtdb->node_lock_count; i++) {
+                        dns_rbtnode_t *node;
+
+                        node = ISC_LIST_HEAD(rbtdb->deadnodes[i]);
+                        while (node != NULL) {
+                                ISC_LIST_UNLINK(rbtdb->deadnodes[i], node,
+                                    deadlink);
+                                node = ISC_LIST_HEAD(rbtdb->deadnodes[i]);
+                        }
+                }
+        }
+        if (event == NULL)
+                rbtdb->quantum = (rbtdb->task != NULL) ? 100 : 0;
  again:
-       if (rbtdb->tree != NULL) {
-               isc_time_now(&start);
-               result = dns_rbt_destroy2(&rbtdb->tree, rbtdb->quantum);
-               if (result == ISC_R_QUOTA) {
-                       INSIST(rbtdb->task != NULL);
-                       if (rbtdb->quantum != 0)
-                               rbtdb->quantum = adjust_quantum(rbtdb->quantum,
-                                                               &start);
-                       if (event == NULL)
-                               event = isc_event_allocate(rbtdb->common.mctx,
-                                                          NULL,
-                                                        DNS_EVENT_FREESTORAGE,
-                                                          free_rbtdb_callback,
-                                                          rbtdb,
-                                                          sizeof(isc_event_t));
-                       if (event == NULL)
-                               goto again;
-                       isc_task_send(rbtdb->task, &event);
-                       return;
-               }
-               INSIST(result == ISC_R_SUCCESS && rbtdb->tree == NULL);
-       }
-       if (event != NULL)
-               isc_event_free(&event);
-       if (log) {
-               if (dns_name_dynamic(&rbtdb->common.origin))
-                       dns_name_format(&rbtdb->common.origin, buf,
-                                       sizeof(buf));
-               else
-                       strcpy(buf, "<UNKNOWN>");
-               isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
-                             DNS_LOGMODULE_CACHE, ISC_LOG_DEBUG(1),
-                             "done free_rbtdb(%s)", buf);
-       }
-       if (dns_name_dynamic(&rbtdb->common.origin))
-               dns_name_free(&rbtdb->common.origin, rbtdb->common.mctx);
-       for (i = 0; i < rbtdb->node_lock_count; i++) {
-               isc_refcount_destroy(&rbtdb->node_locks[i].references);
-               NODE_DESTROYLOCK(&rbtdb->node_locks[i].lock);
-       }
-       isc_mem_put(rbtdb->common.mctx, rbtdb->node_locks,
-                   rbtdb->node_lock_count * sizeof(rbtdb_nodelock_t));
-       isc_rwlock_destroy(&rbtdb->tree_lock);
-       isc_refcount_destroy(&rbtdb->references);
-       if (rbtdb->task != NULL)
-               isc_task_detach(&rbtdb->task);
-       RBTDB_DESTROYLOCK(&rbtdb->lock);
-       rbtdb->common.magic = 0;
-       rbtdb->common.impmagic = 0;
-       ondest = rbtdb->common.ondest;
-       isc_mem_putanddetach(&rbtdb->common.mctx, rbtdb, sizeof(*rbtdb));
-       isc_ondestroy_notify(&ondest, rbtdb);
+        if (rbtdb->tree != NULL) {
+                isc_time_now(&start);
+                result = dns_rbt_destroy2(&rbtdb->tree, rbtdb->quantum);
+                if (result == ISC_R_QUOTA) {
+                        INSIST(rbtdb->task != NULL);
+                        if (rbtdb->quantum != 0)
+                                rbtdb->quantum = adjust_quantum(rbtdb->quantum,
+                                                                &start);
+                        if (event == NULL)
+                                event = isc_event_allocate(rbtdb->common.mctx,
+                                                           NULL,
+                                                         DNS_EVENT_FREESTORAGE,
+                                                           free_rbtdb_callback,
+                                                           rbtdb,
+                                                           sizeof(isc_event_t));
+                        if (event == NULL)
+                                goto again;
+                        isc_task_send(rbtdb->task, &event);
+                        return;
+                }
+                INSIST(result == ISC_R_SUCCESS && rbtdb->tree == NULL);
+        }
+        if (event != NULL)
+                isc_event_free(&event);
+        if (log) {
+                if (dns_name_dynamic(&rbtdb->common.origin))
+                        dns_name_format(&rbtdb->common.origin, buf,
+                                        sizeof(buf));
+                else
+                        strcpy(buf, "<UNKNOWN>");
+                isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+                              DNS_LOGMODULE_CACHE, ISC_LOG_DEBUG(1),
+                              "done free_rbtdb(%s)", buf);
+        }
+        if (dns_name_dynamic(&rbtdb->common.origin))
+                dns_name_free(&rbtdb->common.origin, rbtdb->common.mctx);
+        for (i = 0; i < rbtdb->node_lock_count; i++) {
+                isc_refcount_destroy(&rbtdb->node_locks[i].references);
+                NODE_DESTROYLOCK(&rbtdb->node_locks[i].lock);
+        }
+
+        /*
+         * Clean up LRU cache objects.
+         */
+        if (rbtdb->rdatasets != NULL) {
+                for (i = 0; i < rbtdb->node_lock_count; i++)
+                        INSIST(ISC_LIST_EMPTY(rbtdb->rdatasets[i]));
+                isc_mem_put(rbtdb->common.mctx, rbtdb->rdatasets,
+                            rbtdb->node_lock_count *
+                            sizeof(rdatasetheaderlist_t));
+        }
+        /*
+         * Clean up dead node buckets.
+         */
+        if (rbtdb->deadnodes != NULL) {
+                for (i = 0; i < rbtdb->node_lock_count; i++)
+                        INSIST(ISC_LIST_EMPTY(rbtdb->deadnodes[i]));
+                isc_mem_put(rbtdb->common.mctx, rbtdb->deadnodes,
+                    rbtdb->node_lock_count * sizeof(rbtnodelist_t));
+        }
+        /*
+         * Clean up TTL heap cache objects.
+         */
+        if (rbtdb->heaps != NULL) {
+                for (i = 0; i < rbtdb->node_lock_count; i++)
+                        isc_heap_destroy(&rbtdb->heaps[i]);
+                isc_mem_put(rbtdb->common.mctx, rbtdb->heaps,
+                            rbtdb->node_lock_count *
+                            sizeof(isc_heap_t *));
+        }
+
+        isc_mem_put(rbtdb->common.mctx, rbtdb->node_locks,
+                    rbtdb->node_lock_count * sizeof(rbtdb_nodelock_t));
+        isc_rwlock_destroy(&rbtdb->tree_lock);
+        isc_refcount_destroy(&rbtdb->references);
+        if (rbtdb->task != NULL)
+                isc_task_detach(&rbtdb->task);
+
+#ifdef LRU_DEBUG
+        /* Experimental logging about memory usage */
+        if (IS_CACHE(rbtdb) && rbtdb->common.rdclass == dns_rdataclass_in) {
+                isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+                              DNS_LOGMODULE_CACHE, ISC_LOG_INFO,
+                              "cache DB %p: mem inuse %lu, XXX node, "
+                              "%d/%u current/total cache, %d/%u neg, %d/%u A, %d/%u AAAA, "
+                              "%d/%u NS, %d/%u PTR, %d/%u glue, "
+                              "%d/%u  additional, purge/scan=%u(%u expiry, %u lru)/%u, "
+                              "overmem=%d",
+                              rbtdb,
+                              (unsigned long)isc_mem_inuse(rbtdb->common.mctx),
+                              rbtdb->cachestat.cache_current, rbtdb->cachestat.cache_total,
+                              rbtdb->cachestat.ncache_current, rbtdb->cachestat.ncache_total,
+                              rbtdb->cachestat.a_current, rbtdb->cachestat.a_total,
+                              rbtdb->cachestat.aaaa_current, rbtdb->cachestat.aaaa_total,
+                              rbtdb->cachestat.ns_current, rbtdb->cachestat.ns_total,
+                              rbtdb->cachestat.ptr_current, rbtdb->cachestat.ptr_total,
+                              rbtdb->cachestat.glue_current, rbtdb->cachestat.glue_total,
+                              rbtdb->cachestat.additional_current,
+                              rbtdb->cachestat.additional_total,
+                              rbtdb->cachestat.stale_purge, rbtdb->cachestat.stale_expire,
+                              rbtdb->cachestat.stale_lru, rbtdb->cachestat.stale_scan,
+                              rbtdb->overmem);
+                INSIST(rbtdb->cachestat.cache_current == 0);
+                INSIST(rbtdb->cachestat.ncache_current == 0);
+                INSIST(rbtdb->cachestat.a_current == 0);
+                INSIST(rbtdb->cachestat.aaaa_current == 0);
+                INSIST(rbtdb->cachestat.ns_current == 0);
+                INSIST(rbtdb->cachestat.ptr_current == 0);
+                INSIST(rbtdb->cachestat.glue_current == 0);
+                INSIST(rbtdb->cachestat.additional_current == 0);
+        }
+#endif
+
+        RBTDB_DESTROYLOCK(&rbtdb->lock);
+        rbtdb->common.magic = 0;
+        rbtdb->common.impmagic = 0;
+        ondest = rbtdb->common.ondest;
+        isc_mem_putanddetach(&rbtdb->common.mctx, rbtdb, sizeof(*rbtdb));
+        isc_ondestroy_notify(&ondest, rbtdb);
 }
 
 static inline void
 maybe_free_rbtdb(dns_rbtdb_t *rbtdb) {
-       isc_boolean_t want_free = ISC_FALSE;
-       unsigned int i;
-       unsigned int inactive = 0;
-
-       /* XXX check for open versions here */
-
-       if (rbtdb->soanode != NULL)
-               dns_db_detachnode((dns_db_t *)rbtdb, &rbtdb->soanode);
-       if (rbtdb->nsnode != NULL)
-               dns_db_detachnode((dns_db_t *)rbtdb, &rbtdb->nsnode);
-
-       /*
-        * Even though there are no external direct references, there still
-        * may be nodes in use.
-        */
-       for (i = 0; i < rbtdb->node_lock_count; i++) {
-               NODE_LOCK(&rbtdb->node_locks[i].lock, isc_rwlocktype_write);
-               rbtdb->node_locks[i].exiting = ISC_TRUE;
-               NODE_UNLOCK(&rbtdb->node_locks[i].lock, isc_rwlocktype_write);
-               if (isc_refcount_current(&rbtdb->node_locks[i].references)
-                   == 0) {
-                       inactive++;
-               }
-       }
-
-       if (inactive != 0) {
-               RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_write);
-               rbtdb->active -= inactive;
-               if (rbtdb->active == 0)
-                       want_free = ISC_TRUE;
-               RBTDB_UNLOCK(&rbtdb->lock, isc_rwlocktype_write);
-               if (want_free) {
-                       char buf[DNS_NAME_FORMATSIZE];
-                       if (dns_name_dynamic(&rbtdb->common.origin))
-                               dns_name_format(&rbtdb->common.origin, buf,
-                                               sizeof(buf));
-                       else
-                               strcpy(buf, "<UNKNOWN>");
-                       isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
-                                     DNS_LOGMODULE_CACHE, ISC_LOG_DEBUG(1),
-                                     "calling free_rbtdb(%s)", buf);
-                       free_rbtdb(rbtdb, ISC_TRUE, NULL);
-               }
-       }
+        isc_boolean_t want_free = ISC_FALSE;
+        unsigned int i;
+        unsigned int inactive = 0;
+
+        /* XXX check for open versions here */
+
+        if (rbtdb->soanode != NULL)
+                dns_db_detachnode((dns_db_t *)rbtdb, &rbtdb->soanode);
+        if (rbtdb->nsnode != NULL)
+                dns_db_detachnode((dns_db_t *)rbtdb, &rbtdb->nsnode);
+
+        /*
+         * Even though there are no external direct references, there still
+         * may be nodes in use.
+         */
+        for (i = 0; i < rbtdb->node_lock_count; i++) {
+                NODE_LOCK(&rbtdb->node_locks[i].lock, isc_rwlocktype_write);
+                rbtdb->node_locks[i].exiting = ISC_TRUE;
+                NODE_UNLOCK(&rbtdb->node_locks[i].lock, isc_rwlocktype_write);
+                if (isc_refcount_current(&rbtdb->node_locks[i].references)
+                    == 0) {
+                        inactive++;
+                }
+        }
+
+        if (inactive != 0) {
+                RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_write);
+                rbtdb->active -= inactive;
+                if (rbtdb->active == 0)
+                        want_free = ISC_TRUE;
+                RBTDB_UNLOCK(&rbtdb->lock, isc_rwlocktype_write);
+                if (want_free) {
+                        char buf[DNS_NAME_FORMATSIZE];
+                        if (dns_name_dynamic(&rbtdb->common.origin))
+                                dns_name_format(&rbtdb->common.origin, buf,
+                                                sizeof(buf));
+                        else
+                                strcpy(buf, "<UNKNOWN>");
+                        isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+                                      DNS_LOGMODULE_CACHE, ISC_LOG_DEBUG(1),
+                                      "calling free_rbtdb(%s)", buf);
+                        free_rbtdb(rbtdb, ISC_TRUE, NULL);
+                }
+        }
 }
 
 static void
 detach(dns_db_t **dbp) {
-       dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)(*dbp);
-       unsigned int refs;
+        dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)(*dbp);
+        unsigned int refs;
 
-       REQUIRE(VALID_RBTDB(rbtdb));
+        REQUIRE(VALID_RBTDB(rbtdb));
 
-       isc_refcount_decrement(&rbtdb->references, &refs);
+        isc_refcount_decrement(&rbtdb->references, &refs);
 
-       if (refs == 0)
-               maybe_free_rbtdb(rbtdb);
+        if (refs == 0)
+                maybe_free_rbtdb(rbtdb);
 
-       *dbp = NULL;
+        *dbp = NULL;
 }
 
 static void
 currentversion(dns_db_t *db, dns_dbversion_t **versionp) {
-       dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
-       rbtdb_version_t *version;
-       unsigned int refs;
+        dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
+        rbtdb_version_t *version;
+        unsigned int refs;
 
-       REQUIRE(VALID_RBTDB(rbtdb));
+        REQUIRE(VALID_RBTDB(rbtdb));
 
-       RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_read);
-       version = rbtdb->current_version;
-       isc_refcount_increment(&version->references, &refs);
-       RBTDB_UNLOCK(&rbtdb->lock, isc_rwlocktype_read);
+        RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_read);
+        version = rbtdb->current_version;
+        isc_refcount_increment(&version->references, &refs);
+        RBTDB_UNLOCK(&rbtdb->lock, isc_rwlocktype_read);
 
-       *versionp = (dns_dbversion_t *)version;
+        *versionp = (dns_dbversion_t *)version;
 }
 
 static inline rbtdb_version_t *
 allocate_version(isc_mem_t *mctx, rbtdb_serial_t serial,
-                unsigned int references, isc_boolean_t writer)
+                 unsigned int references, isc_boolean_t writer)
 {
-       isc_result_t result;
-       rbtdb_version_t *version;
-
-       version = isc_mem_get(mctx, sizeof(*version));
-       if (version == NULL)
-               return (NULL);
-       version->serial = serial;
-       result = isc_refcount_init(&version->references, references);
-       if (result != ISC_R_SUCCESS) {
-               isc_mem_put(mctx, version, sizeof(*version));
-               return (NULL);
-       }
-       version->writer = writer;
-       version->commit_ok = ISC_FALSE;
-       ISC_LIST_INIT(version->changed_list);
-       ISC_LINK_INIT(version, link);
-
-       return (version);
+        isc_result_t result;
+        rbtdb_version_t *version;
+
+        version = isc_mem_get(mctx, sizeof(*version));
+        if (version == NULL)
+                return (NULL);
+        version->serial = serial;
+        result = isc_refcount_init(&version->references, references);
+        if (result != ISC_R_SUCCESS) {
+                isc_mem_put(mctx, version, sizeof(*version));
+                return (NULL);
+        }
+        version->writer = writer;
+        version->commit_ok = ISC_FALSE;
+        ISC_LIST_INIT(version->changed_list);
+        ISC_LINK_INIT(version, link);
+
+        return (version);
 }
 
 static isc_result_t
 newversion(dns_db_t *db, dns_dbversion_t **versionp) {
-       dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
-       rbtdb_version_t *version;
-
-       REQUIRE(VALID_RBTDB(rbtdb));
-       REQUIRE(versionp != NULL && *versionp == NULL);
-       REQUIRE(rbtdb->future_version == NULL);
-
-       RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_write);
-       RUNTIME_CHECK(rbtdb->next_serial != 0);         /* XXX Error? */
-       version = allocate_version(rbtdb->common.mctx, rbtdb->next_serial, 1,
-                                  ISC_TRUE);
-       if (version != NULL) {
-               version->commit_ok = ISC_TRUE;
-               rbtdb->next_serial++;
-               rbtdb->future_version = version;
-       }
-       RBTDB_UNLOCK(&rbtdb->lock, isc_rwlocktype_write);
-
-       if (version == NULL)
-               return (ISC_R_NOMEMORY);
-
-       *versionp = version;
-
-       return (ISC_R_SUCCESS);
+        dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
+        rbtdb_version_t *version;
+
+        REQUIRE(VALID_RBTDB(rbtdb));
+        REQUIRE(versionp != NULL && *versionp == NULL);
+        REQUIRE(rbtdb->future_version == NULL);
+
+        RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_write);
+        RUNTIME_CHECK(rbtdb->next_serial != 0);         /* XXX Error? */
+        version = allocate_version(rbtdb->common.mctx, rbtdb->next_serial, 1,
+                                   ISC_TRUE);
+        if (version != NULL) {
+                version->commit_ok = ISC_TRUE;
+                rbtdb->next_serial++;
+                rbtdb->future_version = version;
+        }
+        RBTDB_UNLOCK(&rbtdb->lock, isc_rwlocktype_write);
+
+        if (version == NULL)
+                return (ISC_R_NOMEMORY);
+
+        *versionp = version;
+
+        return (ISC_R_SUCCESS);
 }
 
 static void
 attachversion(dns_db_t *db, dns_dbversion_t *source,
-             dns_dbversion_t **targetp)
+              dns_dbversion_t **targetp)
 {
-       dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
-       rbtdb_version_t *rbtversion = source;
-       unsigned int refs;
+        dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
+        rbtdb_version_t *rbtversion = source;
+        unsigned int refs;
 
-       REQUIRE(VALID_RBTDB(rbtdb));
+        REQUIRE(VALID_RBTDB(rbtdb));
 
-       isc_refcount_increment(&rbtversion->references, &refs);
-       INSIST(refs > 1);
+        isc_refcount_increment(&rbtversion->references, &refs);
+        INSIST(refs > 1);
 
-       *targetp = rbtversion;
+        *targetp = rbtversion;
 }
 
 static rbtdb_changed_t *
 add_changed(dns_rbtdb_t *rbtdb, rbtdb_version_t *version,
-           dns_rbtnode_t *node)
+            dns_rbtnode_t *node)
 {
-       rbtdb_changed_t *changed;
-       unsigned int refs;
+        rbtdb_changed_t *changed;
+        unsigned int refs;
 
-       /*
-        * Caller must be holding the node lock if its reference must be
-        * protected by the lock.
-        */
+        /*
+         * Caller must be holding the node lock if its reference must be
+         * protected by the lock.
+         */
 
-       changed = isc_mem_get(rbtdb->common.mctx, sizeof(*changed));
+        changed = isc_mem_get(rbtdb->common.mctx, sizeof(*changed));
 
-       RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_write);
+        RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_write);
 
-       REQUIRE(version->writer);
+        REQUIRE(version->writer);
 
-       if (changed != NULL) {
-               dns_rbtnode_refincrement(node, &refs);
-               INSIST(refs != 0);
-               changed->node = node;
-               changed->dirty = ISC_FALSE;
-               ISC_LIST_INITANDAPPEND(version->changed_list, changed, link);
-       } else
-               version->commit_ok = ISC_FALSE;
+        if (changed != NULL) {
+                dns_rbtnode_refincrement(node, &refs);
+                INSIST(refs != 0);
+                changed->node = node;
+                changed->dirty = ISC_FALSE;
+                ISC_LIST_INITANDAPPEND(version->changed_list, changed, link);
+        } else
+                version->commit_ok = ISC_FALSE;
 
-       RBTDB_UNLOCK(&rbtdb->lock, isc_rwlocktype_write);
+        RBTDB_UNLOCK(&rbtdb->lock, isc_rwlocktype_write);
 
-       return (changed);
+        return (changed);
 }
 
 static void
 free_acachearray(isc_mem_t *mctx, rdatasetheader_t *header,
-                acachectl_t *array)
+                 acachectl_t *array)
 {
-       unsigned int count;
-       unsigned int i;
-       unsigned char *raw;     /* RDATASLAB */
+        unsigned int count;
+        unsigned int i;
+        unsigned char *raw;     /* RDATASLAB */
 
-       /*
-        * The caller must be holding the corresponding node lock.
-        */
+        /*
+         * The caller must be holding the corresponding node lock.
+         */
 
-       if (array == NULL)
-               return;
+        if (array == NULL)
+                return;
 
-       raw = (unsigned char *)header + sizeof(*header);
-       count = raw[0] * 256 + raw[1];
+        raw = (unsigned char *)header + sizeof(*header);
+        count = raw[0] * 256 + raw[1];
 
-       /*
-        * Sanity check: since an additional cache entry has a reference to
-        * the original DB node (in the callback arg), there should be no
-        * acache entries when the node can be freed. 
-        */
-       for (i = 0; i < count; i++)
-               INSIST(array[i].entry == NULL && array[i].cbarg == NULL);
+        /*
+         * Sanity check: since an additional cache entry has a reference to
+         * the original DB node (in the callback arg), there should be no
+         * acache entries when the node can be freed.
+         */
+        for (i = 0; i < count; i++)
+                INSIST(array[i].entry == NULL && array[i].cbarg == NULL);
 
-       isc_mem_put(mctx, array, count * sizeof(acachectl_t));
+        isc_mem_put(mctx, array, count * sizeof(acachectl_t));
 }
 
 static inline void
 free_noqname(isc_mem_t *mctx, struct noqname **noqname) {
 
-       if (dns_name_dynamic(&(*noqname)->name))
-               dns_name_free(&(*noqname)->name, mctx);
-       if ((*noqname)->nsec != NULL)
-               isc_mem_put(mctx, (*noqname)->nsec,
-                           dns_rdataslab_size((*noqname)->nsec, 0));
-       if ((*noqname)->nsecsig != NULL)
-               isc_mem_put(mctx, (*noqname)->nsecsig,
-                           dns_rdataslab_size((*noqname)->nsecsig, 0));
-       isc_mem_put(mctx, *noqname, sizeof(**noqname));
-       *noqname = NULL;
+        if (dns_name_dynamic(&(*noqname)->name))
+                dns_name_free(&(*noqname)->name, mctx);
+        if ((*noqname)->nsec != NULL)
+                isc_mem_put(mctx, (*noqname)->nsec,
+                            dns_rdataslab_size((*noqname)->nsec, 0));
+        if ((*noqname)->nsecsig != NULL)
+                isc_mem_put(mctx, (*noqname)->nsecsig,
+                            dns_rdataslab_size((*noqname)->nsecsig, 0));
+        isc_mem_put(mctx, *noqname, sizeof(**noqname));
+        *noqname = NULL;
 }
 
 static inline void
-free_rdataset(isc_mem_t *mctx, rdatasetheader_t *rdataset) {
-       unsigned int size;
+init_rdataset(dns_rbtdb_t *rbtdb, rdatasetheader_t *h)
+{
+        ISC_LINK_INIT(h, lru_link);
+        h->heap_index = 0;
+
+#if TRACE_HEADER
+        if (IS_CACHE(rbtdb) && rbtdb->common.rdclass == dns_rdataclass_in)
+                fprintf(stderr, "initialized header: %p\n", h);
+#else
+        UNUSED(rbtdb);
+#endif
+}
 
-       if (rdataset->noqname != NULL)
-               free_noqname(mctx, &rdataset->noqname);
+static inline rdatasetheader_t *
+new_rdataset(dns_rbtdb_t *rbtdb, isc_mem_t *mctx)
+{
+        rdatasetheader_t *h;
 
-       free_acachearray(mctx, rdataset, rdataset->additional_auth);
-       free_acachearray(mctx, rdataset, rdataset->additional_glue);
+        h = isc_mem_get(mctx, sizeof(*h));
+        if (h == NULL)
+                return (NULL);
 
-       if ((rdataset->attributes & RDATASET_ATTR_NONEXISTENT) != 0)
-               size = sizeof(*rdataset);
-       else
-               size = dns_rdataslab_size((unsigned char *)rdataset,
-                                         sizeof(*rdataset));
-       isc_mem_put(mctx, rdataset, size);
+#if TRACE_HEADER
+        if (IS_CACHE(rbtdb) && rbtdb->common.rdclass == dns_rdataclass_in)
+                fprintf(stderr, "allocated header: %p\n", h);
+#endif
+        init_rdataset(rbtdb, h);
+        return (h);
+}
+
+static inline void
+free_rdataset(dns_rbtdb_t *rbtdb, isc_mem_t *mctx, rdatasetheader_t *rdataset)
+{
+        unsigned int size;
+
+#ifdef LRU_DEBUG
+        /*
+         * for debug: statistics update.
+         * Nothing in this block should have any side-effects.
+         */
+        if (EXISTS(rdataset) &&
+            (rdataset->attributes & RDATASET_ATTR_CACHE) != 0) {
+                rbtdb->cachestat.cache_current--;
+                if ((rdataset->attributes & RDATASET_ATTR_CANCELED) != 0)
+                        rbtdb->cachestat.cache_total--;
+                if (RBTDB_RDATATYPE_BASE(rdataset->type) == 0) {
+                        rbtdb->cachestat.ncache_current--;
+                        INSIST(rbtdb->cachestat.ncache_current >= 0);
+                        if ((rdataset->attributes & RDATASET_ATTR_CANCELED)
+                            != 0)
+                                rbtdb->cachestat.ncache_total--;
+                }
+                if (rdataset->type == dns_rdatatype_a) {
+                        rbtdb->cachestat.a_current--;
+                        INSIST(rbtdb->cachestat.a_current >= 0);
+                        if ((rdataset->attributes & RDATASET_ATTR_CANCELED)
+                            != 0)
+                                rbtdb->cachestat.a_total--;
+                } else if (rdataset->type == dns_rdatatype_aaaa) {
+                        rbtdb->cachestat.aaaa_current--;
+                        INSIST(rbtdb->cachestat.aaaa_current >= 0);
+                        if ((rdataset->attributes & RDATASET_ATTR_CANCELED)
+                            != 0)
+                                rbtdb->cachestat.aaaa_total--;
+                } else if (rdataset->type == dns_rdatatype_ptr) {
+                        rbtdb->cachestat.ptr_current--;
+                        INSIST(rbtdb->cachestat.ptr_current >= 0);
+                        if ((rdataset->attributes & RDATASET_ATTR_CANCELED)
+                            != 0)
+                                rbtdb->cachestat.ptr_total--;
+                } else if (rdataset->type == dns_rdatatype_ns) {
+                        rbtdb->cachestat.ns_current--;
+                        INSIST(rbtdb->cachestat.ns_current >= 0);
+                        if ((rdataset->attributes & RDATASET_ATTR_CANCELED)
+                            != 0)
+                                rbtdb->cachestat.ns_total--;
+                }
+                if (rdataset->trust == dns_trust_glue &&
+                    (rdataset->type == dns_rdatatype_a ||
+                     rdataset->type == dns_rdatatype_aaaa)) {
+                        rbtdb->cachestat.glue_current--;
+                        INSIST(rbtdb->cachestat.glue_current >= 0);
+                        if ((rdataset->attributes & RDATASET_ATTR_CANCELED)
+                            != 0)
+                                rbtdb->cachestat.glue_total--;
+                }
+                if (rdataset->trust == dns_trust_additional &&
+                    (rdataset->type == dns_rdatatype_a ||
+                     rdataset->type == dns_rdatatype_aaaa)) {
+                        rbtdb->cachestat.additional_current--;
+                        INSIST(rbtdb->cachestat.additional_current >= 0);
+                        if ((rdataset->attributes & RDATASET_ATTR_CANCELED)
+                            != 0)
+                                rbtdb->cachestat.additional_total--;
+                }
+        }
+#endif
+
+        if (IS_CACHE(rbtdb) && ISC_LINK_LINKED(rdataset, lru_link)) {
+                int idx = rdataset->node->locknum;
+                ISC_LIST_UNLINK(rbtdb->rdatasets[idx], rdataset, lru_link);
+                if (rdataset->heap_index != 0) {
+                        isc_heap_delete(rbtdb->heaps[idx],
+                                        rdataset->heap_index);
+                }
+                rdataset->heap_index = 0;
+        }
+
+        if (rdataset->noqname != NULL)
+                free_noqname(mctx, &rdataset->noqname);
+
+        free_acachearray(mctx, rdataset, rdataset->additional_auth);
+        free_acachearray(mctx, rdataset, rdataset->additional_glue);
+
+        if ((rdataset->attributes & RDATASET_ATTR_NONEXISTENT) != 0)
+                size = sizeof(*rdataset);
+        else
+                size = dns_rdataslab_size((unsigned char *)rdataset,
+                                          sizeof(*rdataset));
+        isc_mem_put(mctx, rdataset, size);
 }
 
 static inline void
 rollback_node(dns_rbtnode_t *node, rbtdb_serial_t serial) {
-       rdatasetheader_t *header, *dcurrent;
-       isc_boolean_t make_dirty = ISC_FALSE;
-
-       /*
-        * Caller must hold the node lock.
-        */
-
-       /*
-        * We set the IGNORE attribute on rdatasets with serial number
-        * 'serial'.  When the reference count goes to zero, these rdatasets
-        * will be cleaned up; until that time, they will be ignored.
-        */
-       for (header = node->data; header != NULL; header = header->next) {
-               if (header->serial == serial) {
-                       header->attributes |= RDATASET_ATTR_IGNORE;
-                       make_dirty = ISC_TRUE;
-               }
-               for (dcurrent = header->down;
-                    dcurrent != NULL;
-                    dcurrent = dcurrent->down) {
-                       if (dcurrent->serial == serial) {
-                               dcurrent->attributes |= RDATASET_ATTR_IGNORE;
-                               make_dirty = ISC_TRUE;
-                       }
-               }
-       }
-       if (make_dirty)
-               node->dirty = 1;
+        rdatasetheader_t *header, *dcurrent;
+        isc_boolean_t make_dirty = ISC_FALSE;
+
+        /*
+         * Caller must hold the node lock.
+         */
+
+        /*
+         * We set the IGNORE attribute on rdatasets with serial number
+         * 'serial'.  When the reference count goes to zero, these rdatasets
+         * will be cleaned up; until that time, they will be ignored.
+         */
+        for (header = node->data; header != NULL; header = header->next) {
+                if (header->serial == serial) {
+                        header->attributes |= RDATASET_ATTR_IGNORE;
+                        make_dirty = ISC_TRUE;
+                }
+                for (dcurrent = header->down;
+                     dcurrent != NULL;
+                     dcurrent = dcurrent->down) {
+                        if (dcurrent->serial == serial) {
+                                dcurrent->attributes |= RDATASET_ATTR_IGNORE;
+                                make_dirty = ISC_TRUE;
+                        }
+                }
+        }
+        if (make_dirty)
+                node->dirty = 1;
 }
 
 static inline void
-clean_stale_headers(isc_mem_t *mctx, rdatasetheader_t *top) {
-       rdatasetheader_t *d, *down_next;
-
-       for (d = top->down; d != NULL; d = down_next) {
-               down_next = d->down;
-               free_rdataset(mctx, d);
-       }
-       top->down = NULL;
+clean_stale_headers(dns_rbtdb_t *rbtdb, isc_mem_t *mctx, rdatasetheader_t *top)
+{
+        rdatasetheader_t *d, *down_next;
+
+        for (d = top->down; d != NULL; d = down_next) {
+                down_next = d->down;
+                free_rdataset(rbtdb, mctx, d);
+        }
+        top->down = NULL;
 }
 
 static inline void
 clean_cache_node(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node) {
-       rdatasetheader_t *current, *top_prev, *top_next;
-       isc_mem_t *mctx = rbtdb->common.mctx;
-
-       /*
-        * Caller must be holding the node lock.
-        */
-
-       top_prev = NULL;
-       for (current = node->data; current != NULL; current = top_next) {
-               top_next = current->next;
-               clean_stale_headers(mctx, current);
-               /*
-                * If current is nonexistent or stale, we can clean it up.
-                */
-               if ((current->attributes &
-                    (RDATASET_ATTR_NONEXISTENT|RDATASET_ATTR_STALE)) != 0) {
-                       if (top_prev != NULL)
-                               top_prev->next = current->next;
-                       else
-                               node->data = current->next;
-                       free_rdataset(mctx, current);
-               } else
-                       top_prev = current;
-       }
-       node->dirty = 0;
+        rdatasetheader_t *current, *top_prev, *top_next;
+        isc_mem_t *mctx = rbtdb->common.mctx;
+
+        /*
+         * Caller must be holding the node lock.
+         */
+
+        top_prev = NULL;
+        for (current = node->data; current != NULL; current = top_next) {
+                top_next = current->next;
+                clean_stale_headers(rbtdb, mctx, current);
+                /*
+                 * If current is nonexistent or stale, we can clean it up.
+                 */
+                if ((current->attributes &
+                     (RDATASET_ATTR_NONEXISTENT|RDATASET_ATTR_STALE)) != 0) {
+                        if (top_prev != NULL)
+                                top_prev->next = current->next;
+                        else
+                                node->data = current->next;
+                        free_rdataset(rbtdb, mctx, current);
+                } else
+                        top_prev = current;
+        }
+        node->dirty = 0;
 }
 
 static inline void
 clean_zone_node(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node,
-               rbtdb_serial_t least_serial)
+                rbtdb_serial_t least_serial)
 {
-       rdatasetheader_t *current, *dcurrent, *down_next, *dparent;
-       rdatasetheader_t *top_prev, *top_next;
-       isc_mem_t *mctx = rbtdb->common.mctx;
-       isc_boolean_t still_dirty = ISC_FALSE;
-
-       /*
-        * Caller must be holding the node lock.
-        */
-       REQUIRE(least_serial != 0);
-
-       top_prev = NULL;
-       for (current = node->data; current != NULL; current = top_next) {
-               top_next = current->next;
-
-               /*
-                * First, we clean up any instances of multiple rdatasets
-                * with the same serial number, or that have the IGNORE
-                * attribute.
-                */
-               dparent = current;
-               for (dcurrent = current->down;
-                    dcurrent != NULL;
-                    dcurrent = down_next) {
-                       down_next = dcurrent->down;
-                       INSIST(dcurrent->serial <= dparent->serial);
-                       if (dcurrent->serial == dparent->serial ||
-                           IGNORE(dcurrent)) {
-                               if (down_next != NULL)
-                                       down_next->next = dparent;
-                               dparent->down = down_next;
-                               free_rdataset(mctx, dcurrent);
-                       } else
-                               dparent = dcurrent;
-               }
-
-               /*
-                * We've now eliminated all IGNORE datasets with the possible
-                * exception of current, which we now check.
-                */
-               if (IGNORE(current)) {
-                       down_next = current->down;
-                       if (down_next == NULL) {
-                               if (top_prev != NULL)
-                                       top_prev->next = current->next;
-                               else
-                                       node->data = current->next;
-                               free_rdataset(mctx, current);
-                               /*
-                                * current no longer exists, so we can
-                                * just continue with the loop.
-                                */
-                               continue;
-                       } else {
-                               /*
-                                * Pull up current->down, making it the new
-                                * current.
-                                */
-                               if (top_prev != NULL)
-                                       top_prev->next = down_next;
-                               else
-                                       node->data = down_next;
-                               down_next->next = top_next;
-                               free_rdataset(mctx, current);
-                               current = down_next;
-                       }
-               }
-
-               /*
-                * We now try to find the first down node less than the
-                * least serial.
-                */
-               dparent = current;
-               for (dcurrent = current->down;
-                    dcurrent != NULL;
-                    dcurrent = down_next) {
-                       down_next = dcurrent->down;
-                       if (dcurrent->serial < least_serial)
-                               break;
-                       dparent = dcurrent;
-               }
-
-               /*
-                * If there is a such an rdataset, delete it and any older
-                * versions.
-                */
-               if (dcurrent != NULL) {
-                       do {
-                               down_next = dcurrent->down;
-                               INSIST(dcurrent->serial <= least_serial);
-                               free_rdataset(mctx, dcurrent);
-                               dcurrent = down_next;
-                       } while (dcurrent != NULL);
-                       dparent->down = NULL;
-               }
-
-               /*
-                * Note.  The serial number of 'current' might be less than
-                * least_serial too, but we cannot delete it because it is
-                * the most recent version, unless it is a NONEXISTENT
-                * rdataset.
-                */
-               if (current->down != NULL) {
-                       still_dirty = ISC_TRUE;
-                       top_prev = current;
-               } else {
-                       /*
-                        * If this is a NONEXISTENT rdataset, we can delete it.
-                        */
-                       if (NONEXISTENT(current)) {
-                               if (top_prev != NULL)
-                                       top_prev->next = current->next;
-                               else
-                                       node->data = current->next;
-                               free_rdataset(mctx, current);
-                       } else
-                               top_prev = current;
-               }
-       }
-       if (!still_dirty)
-               node->dirty = 0;
+        rdatasetheader_t *current, *dcurrent, *down_next, *dparent;
+        rdatasetheader_t *top_prev, *top_next;
+        isc_mem_t *mctx = rbtdb->common.mctx;
+        isc_boolean_t still_dirty = ISC_FALSE;
+
+        /*
+         * Caller must be holding the node lock.
+         */
+        REQUIRE(least_serial != 0);
+
+        top_prev = NULL;
+        for (current = node->data; current != NULL; current = top_next) {
+                top_next = current->next;
+
+                /*
+                 * First, we clean up any instances of multiple rdatasets
+                 * with the same serial number, or that have the IGNORE
+                 * attribute.
+                 */
+                dparent = current;
+                for (dcurrent = current->down;
+                     dcurrent != NULL;
+                     dcurrent = down_next) {
+                        down_next = dcurrent->down;
+                        INSIST(dcurrent->serial <= dparent->serial);
+                        if (dcurrent->serial == dparent->serial ||
+                            IGNORE(dcurrent)) {
+                                if (down_next != NULL)
+                                        down_next->next = dparent;
+                                dparent->down = down_next;
+                                free_rdataset(rbtdb, mctx, dcurrent);
+                        } else
+                                dparent = dcurrent;
+                }
+
+                /*
+                 * We've now eliminated all IGNORE datasets with the possible
+                 * exception of current, which we now check.
+                 */
+                if (IGNORE(current)) {
+                        down_next = current->down;
+                        if (down_next == NULL) {
+                                if (top_prev != NULL)
+                                        top_prev->next = current->next;
+                                else
+                                        node->data = current->next;
+                                free_rdataset(rbtdb, mctx, current);
+                                /*
+                                 * current no longer exists, so we can
+                                 * just continue with the loop.
+                                 */
+                                continue;
+                        } else {
+                                /*
+                                 * Pull up current->down, making it the new
+                                 * current.
+                                 */
+                                if (top_prev != NULL)
+                                        top_prev->next = down_next;
+                                else
+                                        node->data = down_next;
+                                down_next->next = top_next;
+                                free_rdataset(rbtdb, mctx, current);
+                                current = down_next;
+                        }
+                }
+
+                /*
+                 * We now try to find the first down node less than the
+                 * least serial.
+                 */
+                dparent = current;
+                for (dcurrent = current->down;
+                     dcurrent != NULL;
+                     dcurrent = down_next) {
+                        down_next = dcurrent->down;
+                        if (dcurrent->serial < least_serial)
+                                break;
+                        dparent = dcurrent;
+                }
+
+                /*
+                 * If there is a such an rdataset, delete it and any older
+                 * versions.
+                 */
+                if (dcurrent != NULL) {
+                        do {
+                                down_next = dcurrent->down;
+                                INSIST(dcurrent->serial <= least_serial);
+                                free_rdataset(rbtdb, mctx, dcurrent);
+                                dcurrent = down_next;
+                        } while (dcurrent != NULL);
+                        dparent->down = NULL;
+                }
+
+                /*
+                 * Note.  The serial number of 'current' might be less than
+                 * least_serial too, but we cannot delete it because it is
+                 * the most recent version, unless it is a NONEXISTENT
+                 * rdataset.
+                 */
+                if (current->down != NULL) {
+                        still_dirty = ISC_TRUE;
+                        top_prev = current;
+                } else {
+                        /*
+                         * If this is a NONEXISTENT rdataset, we can delete it.
+                         */
+                        if (NONEXISTENT(current)) {
+                                if (top_prev != NULL)
+                                        top_prev->next = current->next;
+                                else
+                                        node->data = current->next;
+                                free_rdataset(rbtdb, mctx, current);
+                        } else
+                                top_prev = current;
+                }
+        }
+        if (!still_dirty)
+                node->dirty = 0;
+}
+
+/*%
+ * Clean up dead nodes.  These are nodes which have no references, and
+ * have no data.  They are dead but we could not or chose not to delete
+ * them when we deleted all the data at that node because we did not want
+ * to wait for the tree write lock.
+ *
+ * The caller must hold a tree write lock and bucketnum'th node (write) lock.
+ */
+static void
+cleanup_dead_nodes(dns_rbtdb_t *rbtdb, int bucketnum) {
+        dns_rbtnode_t *node;
+        isc_result_t result;
+        int count = 10;         /* XXXJT: should be adjustable */
+
+        node = ISC_LIST_HEAD(rbtdb->deadnodes[bucketnum]);
+        while (node != NULL && count > 0) {
+                ISC_LIST_UNLINK(rbtdb->deadnodes[bucketnum], node, deadlink);
+
+                /*
+                 * Since we're holding a tree write lock, it should be
+                 * impossible for this node to be referenced by others.
+                 */
+                INSIST(dns_rbtnode_refcurrent(node) == 0 &&
+                       node->data == NULL);
+
+                result = dns_rbt_deletenode(rbtdb->tree, node, ISC_FALSE);
+                if (result != ISC_R_SUCCESS)
+                        isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+                                      DNS_LOGMODULE_CACHE, ISC_LOG_WARNING,
+                                      "cleanup_dead_nodes: "
+                                      "dns_rbt_deletenode: %s",
+                                      isc_result_totext(result));
+                node = ISC_LIST_HEAD(rbtdb->deadnodes[bucketnum]);
+                count--;
+        }
 }
 
 /*
@@ -1135,16 +1492,16 @@ clean_zone_node(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node,
  */
 static inline void
 new_reference(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node) {
-       unsigned int lockrefs, noderefs;
-       isc_refcount_t *lockref;
-
-       dns_rbtnode_refincrement0(node, &noderefs);
-       if (noderefs == 1) {    /* this is the first reference to the node */
-               lockref = &rbtdb->node_locks[node->locknum].references;
-               isc_refcount_increment0(lockref, &lockrefs);
-               INSIST(lockrefs != 0);
-       }
-       INSIST(noderefs != 0);
+        unsigned int lockrefs, noderefs;
+        isc_refcount_t *lockref;
+
+        dns_rbtnode_refincrement0(node, &noderefs);
+        if (noderefs == 1) {    /* this is the first reference to the node */
+                lockref = &rbtdb->node_locks[node->locknum].references;
+                isc_refcount_increment0(lockref, &lockrefs);
+                INSIST(lockrefs != 0);
+        }
+        INSIST(noderefs != 0);
 }
 
 /*
@@ -1159,420 +1516,426 @@ new_reference(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node) {
  */
 static isc_boolean_t
 decrement_reference(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node,
-                   rbtdb_serial_t least_serial,
-                   isc_rwlocktype_t nlock, isc_rwlocktype_t tlock)
+                    rbtdb_serial_t least_serial,
+                    isc_rwlocktype_t nlock, isc_rwlocktype_t tlock)
 {
-       isc_result_t result;
-       isc_boolean_t write_locked;
-       rbtdb_nodelock_t *nodelock;
-       unsigned int refs, nrefs;
-
-       nodelock = &rbtdb->node_locks[node->locknum];
-
-       /* Handle easy and typical case first. */
-       if (!node->dirty && (node->data != NULL || node->down != NULL)) {
-               dns_rbtnode_refdecrement(node, &nrefs);
-               INSIST((int)nrefs >= 0);
-               if (nrefs == 0) {
-                       isc_refcount_decrement(&nodelock->references, &refs);
-                       INSIST((int)refs >= 0);
-               }
-               return ((nrefs == 0) ? ISC_TRUE : ISC_FALSE);
-       }
-
-       /* Upgrade the lock? */
-       if (nlock == isc_rwlocktype_read) {
-               NODE_WEAKUNLOCK(&nodelock->lock, isc_rwlocktype_read);
-               NODE_WEAKLOCK(&nodelock->lock, isc_rwlocktype_write);
-       }
-       dns_rbtnode_refdecrement(node, &nrefs);
-       INSIST((int)nrefs >= 0);
-       if (nrefs > 0) {
-               /* Restore the lock? */
-               if (nlock == isc_rwlocktype_read)
-                       NODE_WEAKDOWNGRADE(&nodelock->lock);
-               return (ISC_FALSE);
-       }
-
-       if (node->dirty && dns_rbtnode_refcurrent(node) == 0) {
-               if (IS_CACHE(rbtdb))
-                       clean_cache_node(rbtdb, node);
-               else {
-                       if (least_serial == 0) {
-                               /*
-                                * Caller doesn't know the least serial.
-                                * Get it.
-                                */
-                               RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_read);
-                               least_serial = rbtdb->least_serial;
-                               RBTDB_UNLOCK(&rbtdb->lock,
-                                            isc_rwlocktype_read);
-                       }
-                       clean_zone_node(rbtdb, node, least_serial);
-               }
-       }
-
-       isc_refcount_decrement(&nodelock->references, &refs);
-       INSIST((int)refs >= 0);
-
-       /*
-        * XXXDCL should this only be done for cache zones?
-        */
-       if (node->data != NULL || node->down != NULL) {
-               /* Restore the lock? */
-               if (nlock == isc_rwlocktype_read)
-                       NODE_WEAKDOWNGRADE(&nodelock->lock);
-               return (ISC_TRUE);
-       }
-
-       /*
-        * XXXDCL need to add a deferred delete method for ISC_R_LOCKBUSY.
-        */
-       if (tlock != isc_rwlocktype_write) {
-               /*
-                * Locking hierarchy notwithstanding, we don't need to free
-                * the node lock before acquiring the tree write lock because
-                * we only do a trylock.
-                */
-               if (tlock == isc_rwlocktype_read)
-                       result = isc_rwlock_tryupgrade(&rbtdb->tree_lock);
-               else
-                       result = isc_rwlock_trylock(&rbtdb->tree_lock,
-                                                   isc_rwlocktype_write);
-               RUNTIME_CHECK(result == ISC_R_SUCCESS ||
-                             result == ISC_R_LOCKBUSY);
-               write_locked = ISC_TF(result == ISC_R_SUCCESS);
-       } else
-               write_locked = ISC_TRUE;
-
-       if (write_locked && dns_rbtnode_refcurrent(node) == 0) {
-               /*
-                * We can now delete the node if the reference counter is
-                * zero.  This should be typically the case, but a different
-                * thread may still gain a (new) reference just before the
-                * current thread locks the tree (e.g., in findnode()).
-                */
-
-               if (isc_log_wouldlog(dns_lctx, ISC_LOG_DEBUG(1))) {
-                       char printname[DNS_NAME_FORMATSIZE];
-
-                       isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
-                                     DNS_LOGMODULE_CACHE, ISC_LOG_DEBUG(1),
-                                     "decrement_reference: "
-                                     "delete from rbt: %p %s",
-                                     node,
-                                     dns_rbt_formatnodename(node, printname,
-                                                          sizeof(printname)));
-               }
-
-               result = dns_rbt_deletenode(rbtdb->tree, node, ISC_FALSE);
-               if (result != ISC_R_SUCCESS)
-                       isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
-                                     DNS_LOGMODULE_CACHE, ISC_LOG_WARNING,
-                                     "decrement_reference: "
-                                     "dns_rbt_deletenode: %s",
-                                     isc_result_totext(result));
-       }
-
-       /* Restore the lock? */
-       if (nlock == isc_rwlocktype_read)
-               NODE_WEAKDOWNGRADE(&nodelock->lock);
-
-       /*
-        * Relock a read lock, or unlock the write lock if no lock was held.
-        */
-       if (tlock == isc_rwlocktype_none)
-               if (write_locked)
-                       RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_write);
-
-       if (tlock == isc_rwlocktype_read)
-               if (write_locked)
-                       isc_rwlock_downgrade(&rbtdb->tree_lock);
-
-       return (ISC_TRUE);
+        isc_result_t result;
+        isc_boolean_t write_locked;
+        rbtdb_nodelock_t *nodelock;
+        unsigned int refs, nrefs;
+        int bucket = node->locknum;
+
+        nodelock = &rbtdb->node_locks[bucket];
+
+        /* Handle easy and typical case first. */
+        if (!node->dirty && (node->data != NULL || node->down != NULL)) {
+                dns_rbtnode_refdecrement(node, &nrefs);
+                INSIST((int)nrefs >= 0);
+                if (nrefs == 0) {
+                        isc_refcount_decrement(&nodelock->references, &refs);
+                        INSIST((int)refs >= 0);
+                }
+                return ((nrefs == 0) ? ISC_TRUE : ISC_FALSE);
+        }
+
+        /* Upgrade the lock? */
+        if (nlock == isc_rwlocktype_read) {
+                NODE_WEAKUNLOCK(&nodelock->lock, isc_rwlocktype_read);
+                NODE_WEAKLOCK(&nodelock->lock, isc_rwlocktype_write);
+        }
+        dns_rbtnode_refdecrement(node, &nrefs);
+        INSIST((int)nrefs >= 0);
+        if (nrefs > 0) {
+                /* Restore the lock? */
+                if (nlock == isc_rwlocktype_read)
+                        NODE_WEAKDOWNGRADE(&nodelock->lock);
+                return (ISC_FALSE);
+        }
+
+        if (node->dirty && dns_rbtnode_refcurrent(node) == 0) {
+                if (IS_CACHE(rbtdb))
+                        clean_cache_node(rbtdb, node);
+                else {
+                        if (least_serial == 0) {
+                                /*
+                                 * Caller doesn't know the least serial.
+                                 * Get it.
+                                 */
+                                RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_read);
+                                least_serial = rbtdb->least_serial;
+                                RBTDB_UNLOCK(&rbtdb->lock,
+                                             isc_rwlocktype_read);
+                        }
+                        clean_zone_node(rbtdb, node, least_serial);
+                }
+        }
+
+        isc_refcount_decrement(&nodelock->references, &refs);
+        INSIST((int)refs >= 0);
+
+        /*
+         * XXXDCL should this only be done for cache zones?
+         */
+        if (node->data != NULL || node->down != NULL) {
+                /* Restore the lock? */
+                if (nlock == isc_rwlocktype_read)
+                        NODE_WEAKDOWNGRADE(&nodelock->lock);
+                return (ISC_TRUE);
+        }
+
+        /*
+         * Attempt to switch to a write lock on the tree.  If this fails,
+         * we will add this node to a linked list of nodes in this locking
+         * bucket which we will free later.
+         */
+        if (tlock != isc_rwlocktype_write) {
+                /*
+                 * Locking hierarchy notwithstanding, we don't need to free
+                 * the node lock before acquiring the tree write lock because
+                 * we only do a trylock.
+                 */
+                if (tlock == isc_rwlocktype_read)
+                        result = isc_rwlock_tryupgrade(&rbtdb->tree_lock);
+                else
+                        result = isc_rwlock_trylock(&rbtdb->tree_lock,
+                                                    isc_rwlocktype_write);
+                RUNTIME_CHECK(result == ISC_R_SUCCESS ||
+                              result == ISC_R_LOCKBUSY);
+
+                write_locked = ISC_TF(result == ISC_R_SUCCESS);
+        } else
+                write_locked = ISC_TRUE;
+
+        if (write_locked && dns_rbtnode_refcurrent(node) == 0) {
+                /*
+                 * We can now delete the node if the reference counter is
+                 * zero.  This should be typically the case, but a different
+                 * thread may still gain a (new) reference just before the
+                 * current thread locks the tree (e.g., in findnode()).
+                 */
+
+                if (isc_log_wouldlog(dns_lctx, ISC_LOG_DEBUG(1))) {
+                        char printname[DNS_NAME_FORMATSIZE];
+
+                        isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+                                      DNS_LOGMODULE_CACHE, ISC_LOG_DEBUG(1),
+                                      "decrement_reference: "
+                                      "delete from rbt: %p %s",
+                                      node,
+                                      dns_rbt_formatnodename(node, printname,
+                                                           sizeof(printname)));
+                }
+
+                result = dns_rbt_deletenode(rbtdb->tree, node, ISC_FALSE);
+                if (result != ISC_R_SUCCESS)
+                        isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+                                      DNS_LOGMODULE_CACHE, ISC_LOG_WARNING,
+                                      "decrement_reference: "
+                                      "dns_rbt_deletenode: %s",
+                                      isc_result_totext(result));
+        } else if (dns_rbtnode_refcurrent(node) == 0) {
+                INSIST(!ISC_LINK_LINKED(node, deadlink));
+                ISC_LIST_APPEND(rbtdb->deadnodes[bucket], node, deadlink);
+        }
+
+        /* Restore the lock? */
+        if (nlock == isc_rwlocktype_read)
+                NODE_WEAKDOWNGRADE(&nodelock->lock);
+
+        /*
+         * Relock a read lock, or unlock the write lock if no lock was held.
+         */
+        if (tlock == isc_rwlocktype_none)
+                if (write_locked)
+                        RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_write);
+
+        if (tlock == isc_rwlocktype_read)
+                if (write_locked)
+                        isc_rwlock_downgrade(&rbtdb->tree_lock);
+
+        return (ISC_TRUE);
 }
 
 static inline void
 make_least_version(dns_rbtdb_t *rbtdb, rbtdb_version_t *version,
-                  rbtdb_changedlist_t *cleanup_list)
+                   rbtdb_changedlist_t *cleanup_list)
 {
-       /*
-        * Caller must be holding the database lock.
-        */
+        /*
+         * Caller must be holding the database lock.
+         */
 
-       rbtdb->least_serial = version->serial;
-       *cleanup_list = version->changed_list;
-       ISC_LIST_INIT(version->changed_list);
+        rbtdb->least_serial = version->serial;
+        *cleanup_list = version->changed_list;
+        ISC_LIST_INIT(version->changed_list);
 }
 
 static inline void
 cleanup_nondirty(rbtdb_version_t *version, rbtdb_changedlist_t *cleanup_list) {
-       rbtdb_changed_t *changed, *next_changed;
-
-       /*
-        * If the changed record is dirty, then
-        * an update created multiple versions of
-        * a given rdataset.  We keep this list
-        * until we're the least open version, at
-        * which point it's safe to get rid of any
-        * older versions.
-        *
-        * If the changed record isn't dirty, then
-        * we don't need it anymore since we're
-        * committing and not rolling back.
-        *
-        * The caller must be holding the database lock.
-        */
-       for (changed = HEAD(version->changed_list);
-            changed != NULL;
-            changed = next_changed) {
-               next_changed = NEXT(changed, link);
-               if (!changed->dirty) {
-                       UNLINK(version->changed_list,
-                              changed, link);
-                       APPEND(*cleanup_list,
-                              changed, link);
-               }
-       }
+        rbtdb_changed_t *changed, *next_changed;
+
+        /*
+         * If the changed record is dirty, then
+         * an update created multiple versions of
+         * a given rdataset.  We keep this list
+         * until we're the least open version, at
+         * which point it's safe to get rid of any
+         * older versions.
+         *
+         * If the changed record isn't dirty, then
+         * we don't need it anymore since we're
+         * committing and not rolling back.
+         *
+         * The caller must be holding the database lock.
+         */
+        for (changed = HEAD(version->changed_list);
+             changed != NULL;
+             changed = next_changed) {
+                next_changed = NEXT(changed, link);
+                if (!changed->dirty) {
+                        UNLINK(version->changed_list,
+                               changed, link);
+                        APPEND(*cleanup_list,
+                               changed, link);
+                }
+        }
 }
 
 static isc_boolean_t
 iszonesecure(dns_db_t *db, dns_dbnode_t *origin) {
-       dns_rdataset_t keyset;
-       dns_rdataset_t nsecset, signsecset;
-       isc_boolean_t haszonekey = ISC_FALSE;
-       isc_boolean_t hasnsec = ISC_FALSE;
-       isc_result_t result;
-
-       dns_rdataset_init(&keyset);
-       result = dns_db_findrdataset(db, origin, NULL, dns_rdatatype_dnskey, 0,
-                                    0, &keyset, NULL);
-       if (result == ISC_R_SUCCESS) {
-               dns_rdata_t keyrdata = DNS_RDATA_INIT;
-               result = dns_rdataset_first(&keyset);
-               while (result == ISC_R_SUCCESS) {
-                       dns_rdataset_current(&keyset, &keyrdata);
-                       if (dns_zonekey_iszonekey(&keyrdata)) {
-                               haszonekey = ISC_TRUE;
-                               break;
-                       }
-                       result = dns_rdataset_next(&keyset);
-               }
-               dns_rdataset_disassociate(&keyset);
-       }
-       if (!haszonekey)
-               return (ISC_FALSE);
-
-       dns_rdataset_init(&nsecset);
-       dns_rdataset_init(&signsecset);
-       result = dns_db_findrdataset(db, origin, NULL, dns_rdatatype_nsec, 0,
-                                    0, &nsecset, &signsecset);
-       if (result == ISC_R_SUCCESS) {
-               if (dns_rdataset_isassociated(&signsecset)) {
-                       hasnsec = ISC_TRUE;
-                       dns_rdataset_disassociate(&signsecset);
-               }
-               dns_rdataset_disassociate(&nsecset);
-       }
-       return (hasnsec);
+        dns_rdataset_t keyset;
+        dns_rdataset_t nsecset, signsecset;
+        isc_boolean_t haszonekey = ISC_FALSE;
+        isc_boolean_t hasnsec = ISC_FALSE;
+        isc_result_t result;
+
+        dns_rdataset_init(&keyset);
+        result = dns_db_findrdataset(db, origin, NULL, dns_rdatatype_dnskey, 0,
+                                     0, &keyset, NULL);
+        if (result == ISC_R_SUCCESS) {
+                dns_rdata_t keyrdata = DNS_RDATA_INIT;
+                result = dns_rdataset_first(&keyset);
+                while (result == ISC_R_SUCCESS) {
+                        dns_rdataset_current(&keyset, &keyrdata);
+                        if (dns_zonekey_iszonekey(&keyrdata)) {
+                                haszonekey = ISC_TRUE;
+                                break;
+                        }
+                        result = dns_rdataset_next(&keyset);
+                }
+                dns_rdataset_disassociate(&keyset);
+        }
+        if (!haszonekey)
+                return (ISC_FALSE);
+
+        dns_rdataset_init(&nsecset);
+        dns_rdataset_init(&signsecset);
+        result = dns_db_findrdataset(db, origin, NULL, dns_rdatatype_nsec, 0,
+                                     0, &nsecset, &signsecset);
+        if (result == ISC_R_SUCCESS) {
+                if (dns_rdataset_isassociated(&signsecset)) {
+                        hasnsec = ISC_TRUE;
+                        dns_rdataset_disassociate(&signsecset);
+                }
+                dns_rdataset_disassociate(&nsecset);
+        }
+        return (hasnsec);
 }
 
 static void
 closeversion(dns_db_t *db, dns_dbversion_t **versionp, isc_boolean_t commit) {
-       dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
-       rbtdb_version_t *version, *cleanup_version, *least_greater;
-       isc_boolean_t rollback = ISC_FALSE;
-       rbtdb_changedlist_t cleanup_list;
-       rbtdb_changed_t *changed, *next_changed;
-       rbtdb_serial_t serial, least_serial;
-       dns_rbtnode_t *rbtnode;
-       unsigned int refs;
-
-       REQUIRE(VALID_RBTDB(rbtdb));
-       version = (rbtdb_version_t *)*versionp;
-
-       cleanup_version = NULL;
-       ISC_LIST_INIT(cleanup_list);
-
-       isc_refcount_decrement(&version->references, &refs);
-       if (refs > 0) {         /* typical and easy case first */
-               if (commit) {
-                       RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_read);
-                       INSIST(!version->writer);
-                       RBTDB_UNLOCK(&rbtdb->lock, isc_rwlocktype_read);
-               }
-               goto end;
-       }
-
-       RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_write);
-       serial = version->serial;
-       if (version->writer) {
-               if (commit) {
-                       unsigned cur_ref;
-                       rbtdb_version_t *cur_version;
-
-                       INSIST(version->commit_ok);
-                       INSIST(version == rbtdb->future_version);
-                       /*
-                        * The current version is going to be replaced.
-                        * Release the (likely last) reference to it from the
-                        * DB itself and unlink it from the open list.
-                        */
-                       cur_version = rbtdb->current_version;
-                       isc_refcount_decrement(&cur_version->references,
-                                              &cur_ref);
-                       if (cur_ref == 0) {
-                               if (cur_version->serial == rbtdb->least_serial)
-                                       INSIST(EMPTY(cur_version->changed_list));
-                               UNLINK(rbtdb->open_versions,
-                                      cur_version, link);
-                       }
-                       if (EMPTY(rbtdb->open_versions)) {
-                               /*
-                                * We're going to become the least open
-                                * version.
-                                */
-                               make_least_version(rbtdb, version,
-                                                  &cleanup_list);
-                       } else {
-                               /*
-                                * Some other open version is the
-                                * least version.  We can't cleanup
-                                * records that were changed in this
-                                * version because the older versions
-                                * may still be in use by an open
-                                * version.
-                                *
-                                * We can, however, discard the
-                                * changed records for things that
-                                * we've added that didn't exist in
-                                * prior versions.
-                                */
-                               cleanup_nondirty(version, &cleanup_list);
-                       }
-                       /*
-                        * If the (soon to be former) current version
-                        * isn't being used by anyone, we can clean
-                        * it up.
-                        */
-                       if (cur_ref == 0) {
-                               cleanup_version = cur_version;
-                               APPENDLIST(version->changed_list,
-                                          cleanup_version->changed_list,
-                                          link);
-                       }
-                       /*
-                        * Become the current version.
-                        */
-                       version->writer = ISC_FALSE;
-                       rbtdb->current_version = version;
-                       rbtdb->current_serial = version->serial;
-                       rbtdb->future_version = NULL;
-
-                       /*
-                        * Keep the current version in the open list, and
-                        * gain a reference for the DB itself (see the DB
-                        * creation function below).  This must be the only
-                        * case where we need to increment the counter from
-                        * zero and need to use isc_refcount_increment0().
-                        */
-                       isc_refcount_increment0(&version->references,
-                                               &cur_ref);
-                       INSIST(cur_ref == 1);
-                       PREPEND(rbtdb->open_versions,
-                               rbtdb->current_version, link);
-               } else {
-                       /*
-                        * We're rolling back this transaction.
-                        */
-                       cleanup_list = version->changed_list;
-                       ISC_LIST_INIT(version->changed_list);
-                       rollback = ISC_TRUE;
-                       cleanup_version = version;
-                       rbtdb->future_version = NULL;
-               }
-       } else {
-               if (version != rbtdb->current_version) {
-                       /*
-                        * There are no external or internal references
-                        * to this version and it can be cleaned up.
-                        */
-                       cleanup_version = version;
-
-                       /*
-                        * Find the version with the least serial
-                        * number greater than ours.
-                        */
-                       least_greater = PREV(version, link);
-                       if (least_greater == NULL)
-                               least_greater = rbtdb->current_version;
-
-                       INSIST(version->serial < least_greater->serial);
-                       /*
-                        * Is this the least open version?
-                        */
-                       if (version->serial == rbtdb->least_serial) {
-                               /*
-                                * Yes.  Install the new least open
-                                * version.
-                                */
-                               make_least_version(rbtdb,
-                                                  least_greater,
-                                                  &cleanup_list);
-                       } else {
-                               /*
-                                * Add any unexecuted cleanups to
-                                * those of the least greater version.
-                                */
-                               APPENDLIST(least_greater->changed_list,
-                                          version->changed_list,
-                                          link);
-                       }
-               } else if (version->serial == rbtdb->least_serial)
-                       INSIST(EMPTY(version->changed_list));
-               UNLINK(rbtdb->open_versions, version, link);
-       }
-       least_serial = rbtdb->least_serial;
-       RBTDB_UNLOCK(&rbtdb->lock, isc_rwlocktype_write);
-
-       /*
-        * Update the zone's secure status.
-        */
-       if (version->writer && commit && !IS_CACHE(rbtdb))
-               rbtdb->secure = iszonesecure(db, rbtdb->origin_node);
-
-       if (cleanup_version != NULL) {
-               INSIST(EMPTY(cleanup_version->changed_list));
-               isc_mem_put(rbtdb->common.mctx, cleanup_version,
-                           sizeof(*cleanup_version));
-       }
-
-       if (!EMPTY(cleanup_list)) {
-               for (changed = HEAD(cleanup_list);
-                    changed != NULL;
-                    changed = next_changed) {
-                       nodelock_t *lock;
-
-                       next_changed = NEXT(changed, link);
-                       rbtnode = changed->node;
-                       lock = &rbtdb->node_locks[rbtnode->locknum].lock;
-
-                       NODE_LOCK(lock, isc_rwlocktype_write);
-                       if (rollback)
-                               rollback_node(rbtnode, serial);
-                       decrement_reference(rbtdb, rbtnode, least_serial,
-                                           isc_rwlocktype_write,
-                                           isc_rwlocktype_none);
-                       NODE_UNLOCK(lock, isc_rwlocktype_write);
-
-                       isc_mem_put(rbtdb->common.mctx, changed,
-                                   sizeof(*changed));
-               }
-       }
+        dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
+        rbtdb_version_t *version, *cleanup_version, *least_greater;
+        isc_boolean_t rollback = ISC_FALSE;
+        rbtdb_changedlist_t cleanup_list;
+        rbtdb_changed_t *changed, *next_changed;
+        rbtdb_serial_t serial, least_serial;
+        dns_rbtnode_t *rbtnode;
+        unsigned int refs;
+
+        REQUIRE(VALID_RBTDB(rbtdb));
+        version = (rbtdb_version_t *)*versionp;
+
+        cleanup_version = NULL;
+        ISC_LIST_INIT(cleanup_list);
+
+        isc_refcount_decrement(&version->references, &refs);
+        if (refs > 0) {         /* typical and easy case first */
+                if (commit) {
+                        RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_read);
+                        INSIST(!version->writer);
+                        RBTDB_UNLOCK(&rbtdb->lock, isc_rwlocktype_read);
+                }
+                goto end;
+        }
+
+        RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_write);
+        serial = version->serial;
+        if (version->writer) {
+                if (commit) {
+                        unsigned cur_ref;
+                        rbtdb_version_t *cur_version;
+
+                        INSIST(version->commit_ok);
+                        INSIST(version == rbtdb->future_version);
+                        /*
+                         * The current version is going to be replaced.
+                         * Release the (likely last) reference to it from the
+                         * DB itself and unlink it from the open list.
+                         */
+                        cur_version = rbtdb->current_version;
+                        isc_refcount_decrement(&cur_version->references,
+                                               &cur_ref);
+                        if (cur_ref == 0) {
+                                if (cur_version->serial == rbtdb->least_serial)
+                                        INSIST(EMPTY(cur_version->changed_list));
+                                UNLINK(rbtdb->open_versions,
+                                       cur_version, link);
+                        }
+                        if (EMPTY(rbtdb->open_versions)) {
+                                /*
+                                 * We're going to become the least open
+                                 * version.
+                                 */
+                                make_least_version(rbtdb, version,
+                                                   &cleanup_list);
+                        } else {
+                                /*
+                                 * Some other open version is the
+                                 * least version.  We can't cleanup
+                                 * records that were changed in this
+                                 * version because the older versions
+                                 * may still be in use by an open
+                                 * version.
+                                 *
+                                 * We can, however, discard the
+                                 * changed records for things that
+                                 * we've added that didn't exist in
+                                 * prior versions.
+                                 */
+                                cleanup_nondirty(version, &cleanup_list);
+                        }
+                        /*
+                         * If the (soon to be former) current version
+                         * isn't being used by anyone, we can clean
+                         * it up.
+                         */
+                        if (cur_ref == 0) {
+                                cleanup_version = cur_version;
+                                APPENDLIST(version->changed_list,
+                                           cleanup_version->changed_list,
+                                           link);
+                        }
+                        /*
+                         * Become the current version.
+                         */
+                        version->writer = ISC_FALSE;
+                        rbtdb->current_version = version;
+                        rbtdb->current_serial = version->serial;
+                        rbtdb->future_version = NULL;
+
+                        /*
+                         * Keep the current version in the open list, and
+                         * gain a reference for the DB itself (see the DB
+                         * creation function below).  This must be the only
+                         * case where we need to increment the counter from
+                         * zero and need to use isc_refcount_increment0().
+                         */
+                        isc_refcount_increment0(&version->references,
+                                                &cur_ref);
+                        INSIST(cur_ref == 1);
+                        PREPEND(rbtdb->open_versions,
+                                rbtdb->current_version, link);
+                } else {
+                        /*
+                         * We're rolling back this transaction.
+                         */
+                        cleanup_list = version->changed_list;
+                        ISC_LIST_INIT(version->changed_list);
+                        rollback = ISC_TRUE;
+                        cleanup_version = version;
+                        rbtdb->future_version = NULL;
+                }
+        } else {
+                if (version != rbtdb->current_version) {
+                        /*
+                         * There are no external or internal references
+                         * to this version and it can be cleaned up.
+                         */
+                        cleanup_version = version;
+
+                        /*
+                         * Find the version with the least serial
+                         * number greater than ours.
+                         */
+                        least_greater = PREV(version, link);
+                        if (least_greater == NULL)
+                                least_greater = rbtdb->current_version;
+
+                        INSIST(version->serial < least_greater->serial);
+                        /*
+                         * Is this the least open version?
+                         */
+                        if (version->serial == rbtdb->least_serial) {
+                                /*
+                                 * Yes.  Install the new least open
+                                 * version.
+                                 */
+                                make_least_version(rbtdb,
+                                                   least_greater,
+                                                   &cleanup_list);
+                        } else {
+                                /*
+                                 * Add any unexecuted cleanups to
+                                 * those of the least greater version.
+                                 */
+                                APPENDLIST(least_greater->changed_list,
+                                           version->changed_list,
+                                           link);
+                        }
+                } else if (version->serial == rbtdb->least_serial)
+                        INSIST(EMPTY(version->changed_list));
+                UNLINK(rbtdb->open_versions, version, link);
+        }
+        least_serial = rbtdb->least_serial;
+        RBTDB_UNLOCK(&rbtdb->lock, isc_rwlocktype_write);
+
+        /*
+         * Update the zone's secure status.
+         */
+        if (version->writer && commit && !IS_CACHE(rbtdb))
+                rbtdb->secure = iszonesecure(db, rbtdb->origin_node);
+
+        if (cleanup_version != NULL) {
+                INSIST(EMPTY(cleanup_version->changed_list));
+                isc_mem_put(rbtdb->common.mctx, cleanup_version,
+                            sizeof(*cleanup_version));
+        }
+
+        if (!EMPTY(cleanup_list)) {
+                for (changed = HEAD(cleanup_list);
+                     changed != NULL;
+                     changed = next_changed) {
+                        nodelock_t *lock;
+
+                        next_changed = NEXT(changed, link);
+                        rbtnode = changed->node;
+                        lock = &rbtdb->node_locks[rbtnode->locknum].lock;
+
+                        NODE_LOCK(lock, isc_rwlocktype_write);
+                        if (rollback)
+                                rollback_node(rbtnode, serial);
+                        decrement_reference(rbtdb, rbtnode, least_serial,
+                                            isc_rwlocktype_write,
+                                            isc_rwlocktype_none);
+                        NODE_UNLOCK(lock, isc_rwlocktype_write);
+
+                        isc_mem_put(rbtdb->common.mctx, changed,
+                                    sizeof(*changed));
+                }
+        }
 
   end:
-       *versionp = NULL;
+        *versionp = NULL;
 }
 
 /*
@@ -1590,3851 +1953,4130 @@ closeversion(dns_db_t *db, dns_dbversion_t **versionp, isc_boolean_t commit) {
  */
 static isc_result_t
 add_wildcard_magic(dns_rbtdb_t *rbtdb, dns_name_t *name) {
-       isc_result_t result;
-       dns_name_t foundname;
-       dns_offsets_t offsets;
-       unsigned int n;
-       dns_rbtnode_t *node = NULL;
-
-       dns_name_init(&foundname, offsets);
-       n = dns_name_countlabels(name);
-       INSIST(n >= 2);
-       n--;
-       dns_name_getlabelsequence(name, 1, n, &foundname);
-       result = dns_rbt_addnode(rbtdb->tree, &foundname, &node);
-       if (result != ISC_R_SUCCESS && result != ISC_R_EXISTS)
-               return (result);
-       node->find_callback = 1;
-       node->wild = 1;
-       return (ISC_R_SUCCESS);
+        isc_result_t result;
+        dns_name_t foundname;
+        dns_offsets_t offsets;
+        unsigned int n;
+        dns_rbtnode_t *node = NULL;
+
+        dns_name_init(&foundname, offsets);
+        n = dns_name_countlabels(name);
+        INSIST(n >= 2);
+        n--;
+        dns_name_getlabelsequence(name, 1, n, &foundname);
+        result = dns_rbt_addnode(rbtdb->tree, &foundname, &node);
+        if (result != ISC_R_SUCCESS && result != ISC_R_EXISTS)
+                return (result);
+        node->find_callback = 1;
+        node->wild = 1;
+        return (ISC_R_SUCCESS);
 }
 
 static isc_result_t
 add_empty_wildcards(dns_rbtdb_t *rbtdb, dns_name_t *name) {
-       isc_result_t result;
-       dns_name_t foundname;
-       dns_offsets_t offsets;
-       unsigned int n, l, i;
-
-       dns_name_init(&foundname, offsets);
-       n = dns_name_countlabels(name);
-       l = dns_name_countlabels(&rbtdb->common.origin);
-       i = l + 1;
-       while (i < n) {
-               dns_rbtnode_t *node = NULL;     /* dummy */
-               dns_name_getlabelsequence(name, n - i, i, &foundname);
-               if (dns_name_iswildcard(&foundname)) {
-                       result = add_wildcard_magic(rbtdb, &foundname);
-                       if (result != ISC_R_SUCCESS)
-                               return (result);
-                       result = dns_rbt_addnode(rbtdb->tree, &foundname,
-                                                &node);
-                       if (result != ISC_R_SUCCESS && result != ISC_R_EXISTS)
-                               return (result);
-               }
-               i++;
-       }
-       return (ISC_R_SUCCESS);
+        isc_result_t result;
+        dns_name_t foundname;
+        dns_offsets_t offsets;
+        unsigned int n, l, i;
+
+        dns_name_init(&foundname, offsets);
+        n = dns_name_countlabels(name);
+        l = dns_name_countlabels(&rbtdb->common.origin);
+        i = l + 1;
+        while (i < n) {
+                dns_rbtnode_t *node = NULL;     /* dummy */
+                dns_name_getlabelsequence(name, n - i, i, &foundname);
+                if (dns_name_iswildcard(&foundname)) {
+                        result = add_wildcard_magic(rbtdb, &foundname);
+                        if (result != ISC_R_SUCCESS)
+                                return (result);
+                        result = dns_rbt_addnode(rbtdb->tree, &foundname,
+                                                 &node);
+                        if (result != ISC_R_SUCCESS && result != ISC_R_EXISTS)
+                                return (result);
+                }
+                i++;
+        }
+        return (ISC_R_SUCCESS);
 }
 
 static isc_result_t
 findnode(dns_db_t *db, dns_name_t *name, isc_boolean_t create,
-        dns_dbnode_t **nodep)
+         dns_dbnode_t **nodep)
 {
-       dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
-       dns_rbtnode_t *node = NULL;
-       dns_name_t nodename;
-       isc_result_t result;
-       isc_rwlocktype_t locktype = isc_rwlocktype_read;
-
-       REQUIRE(VALID_RBTDB(rbtdb));
-
-       dns_name_init(&nodename, NULL);
-       RWLOCK(&rbtdb->tree_lock, locktype);
-       result = dns_rbt_findnode(rbtdb->tree, name, NULL, &node, NULL,
-                                 DNS_RBTFIND_EMPTYDATA, NULL, NULL);
-       if (result != ISC_R_SUCCESS) {
-               RWUNLOCK(&rbtdb->tree_lock, locktype);
-               if (!create) {
-                       if (result == DNS_R_PARTIALMATCH)
-                               result = ISC_R_NOTFOUND;
-                       return (result);
-               }
-               /*
-                * It would be nice to try to upgrade the lock instead of
-                * unlocking then relocking.
-                */
-               locktype = isc_rwlocktype_write;
-               RWLOCK(&rbtdb->tree_lock, locktype);
-               node = NULL;
-               result = dns_rbt_addnode(rbtdb->tree, name, &node);
-               if (result == ISC_R_SUCCESS) {
-                       dns_rbt_namefromnode(node, &nodename);
+        dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
+        dns_rbtnode_t *node = NULL;
+        dns_name_t nodename;
+        isc_result_t result;
+        isc_rwlocktype_t locktype = isc_rwlocktype_read;
+
+        REQUIRE(VALID_RBTDB(rbtdb));
+
+        dns_name_init(&nodename, NULL);
+        RWLOCK(&rbtdb->tree_lock, locktype);
+        result = dns_rbt_findnode(rbtdb->tree, name, NULL, &node, NULL,
+                                  DNS_RBTFIND_EMPTYDATA, NULL, NULL);
+        if (result != ISC_R_SUCCESS) {
+                RWUNLOCK(&rbtdb->tree_lock, locktype);
+                if (!create) {
+                        if (result == DNS_R_PARTIALMATCH)
+                                result = ISC_R_NOTFOUND;
+                        return (result);
+                }
+                /*
+                 * It would be nice to try to upgrade the lock instead of
+                 * unlocking then relocking.
+                 */
+                locktype = isc_rwlocktype_write;
+                RWLOCK(&rbtdb->tree_lock, locktype);
+                node = NULL;
+                result = dns_rbt_addnode(rbtdb->tree, name, &node);
+                if (result == ISC_R_SUCCESS) {
+                        dns_rbt_namefromnode(node, &nodename);
 #ifdef DNS_RBT_USEHASH
-                       node->locknum = node->hashval % rbtdb->node_lock_count;
+                        node->locknum = node->hashval % rbtdb->node_lock_count;
 #else
-                       node->locknum = dns_name_hash(&nodename, ISC_TRUE) %
-                               rbtdb->node_lock_count;
+                        node->locknum = dns_name_hash(&nodename, ISC_TRUE) %
+                                rbtdb->node_lock_count;
 #endif
-                       add_empty_wildcards(rbtdb, name);
-
-                       if (dns_name_iswildcard(name)) {
-                               result = add_wildcard_magic(rbtdb, name);
-                               if (result != ISC_R_SUCCESS) {
-                                       RWUNLOCK(&rbtdb->tree_lock, locktype);
-                                       return (result);
-                               }
-                       }
-               } else if (result != ISC_R_EXISTS) {
-                       RWUNLOCK(&rbtdb->tree_lock, locktype);
-                       return (result);
-               }
-       }
-       NODE_STRONGLOCK(&rbtdb->node_locks[node->locknum].lock);
-       new_reference(rbtdb, node);
-       NODE_STRONGUNLOCK(&rbtdb->node_locks[node->locknum].lock);
-       RWUNLOCK(&rbtdb->tree_lock, locktype);
-
-       *nodep = (dns_dbnode_t *)node;
-
-       return (ISC_R_SUCCESS);
+                        add_empty_wildcards(rbtdb, name);
+
+                        if (dns_name_iswildcard(name)) {
+                                result = add_wildcard_magic(rbtdb, name);
+                                if (result != ISC_R_SUCCESS) {
+                                        RWUNLOCK(&rbtdb->tree_lock, locktype);
+                                        return (result);
+                                }
+                        }
+                } else if (result != ISC_R_EXISTS) {
+                        RWUNLOCK(&rbtdb->tree_lock, locktype);
+                        return (result);
+                }
+        }
+        NODE_STRONGLOCK(&rbtdb->node_locks[node->locknum].lock);
+        new_reference(rbtdb, node);
+
+        /*
+         * If the node just found is in the deadnode list, we need to retrieve
+         * it from the list because we are going to use the node.  There are
+         * other cases where a node is newly referenced, but this should be
+         * the only case where it can be in the deadnode list.  Also, if we
+         * happen to hold a write lock on the tree, it's a good chance to purge
+         * dead nodes.
+         */
+        if (IS_CACHE(rbtdb)) {
+                isc_boolean_t need_relock = ISC_FALSE;
+
+                NODE_WEAKLOCK(&rbtdb->node_locks[node->locknum].lock,
+                              isc_rwlocktype_read);
+                if (ISC_LINK_LINKED(node, deadlink) && isc_rwlocktype_write)
+                        need_relock = ISC_TRUE;
+                else if (!ISC_LIST_EMPTY(rbtdb->deadnodes[node->locknum]) &&
+                         locktype == isc_rwlocktype_write)
+                        need_relock = ISC_TRUE;
+                NODE_WEAKUNLOCK(&rbtdb->node_locks[node->locknum].lock,
+                                isc_rwlocktype_read);
+                if (need_relock) {
+                        NODE_WEAKLOCK(&rbtdb->node_locks[node->locknum].lock,
+                                      isc_rwlocktype_write);
+                        if (ISC_LINK_LINKED(node, deadlink))
+                                ISC_LIST_UNLINK(rbtdb->deadnodes[node->locknum],
+                                                node, deadlink);
+                        if (locktype == isc_rwlocktype_write)
+                                cleanup_dead_nodes(rbtdb, node->locknum);
+                        NODE_WEAKUNLOCK(&rbtdb->node_locks[node->locknum].lock,
+                                        isc_rwlocktype_write);
+                }
+        }
+
+        NODE_STRONGUNLOCK(&rbtdb->node_locks[node->locknum].lock);
+        RWUNLOCK(&rbtdb->tree_lock, locktype);
+
+        *nodep = (dns_dbnode_t *)node;
+
+        return (ISC_R_SUCCESS);
 }
 
 static isc_result_t
 zone_zonecut_callback(dns_rbtnode_t *node, dns_name_t *name, void *arg) {
-       rbtdb_search_t *search = arg;
-       rdatasetheader_t *header, *header_next;
-       rdatasetheader_t *dname_header, *sigdname_header, *ns_header;
-       rdatasetheader_t *found;
-       isc_result_t result;
-       dns_rbtnode_t *onode;
-
-       /*
-        * We only want to remember the topmost zone cut, since it's the one
-        * that counts, so we'll just continue if we've already found a
-        * zonecut.
-        */
-       if (search->zonecut != NULL)
-               return (DNS_R_CONTINUE);
-
-       found = NULL;
-       result = DNS_R_CONTINUE;
-       onode = search->rbtdb->origin_node;
-
-       NODE_LOCK(&(search->rbtdb->node_locks[node->locknum].lock),
-                 isc_rwlocktype_read);
-
-       /*
-        * Look for an NS or DNAME rdataset active in our version.
-        */
-       ns_header = NULL;
-       dname_header = NULL;
-       sigdname_header = NULL;
-       for (header = node->data; header != NULL; header = header_next) {
-               header_next = header->next;
-               if (header->type == dns_rdatatype_ns ||
-                   header->type == dns_rdatatype_dname ||
-                   header->type == RBTDB_RDATATYPE_SIGDNAME) {
-                       do {
-                               if (header->serial <= search->serial &&
-                                   !IGNORE(header)) {
-                                       /*
-                                        * Is this a "this rdataset doesn't
-                                        * exist" record?
-                                        */
-                                       if (NONEXISTENT(header))
-                                               header = NULL;
-                                       break;
-                               } else
-                                       header = header->down;
-                       } while (header != NULL);
-                       if (header != NULL) {
-                               if (header->type == dns_rdatatype_dname)
-                                       dname_header = header;
-                               else if (header->type == 
-                                          RBTDB_RDATATYPE_SIGDNAME)
-                                       sigdname_header = header;
-                               else if (node != onode ||
-                                        IS_STUB(search->rbtdb)) {
-                                       /*
-                                        * We've found an NS rdataset that
-                                        * isn't at the origin node.  We check
-                                        * that they're not at the origin node,
-                                        * because otherwise we'd erroneously
-                                        * treat the zone top as if it were
-                                        * a delegation.
-                                        */
-                                       ns_header = header;
-                               }
-                       }
-               }
-       }
-
-       /*
-        * Did we find anything?
-        */
-       if (dname_header != NULL) {
-               /*
-                * Note that DNAME has precedence over NS if both exist.
-                */
-               found = dname_header;
-               search->zonecut_sigrdataset = sigdname_header;
-       } else if (ns_header != NULL) {
-               found = ns_header;
-               search->zonecut_sigrdataset = NULL;
-       }
-
-       if (found != NULL) {
-               /*
-                * We increment the reference count on node to ensure that
-                * search->zonecut_rdataset will still be valid later.
-                */
-               new_reference(search->rbtdb, node);
-               search->zonecut = node;
-               search->zonecut_rdataset = found;
-               search->need_cleanup = ISC_TRUE;
-               /*
-                * Since we've found a zonecut, anything beneath it is
-                * glue and is not subject to wildcard matching, so we
-                * may clear search->wild.
-                */
-               search->wild = ISC_FALSE;
-               if ((search->options & DNS_DBFIND_GLUEOK) == 0) {
-                       /*
-                        * If the caller does not want to find glue, then
-                        * this is the best answer and the search should
-                        * stop now.
-                        */
-                       result = DNS_R_PARTIALMATCH;
-               } else {
-                       dns_name_t *zcname;
-
-                       /*
-                        * The search will continue beneath the zone cut.
-                        * This may or may not be the best match.  In case it
-                        * is, we need to remember the node name.
-                        */
-                       zcname = dns_fixedname_name(&search->zonecut_name);
-                       RUNTIME_CHECK(dns_name_copy(name, zcname, NULL) ==
-                                     ISC_R_SUCCESS);
-                       search->copy_name = ISC_TRUE;
-               }
-       } else {
-               /*
-                * There is no zonecut at this node which is active in this
-                * version.
-                *
-                * If this is a "wild" node and the caller hasn't disabled
-                * wildcard matching, remember that we've seen a wild node
-                * in case we need to go searching for wildcard matches
-                * later on.
-                */
-               if (node->wild && (search->options & DNS_DBFIND_NOWILD) == 0)
-                       search->wild = ISC_TRUE;
-       }
-
-       NODE_UNLOCK(&(search->rbtdb->node_locks[node->locknum].lock),
-                   isc_rwlocktype_read);
-
-       return (result);
+        rbtdb_search_t *search = arg;
+        rdatasetheader_t *header, *header_next;
+        rdatasetheader_t *dname_header, *sigdname_header, *ns_header;
+        rdatasetheader_t *found;
+        isc_result_t result;
+        dns_rbtnode_t *onode;
+
+        /*
+         * We only want to remember the topmost zone cut, since it's the one
+         * that counts, so we'll just continue if we've already found a
+         * zonecut.
+         */
+        if (search->zonecut != NULL)
+                return (DNS_R_CONTINUE);
+
+        found = NULL;
+        result = DNS_R_CONTINUE;
+        onode = search->rbtdb->origin_node;
+
+        NODE_LOCK(&(search->rbtdb->node_locks[node->locknum].lock),
+                  isc_rwlocktype_read);
+
+        /*
+         * Look for an NS or DNAME rdataset active in our version.
+         */
+        ns_header = NULL;
+        dname_header = NULL;
+        sigdname_header = NULL;
+        for (header = node->data; header != NULL; header = header_next) {
+                header_next = header->next;
+                if (header->type == dns_rdatatype_ns ||
+                    header->type == dns_rdatatype_dname ||
+                    header->type == RBTDB_RDATATYPE_SIGDNAME) {
+                        do {
+                                if (header->serial <= search->serial &&
+                                    !IGNORE(header)) {
+                                        /*
+                                         * Is this a "this rdataset doesn't
+                                         * exist" record?
+                                         */
+                                        if (NONEXISTENT(header))
+                                                header = NULL;
+                                        break;
+                                } else
+                                        header = header->down;
+                        } while (header != NULL);
+                        if (header != NULL) {
+                                if (header->type == dns_rdatatype_dname)
+                                        dname_header = header;
+                                else if (header->type ==
+                                           RBTDB_RDATATYPE_SIGDNAME)
+                                        sigdname_header = header;
+                                else if (node != onode ||
+                                         IS_STUB(search->rbtdb)) {
+                                        /*
+                                         * We've found an NS rdataset that
+                                         * isn't at the origin node.  We check
+                                         * that they're not at the origin node,
+                                         * because otherwise we'd erroneously
+                                         * treat the zone top as if it were
+                                         * a delegation.
+                                         */
+                                        ns_header = header;
+                                }
+                        }
+                }
+        }
+
+        /*
+         * Did we find anything?
+         */
+        if (dname_header != NULL) {
+                /*
+                 * Note that DNAME has precedence over NS if both exist.
+                 */
+                found = dname_header;
+                search->zonecut_sigrdataset = sigdname_header;
+        } else if (ns_header != NULL) {
+                found = ns_header;
+                search->zonecut_sigrdataset = NULL;
+        }
+
+        if (found != NULL) {
+                /*
+                 * We increment the reference count on node to ensure that
+                 * search->zonecut_rdataset will still be valid later.
+                 */
+                new_reference(search->rbtdb, node);
+                search->zonecut = node;
+                search->zonecut_rdataset = found;
+                search->need_cleanup = ISC_TRUE;
+                /*
+                 * Since we've found a zonecut, anything beneath it is
+                 * glue and is not subject to wildcard matching, so we
+                 * may clear search->wild.
+                 */
+                search->wild = ISC_FALSE;
+                if ((search->options & DNS_DBFIND_GLUEOK) == 0) {
+                        /*
+                         * If the caller does not want to find glue, then
+                         * this is the best answer and the search should
+                         * stop now.
+                         */
+                        result = DNS_R_PARTIALMATCH;
+                } else {
+                        dns_name_t *zcname;
+
+                        /*
+                         * The search will continue beneath the zone cut.
+                         * This may or may not be the best match.  In case it
+                         * is, we need to remember the node name.
+                         */
+                        zcname = dns_fixedname_name(&search->zonecut_name);
+                        RUNTIME_CHECK(dns_name_copy(name, zcname, NULL) ==
+                                      ISC_R_SUCCESS);
+                        search->copy_name = ISC_TRUE;
+                }
+        } else {
+                /*
+                 * There is no zonecut at this node which is active in this
+                 * version.
+                 *
+                 * If this is a "wild" node and the caller hasn't disabled
+                 * wildcard matching, remember that we've seen a wild node
+                 * in case we need to go searching for wildcard matches
+                 * later on.
+                 */
+                if (node->wild && (search->options & DNS_DBFIND_NOWILD) == 0)
+                        search->wild = ISC_TRUE;
+        }
+
+        NODE_UNLOCK(&(search->rbtdb->node_locks[node->locknum].lock),
+                    isc_rwlocktype_read);
+
+        return (result);
 }
 
 static inline void
 bind_rdataset(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node,
-             rdatasetheader_t *header, isc_stdtime_t now,
-             dns_rdataset_t *rdataset)
+              rdatasetheader_t *header, isc_stdtime_t now,
+              dns_rdataset_t *rdataset)
 {
-       unsigned char *raw;     /* RDATASLAB */
-
-       /*
-        * Caller must be holding the node reader lock.
-        * XXXJT: technically, we need a writer lock, since we'll increment
-        * the header count below.  However, since the actual counter value
-        * doesn't matter, we prioritize performance here.  (We may want to
-        * use atomic increment when available).
-        */
-
-       if (rdataset == NULL)
-               return;
-
-       new_reference(rbtdb, node);
-
-       INSIST(rdataset->methods == NULL);      /* We must be disassociated. */
-
-       rdataset->methods = &rdataset_methods;
-       rdataset->rdclass = rbtdb->common.rdclass;
-       rdataset->type = RBTDB_RDATATYPE_BASE(header->type);
-       rdataset->covers = RBTDB_RDATATYPE_EXT(header->type);
-       rdataset->ttl = header->ttl - now;
-       rdataset->trust = header->trust;
-       if (NXDOMAIN(header))
-               rdataset->attributes |= DNS_RDATASETATTR_NXDOMAIN;
-       rdataset->private1 = rbtdb;
-       rdataset->private2 = node;
-       raw = (unsigned char *)header + sizeof(*header);
-       rdataset->private3 = raw;
-       rdataset->count = header->count++;
-       if (rdataset->count == ISC_UINT32_MAX)
-               rdataset->count = 0;
-
-       /*
-        * Reset iterator state.
-        */
-       rdataset->privateuint4 = 0;
-       rdataset->private5 = NULL;
-
-       /*
-        * Add noqname proof.
-        */
-       rdataset->private6 = header->noqname;
-       if (rdataset->private6 != NULL)
-               rdataset->attributes |=  DNS_RDATASETATTR_NOQNAME;
+        unsigned char *raw;     /* RDATASLAB */
+
+        /*
+         * Caller must be holding the node reader lock.
+         * XXXJT: technically, we need a writer lock, since we'll increment
+         * the header count below.  However, since the actual counter value
+         * doesn't matter, we prioritize performance here.  (We may want to
+         * use atomic increment when available).
+         */
+
+        if (rdataset == NULL)
+                return;
+
+        new_reference(rbtdb, node);
+
+        INSIST(rdataset->methods == NULL);      /* We must be disassociated. */
+
+        rdataset->methods = &rdataset_methods;
+        rdataset->rdclass = rbtdb->common.rdclass;
+        rdataset->type = RBTDB_RDATATYPE_BASE(header->type);
+        rdataset->covers = RBTDB_RDATATYPE_EXT(header->type);
+        rdataset->ttl = header->rdh_ttl - now;
+        rdataset->trust = header->trust;
+        if (NXDOMAIN(header))
+                rdataset->attributes |= DNS_RDATASETATTR_NXDOMAIN;
+        rdataset->private1 = rbtdb;
+        rdataset->private2 = node;
+        raw = (unsigned char *)header + sizeof(*header);
+        rdataset->private3 = raw;
+        rdataset->count = header->count++;
+        if (rdataset->count == ISC_UINT32_MAX)
+                rdataset->count = 0;
+
+        /*
+         * Reset iterator state.
+         */
+        rdataset->privateuint4 = 0;
+        rdataset->private5 = NULL;
+
+        /*
+         * Add noqname proof.
+         */
+        rdataset->private6 = header->noqname;
+        if (rdataset->private6 != NULL)
+                rdataset->attributes |=  DNS_RDATASETATTR_NOQNAME;
 }
 
 static inline isc_result_t
 setup_delegation(rbtdb_search_t *search, dns_dbnode_t **nodep,
-                dns_name_t *foundname, dns_rdataset_t *rdataset,
-                dns_rdataset_t *sigrdataset)
+                 dns_name_t *foundname, dns_rdataset_t *rdataset,
+                 dns_rdataset_t *sigrdataset)
 {
-       isc_result_t result;
-       dns_name_t *zcname;
-       rbtdb_rdatatype_t type;
-       dns_rbtnode_t *node;
-
-       /*
-        * The caller MUST NOT be holding any node locks.
-        */
-
-       node = search->zonecut;
-       type = search->zonecut_rdataset->type;
-
-       /*
-        * If we have to set foundname, we do it before anything else.
-        * If we were to set foundname after we had set nodep or bound the
-        * rdataset, then we'd have to undo that work if dns_name_copy()
-        * failed.  By setting foundname first, there's nothing to undo if
-        * we have trouble.
-        */
-       if (foundname != NULL && search->copy_name) {
-               zcname = dns_fixedname_name(&search->zonecut_name);
-               result = dns_name_copy(zcname, foundname, NULL);
-               if (result != ISC_R_SUCCESS)
-                       return (result);
-       }
-       if (nodep != NULL) {
-               /*
-                * Note that we don't have to increment the node's reference
-                * count here because we're going to use the reference we
-                * already have in the search block.
-                */
-               *nodep = node;
-               search->need_cleanup = ISC_FALSE;
-       }
-       if (rdataset != NULL) {
-               NODE_LOCK(&(search->rbtdb->node_locks[node->locknum].lock),
-                         isc_rwlocktype_read);
-               bind_rdataset(search->rbtdb, node, search->zonecut_rdataset,
-                             search->now, rdataset);
-               if (sigrdataset != NULL && search->zonecut_sigrdataset != NULL)
-                       bind_rdataset(search->rbtdb, node,
-                                     search->zonecut_sigrdataset,
-                                     search->now, sigrdataset);
-               NODE_UNLOCK(&(search->rbtdb->node_locks[node->locknum].lock),
-                           isc_rwlocktype_read);
-       }
-
-       if (type == dns_rdatatype_dname)
-               return (DNS_R_DNAME);
-       return (DNS_R_DELEGATION);
+        isc_result_t result;
+        dns_name_t *zcname;
+        rbtdb_rdatatype_t type;
+        dns_rbtnode_t *node;
+
+        /*
+         * The caller MUST NOT be holding any node locks.
+         */
+
+        node = search->zonecut;
+        type = search->zonecut_rdataset->type;
+
+        /*
+         * If we have to set foundname, we do it before anything else.
+         * If we were to set foundname after we had set nodep or bound the
+         * rdataset, then we'd have to undo that work if dns_name_copy()
+         * failed.  By setting foundname first, there's nothing to undo if
+         * we have trouble.
+         */
+        if (foundname != NULL && search->copy_name) {
+                zcname = dns_fixedname_name(&search->zonecut_name);
+                result = dns_name_copy(zcname, foundname, NULL);
+                if (result != ISC_R_SUCCESS)
+                        return (result);
+        }
+        if (nodep != NULL) {
+                /*
+                 * Note that we don't have to increment the node's reference
+                 * count here because we're going to use the reference we
+                 * already have in the search block.
+                 */
+                *nodep = node;
+                search->need_cleanup = ISC_FALSE;
+        }
+        if (rdataset != NULL) {
+                NODE_LOCK(&(search->rbtdb->node_locks[node->locknum].lock),
+                          isc_rwlocktype_read);
+                bind_rdataset(search->rbtdb, node, search->zonecut_rdataset,
+                              search->now, rdataset);
+                if (sigrdataset != NULL && search->zonecut_sigrdataset != NULL)
+                        bind_rdataset(search->rbtdb, node,
+                                      search->zonecut_sigrdataset,
+                                      search->now, sigrdataset);
+                NODE_UNLOCK(&(search->rbtdb->node_locks[node->locknum].lock),
+                            isc_rwlocktype_read);
+        }
+
+        if (type == dns_rdatatype_dname)
+                return (DNS_R_DNAME);
+        return (DNS_R_DELEGATION);
 }
 
 static inline isc_boolean_t
 valid_glue(rbtdb_search_t *search, dns_name_t *name, rbtdb_rdatatype_t type,
-          dns_rbtnode_t *node)
+           dns_rbtnode_t *node)
 {
-       unsigned char *raw;     /* RDATASLAB */
-       unsigned int count, size;
-       dns_name_t ns_name;
-       isc_boolean_t valid = ISC_FALSE;
-       dns_offsets_t offsets;
-       isc_region_t region;
-       rdatasetheader_t *header;
-
-       /*
-        * No additional locking is required.
-        */
-
-       /*
-        * Valid glue types are A, AAAA, A6.  NS is also a valid glue type
-        * if it occurs at a zone cut, but is not valid below it.
-        */
-       if (type == dns_rdatatype_ns) {
-               if (node != search->zonecut) {
-                       return (ISC_FALSE);
-               }
-       } else if (type != dns_rdatatype_a &&
-                  type != dns_rdatatype_aaaa &&
-                  type != dns_rdatatype_a6) {
-               return (ISC_FALSE);
-       }
-
-       header = search->zonecut_rdataset;
-       raw = (unsigned char *)header + sizeof(*header);
-       count = raw[0] * 256 + raw[1];
+        unsigned char *raw;     /* RDATASLAB */
+        unsigned int count, size;
+        dns_name_t ns_name;
+        isc_boolean_t valid = ISC_FALSE;
+        dns_offsets_t offsets;
+        isc_region_t region;
+        rdatasetheader_t *header;
+
+        /*
+         * No additional locking is required.
+         */
+
+        /*
+         * Valid glue types are A, AAAA, A6.  NS is also a valid glue type
+         * if it occurs at a zone cut, but is not valid below it.
+         */
+        if (type == dns_rdatatype_ns) {
+                if (node != search->zonecut) {
+                        return (ISC_FALSE);
+                }
+        } else if (type != dns_rdatatype_a &&
+                   type != dns_rdatatype_aaaa &&
+                   type != dns_rdatatype_a6) {
+                return (ISC_FALSE);
+        }
+
+        header = search->zonecut_rdataset;
+        raw = (unsigned char *)header + sizeof(*header);
+        count = raw[0] * 256 + raw[1];
 #if DNS_RDATASET_FIXED
-       raw += 2 + (4 * count);
-#else 
-       raw += 2;
+        raw += 2 + (4 * count);
+#else
+        raw += 2;
 #endif
 
-       while (count > 0) {
-               count--;
-               size = raw[0] * 256 + raw[1];
+        while (count > 0) {
+                count--;
+                size = raw[0] * 256 + raw[1];
 #if DNS_RDATASET_FIXED
-               raw += 4;
+                raw += 4;
 #else
-               raw += 2;
+                raw += 2;
 #endif
-               region.base = raw;
-               region.length = size;
-               raw += size;
-               /*
-                * XXX Until we have rdata structures, we have no choice but
-                * to directly access the rdata format.
-                */
-               dns_name_init(&ns_name, offsets);
-               dns_name_fromregion(&ns_name, &region);
-               if (dns_name_compare(&ns_name, name) == 0) {
-                       valid = ISC_TRUE;
-                       break;
-               }
-       }
-
-       return (valid);
+                region.base = raw;
+                region.length = size;
+                raw += size;
+                /*
+                 * XXX Until we have rdata structures, we have no choice but
+                 * to directly access the rdata format.
+                 */
+                dns_name_init(&ns_name, offsets);
+                dns_name_fromregion(&ns_name, &region);
+                if (dns_name_compare(&ns_name, name) == 0) {
+                        valid = ISC_TRUE;
+                        break;
+                }
+        }
+
+        return (valid);
 }
 
 static inline isc_boolean_t
 activeempty(rbtdb_search_t *search, dns_rbtnodechain_t *chain,
-           dns_name_t *name)
+            dns_name_t *name)
 {
-       dns_fixedname_t fnext;
-       dns_fixedname_t forigin;
-       dns_name_t *next;
-       dns_name_t *origin;
-       dns_name_t prefix;
-       dns_rbtdb_t *rbtdb;
-       dns_rbtnode_t *node;
-       isc_result_t result;
-       isc_boolean_t answer = ISC_FALSE;
-       rdatasetheader_t *header;
-
-       rbtdb = search->rbtdb;
-
-       dns_name_init(&prefix, NULL);
-       dns_fixedname_init(&fnext);
-       next = dns_fixedname_name(&fnext);
-       dns_fixedname_init(&forigin);
-       origin = dns_fixedname_name(&forigin);
-
-       result = dns_rbtnodechain_next(chain, NULL, NULL);
-       while (result == ISC_R_SUCCESS || result == DNS_R_NEWORIGIN) {
-               node = NULL;
-               result = dns_rbtnodechain_current(chain, &prefix,
-                                                 origin, &node);
-               if (result != ISC_R_SUCCESS)
-                       break;
-               NODE_LOCK(&(rbtdb->node_locks[node->locknum].lock),
-                         isc_rwlocktype_read);
-               for (header = node->data;
-                    header != NULL;
-                    header = header->next) {
-                       if (header->serial <= search->serial &&
-                           !IGNORE(header) && EXISTS(header))
-                               break;
-               }
-               NODE_UNLOCK(&(rbtdb->node_locks[node->locknum].lock),
-                           isc_rwlocktype_read);
-               if (header != NULL)
-                       break;
-               result = dns_rbtnodechain_next(chain, NULL, NULL);
-       }
-       if (result == ISC_R_SUCCESS)
-               result = dns_name_concatenate(&prefix, origin, next, NULL);
-       if (result == ISC_R_SUCCESS && dns_name_issubdomain(next, name))
-               answer = ISC_TRUE;
-       return (answer);
+        dns_fixedname_t fnext;
+        dns_fixedname_t forigin;
+        dns_name_t *next;
+        dns_name_t *origin;
+        dns_name_t prefix;
+        dns_rbtdb_t *rbtdb;
+        dns_rbtnode_t *node;
+        isc_result_t result;
+        isc_boolean_t answer = ISC_FALSE;
+        rdatasetheader_t *header;
+
+        rbtdb = search->rbtdb;
+
+        dns_name_init(&prefix, NULL);
+        dns_fixedname_init(&fnext);
+        next = dns_fixedname_name(&fnext);
+        dns_fixedname_init(&forigin);
+        origin = dns_fixedname_name(&forigin);
+
+        result = dns_rbtnodechain_next(chain, NULL, NULL);
+        while (result == ISC_R_SUCCESS || result == DNS_R_NEWORIGIN) {
+                node = NULL;
+                result = dns_rbtnodechain_current(chain, &prefix,
+                                                  origin, &node);
+                if (result != ISC_R_SUCCESS)
+                        break;
+                NODE_LOCK(&(rbtdb->node_locks[node->locknum].lock),
+                          isc_rwlocktype_read);
+                for (header = node->data;
+                     header != NULL;
+                     header = header->next) {
+                        if (header->serial <= search->serial &&
+                            !IGNORE(header) && EXISTS(header))
+                                break;
+                }
+                NODE_UNLOCK(&(rbtdb->node_locks[node->locknum].lock),
+                            isc_rwlocktype_read);
+                if (header != NULL)
+                        break;
+                result = dns_rbtnodechain_next(chain, NULL, NULL);
+        }
+        if (result == ISC_R_SUCCESS)
+                result = dns_name_concatenate(&prefix, origin, next, NULL);
+        if (result == ISC_R_SUCCESS && dns_name_issubdomain(next, name))
+                answer = ISC_TRUE;
+        return (answer);
 }
 
 static inline isc_boolean_t
 activeemtpynode(rbtdb_search_t *search, dns_name_t *qname, dns_name_t *wname) {
-       dns_fixedname_t fnext;
-       dns_fixedname_t forigin;
-       dns_fixedname_t fprev;
-       dns_name_t *next;
-       dns_name_t *origin;
-       dns_name_t *prev;
-       dns_name_t name;
-       dns_name_t rname;
-       dns_name_t tname;
-       dns_rbtdb_t *rbtdb;
-       dns_rbtnode_t *node;
-       dns_rbtnodechain_t chain;
-       isc_boolean_t check_next = ISC_TRUE;
-       isc_boolean_t check_prev = ISC_TRUE;
-       isc_boolean_t answer = ISC_FALSE;
-       isc_result_t result;
-       rdatasetheader_t *header;
-       unsigned int n;
-
-       rbtdb = search->rbtdb;
-
-       dns_name_init(&name, NULL);
-       dns_name_init(&tname, NULL);
-       dns_name_init(&rname, NULL);
-       dns_fixedname_init(&fnext);
-       next = dns_fixedname_name(&fnext);
-       dns_fixedname_init(&fprev);
-       prev = dns_fixedname_name(&fprev);
-       dns_fixedname_init(&forigin);
-       origin = dns_fixedname_name(&forigin);
-
-       /*
-        * Find if qname is at or below a empty node.
-        * Use our own copy of the chain.
-        */
-
-       chain = search->chain;
-       do {
-               node = NULL;
-               result = dns_rbtnodechain_current(&chain, &name,
-                                                 origin, &node);
-               if (result != ISC_R_SUCCESS)
-                       break;
-               NODE_LOCK(&(rbtdb->node_locks[node->locknum].lock),
-                         isc_rwlocktype_read);
-               for (header = node->data;
-                    header != NULL;
-                    header = header->next) {
-                       if (header->serial <= search->serial &&
-                           !IGNORE(header) && EXISTS(header))
-                               break;
-               }
-               NODE_UNLOCK(&(rbtdb->node_locks[node->locknum].lock),
-                           isc_rwlocktype_read);
-               if (header != NULL)
-                       break;
-               result = dns_rbtnodechain_prev(&chain, NULL, NULL);
-       } while (result == ISC_R_SUCCESS || result == DNS_R_NEWORIGIN);
-       if (result == ISC_R_SUCCESS)
-               result = dns_name_concatenate(&name, origin, prev, NULL);
-       if (result != ISC_R_SUCCESS)
-               check_prev = ISC_FALSE;
-
-       result = dns_rbtnodechain_next(&chain, NULL, NULL);
-       while (result == ISC_R_SUCCESS || result == DNS_R_NEWORIGIN) {
-               node = NULL;
-               result = dns_rbtnodechain_current(&chain, &name,
-                                                 origin, &node);
-               if (result != ISC_R_SUCCESS)
-                       break;
-               NODE_LOCK(&(rbtdb->node_locks[node->locknum].lock),
-                         isc_rwlocktype_read);
-               for (header = node->data;
-                    header != NULL;
-                    header = header->next) {
-                       if (header->serial <= search->serial &&
-                           !IGNORE(header) && EXISTS(header))
-                               break;
-               }
-               NODE_UNLOCK(&(rbtdb->node_locks[node->locknum].lock),
-                           isc_rwlocktype_read);
-               if (header != NULL)
-                       break;
-               result = dns_rbtnodechain_next(&chain, NULL, NULL);
-       }
-       if (result == ISC_R_SUCCESS)
-               result = dns_name_concatenate(&name, origin, next, NULL);
-       if (result != ISC_R_SUCCESS)
-               check_next = ISC_FALSE;
-
-       dns_name_clone(qname, &rname);
-
-       /*
-        * Remove the wildcard label to find the terminal name.
-        */
-       n = dns_name_countlabels(wname);
-       dns_name_getlabelsequence(wname, 1, n - 1, &tname);
-
-       do {
-               if ((check_prev && dns_name_issubdomain(prev, &rname)) ||
-                   (check_next && dns_name_issubdomain(next, &rname))) {
-                       answer = ISC_TRUE;
-                       break;
-               }
-               /*
-                * Remove the left hand label.
-                */
-               n = dns_name_countlabels(&rname);
-               dns_name_getlabelsequence(&rname, 1, n - 1, &rname);
-       } while (!dns_name_equal(&rname, &tname));
-       return (answer);
+        dns_fixedname_t fnext;
+        dns_fixedname_t forigin;
+        dns_fixedname_t fprev;
+        dns_name_t *next;
+        dns_name_t *origin;
+        dns_name_t *prev;
+        dns_name_t name;
+        dns_name_t rname;
+        dns_name_t tname;
+        dns_rbtdb_t *rbtdb;
+        dns_rbtnode_t *node;
+        dns_rbtnodechain_t chain;
+        isc_boolean_t check_next = ISC_TRUE;
+        isc_boolean_t check_prev = ISC_TRUE;
+        isc_boolean_t answer = ISC_FALSE;
+        isc_result_t result;
+        rdatasetheader_t *header;
+        unsigned int n;
+
+        rbtdb = search->rbtdb;
+
+        dns_name_init(&name, NULL);
+        dns_name_init(&tname, NULL);
+        dns_name_init(&rname, NULL);
+        dns_fixedname_init(&fnext);
+        next = dns_fixedname_name(&fnext);
+        dns_fixedname_init(&fprev);
+        prev = dns_fixedname_name(&fprev);
+        dns_fixedname_init(&forigin);
+        origin = dns_fixedname_name(&forigin);
+
+        /*
+         * Find if qname is at or below a empty node.
+         * Use our own copy of the chain.
+         */
+
+        chain = search->chain;
+        do {
+                node = NULL;
+                result = dns_rbtnodechain_current(&chain, &name,
+                                                  origin, &node);
+                if (result != ISC_R_SUCCESS)
+                        break;
+                NODE_LOCK(&(rbtdb->node_locks[node->locknum].lock),
+                          isc_rwlocktype_read);
+                for (header = node->data;
+                     header != NULL;
+                     header = header->next) {
+                        if (header->serial <= search->serial &&
+                            !IGNORE(header) && EXISTS(header))
+                                break;
+                }
+                NODE_UNLOCK(&(rbtdb->node_locks[node->locknum].lock),
+                            isc_rwlocktype_read);
+                if (header != NULL)
+                        break;
+                result = dns_rbtnodechain_prev(&chain, NULL, NULL);
+        } while (result == ISC_R_SUCCESS || result == DNS_R_NEWORIGIN);
+        if (result == ISC_R_SUCCESS)
+                result = dns_name_concatenate(&name, origin, prev, NULL);
+        if (result != ISC_R_SUCCESS)
+                check_prev = ISC_FALSE;
+
+        result = dns_rbtnodechain_next(&chain, NULL, NULL);
+        while (result == ISC_R_SUCCESS || result == DNS_R_NEWORIGIN) {
+                node = NULL;
+                result = dns_rbtnodechain_current(&chain, &name,
+                                                  origin, &node);
+                if (result != ISC_R_SUCCESS)
+                        break;
+                NODE_LOCK(&(rbtdb->node_locks[node->locknum].lock),
+                          isc_rwlocktype_read);
+                for (header = node->data;
+                     header != NULL;
+                     header = header->next) {
+                        if (header->serial <= search->serial &&
+                            !IGNORE(header) && EXISTS(header))
+                                break;
+                }
+                NODE_UNLOCK(&(rbtdb->node_locks[node->locknum].lock),
+                            isc_rwlocktype_read);
+                if (header != NULL)
+                        break;
+                result = dns_rbtnodechain_next(&chain, NULL, NULL);
+        }
+        if (result == ISC_R_SUCCESS)
+                result = dns_name_concatenate(&name, origin, next, NULL);
+        if (result != ISC_R_SUCCESS)
+                check_next = ISC_FALSE;
+
+        dns_name_clone(qname, &rname);
+
+        /*
+         * Remove the wildcard label to find the terminal name.
+         */
+        n = dns_name_countlabels(wname);
+        dns_name_getlabelsequence(wname, 1, n - 1, &tname);
+
+        do {
+                if ((check_prev && dns_name_issubdomain(prev, &rname)) ||
+                    (check_next && dns_name_issubdomain(next, &rname))) {
+                        answer = ISC_TRUE;
+                        break;
+                }
+                /*
+                 * Remove the left hand label.
+                 */
+                n = dns_name_countlabels(&rname);
+                dns_name_getlabelsequence(&rname, 1, n - 1, &rname);
+        } while (!dns_name_equal(&rname, &tname));
+        return (answer);
 }
 
 static inline isc_result_t
 find_wildcard(rbtdb_search_t *search, dns_rbtnode_t **nodep,
-             dns_name_t *qname)
+              dns_name_t *qname)
 {
-       unsigned int i, j;
-       dns_rbtnode_t *node, *level_node, *wnode;
-       rdatasetheader_t *header;
-       isc_result_t result = ISC_R_NOTFOUND;
-       dns_name_t name;
-       dns_name_t *wname;
-       dns_fixedname_t fwname;
-       dns_rbtdb_t *rbtdb;
-       isc_boolean_t done, wild, active;
-       dns_rbtnodechain_t wchain;
-
-       /*
-        * Caller must be holding the tree lock and MUST NOT be holding
-        * any node locks.
-        */
-
-       /*
-        * Examine each ancestor level.  If the level's wild bit
-        * is set, then construct the corresponding wildcard name and
-        * search for it.  If the wildcard node exists, and is active in
-        * this version, we're done.  If not, then we next check to see
-        * if the ancestor is active in this version.  If so, then there
-        * can be no possible wildcard match and again we're done.  If not,
-        * continue the search.
-        */
-
-       rbtdb = search->rbtdb;
-       i = search->chain.level_matches;
-       done = ISC_FALSE;
-       node = *nodep;
-       do {
-               NODE_LOCK(&(rbtdb->node_locks[node->locknum].lock),
-                         isc_rwlocktype_read);
-
-               /*
-                * First we try to figure out if this node is active in
-                * the search's version.  We do this now, even though we
-                * may not need the information, because it simplifies the
-                * locking and code flow.
-                */
-               for (header = node->data;
-                    header != NULL;
-                    header = header->next) {
-                       if (header->serial <= search->serial &&
-                           !IGNORE(header) && EXISTS(header))
-                               break;
-               }
-               if (header != NULL)
-                       active = ISC_TRUE;
-               else
-                       active = ISC_FALSE;
-
-               if (node->wild)
-                       wild = ISC_TRUE;
-               else
-                       wild = ISC_FALSE;
-
-               NODE_UNLOCK(&(rbtdb->node_locks[node->locknum].lock),
-                           isc_rwlocktype_read);
-
-               if (wild) {
-                       /*
-                        * Construct the wildcard name for this level.
-                        */
-                       dns_name_init(&name, NULL);
-                       dns_rbt_namefromnode(node, &name);
-                       dns_fixedname_init(&fwname);
-                       wname = dns_fixedname_name(&fwname);
-                       result = dns_name_concatenate(dns_wildcardname, &name,
-                                                     wname, NULL);
-                       j = i;
-                       while (result == ISC_R_SUCCESS && j != 0) {
-                               j--;
-                               level_node = search->chain.levels[j];
-                               dns_name_init(&name, NULL);
-                               dns_rbt_namefromnode(level_node, &name);
-                               result = dns_name_concatenate(wname,
-                                                             &name,
-                                                             wname,
-                                                             NULL);
-                       }
-                       if (result != ISC_R_SUCCESS)
-                               break;
-
-                       wnode = NULL;
-                       dns_rbtnodechain_init(&wchain, NULL);
-                       result = dns_rbt_findnode(rbtdb->tree, wname,
-                                                 NULL, &wnode, &wchain,
-                                                 DNS_RBTFIND_EMPTYDATA,
-                                                 NULL, NULL);
-                       if (result == ISC_R_SUCCESS) {
-                               nodelock_t *lock;
-
-                               /*
-                                * We have found the wildcard node.  If it
-                                * is active in the search's version, we're
-                                * done.
-                                */
-                               lock = &rbtdb->node_locks[wnode->locknum].lock;
-                               NODE_LOCK(lock, isc_rwlocktype_read);
-                               for (header = wnode->data;
-                                    header != NULL;
-                                    header = header->next) {
-                                       if (header->serial <= search->serial &&
-                                           !IGNORE(header) && EXISTS(header))
-                                               break;
-                               }
-                               NODE_UNLOCK(lock, isc_rwlocktype_read);
-                               if (header != NULL ||
-                                   activeempty(search, &wchain, wname)) {
-                                       if (activeemtpynode(search, qname,
-                                                           wname)) {
-                                               return (ISC_R_NOTFOUND);
-                                       }
-                                       /*
-                                        * The wildcard node is active!
-                                        *
-                                        * Note: result is still ISC_R_SUCCESS
-                                        * so we don't have to set it.
-                                        */
-                                       *nodep = wnode;
-                                       break;
-                               }
-                       } else if (result != ISC_R_NOTFOUND &&
-                                  result != DNS_R_PARTIALMATCH) {
-                               /*
-                                * An error has occurred.  Bail out.
-                                */
-                               break;
-                       }
-               }
-
-               if (active) {
-                       /*
-                        * The level node is active.  Any wildcarding
-                        * present at higher levels has no
-                        * effect and we're done.
-                        */
-                       result = ISC_R_NOTFOUND;
-                       break;
-               }
-
-               if (i > 0) {
-                       i--;
-                       node = search->chain.levels[i];
-               } else
-                       done = ISC_TRUE;
-       } while (!done);
-
-       return (result);
+        unsigned int i, j;
+        dns_rbtnode_t *node, *level_node, *wnode;
+        rdatasetheader_t *header;
+        isc_result_t result = ISC_R_NOTFOUND;
+        dns_name_t name;
+        dns_name_t *wname;
+        dns_fixedname_t fwname;
+        dns_rbtdb_t *rbtdb;
+        isc_boolean_t done, wild, active;
+        dns_rbtnodechain_t wchain;
+
+        /*
+         * Caller must be holding the tree lock and MUST NOT be holding
+         * any node locks.
+         */
+
+        /*
+         * Examine each ancestor level.  If the level's wild bit
+         * is set, then construct the corresponding wildcard name and
+         * search for it.  If the wildcard node exists, and is active in
+         * this version, we're done.  If not, then we next check to see
+         * if the ancestor is active in this version.  If so, then there
+         * can be no possible wildcard match and again we're done.  If not,
+         * continue the search.
+         */
+
+        rbtdb = search->rbtdb;
+        i = search->chain.level_matches;
+        done = ISC_FALSE;
+        node = *nodep;
+        do {
+                NODE_LOCK(&(rbtdb->node_locks[node->locknum].lock),
+                          isc_rwlocktype_read);
+
+                /*
+                 * First we try to figure out if this node is active in
+                 * the search's version.  We do this now, even though we
+                 * may not need the information, because it simplifies the
+                 * locking and code flow.
+                 */
+                for (header = node->data;
+                     header != NULL;
+                     header = header->next) {
+                        if (header->serial <= search->serial &&
+                            !IGNORE(header) && EXISTS(header))
+                                break;
+                }
+                if (header != NULL)
+                        active = ISC_TRUE;
+                else
+                        active = ISC_FALSE;
+
+                if (node->wild)
+                        wild = ISC_TRUE;
+                else
+                        wild = ISC_FALSE;
+
+                NODE_UNLOCK(&(rbtdb->node_locks[node->locknum].lock),
+                            isc_rwlocktype_read);
+
+                if (wild) {
+                        /*
+                         * Construct the wildcard name for this level.
+                         */
+                        dns_name_init(&name, NULL);
+                        dns_rbt_namefromnode(node, &name);
+                        dns_fixedname_init(&fwname);
+                        wname = dns_fixedname_name(&fwname);
+                        result = dns_name_concatenate(dns_wildcardname, &name,
+                                                      wname, NULL);
+                        j = i;
+                        while (result == ISC_R_SUCCESS && j != 0) {
+                                j--;
+                                level_node = search->chain.levels[j];
+                                dns_name_init(&name, NULL);
+                                dns_rbt_namefromnode(level_node, &name);
+                                result = dns_name_concatenate(wname,
+                                                              &name,
+                                                              wname,
+                                                              NULL);
+                        }
+                        if (result != ISC_R_SUCCESS)
+                                break;
+
+                        wnode = NULL;
+                        dns_rbtnodechain_init(&wchain, NULL);
+                        result = dns_rbt_findnode(rbtdb->tree, wname,
+                                                  NULL, &wnode, &wchain,
+                                                  DNS_RBTFIND_EMPTYDATA,
+                                                  NULL, NULL);
+                        if (result == ISC_R_SUCCESS) {
+                                nodelock_t *lock;
+
+                                /*
+                                 * We have found the wildcard node.  If it
+                                 * is active in the search's version, we're
+                                 * done.
+                                 */
+                                lock = &rbtdb->node_locks[wnode->locknum].lock;
+                                NODE_LOCK(lock, isc_rwlocktype_read);
+                                for (header = wnode->data;
+                                     header != NULL;
+                                     header = header->next) {
+                                        if (header->serial <= search->serial &&
+                                            !IGNORE(header) && EXISTS(header))
+                                                break;
+                                }
+                                NODE_UNLOCK(lock, isc_rwlocktype_read);
+                                if (header != NULL ||
+                                    activeempty(search, &wchain, wname)) {
+                                        if (activeemtpynode(search, qname,
+                                                            wname)) {
+                                                return (ISC_R_NOTFOUND);
+                                        }
+                                        /*
+                                         * The wildcard node is active!
+                                         *
+                                         * Note: result is still ISC_R_SUCCESS
+                                         * so we don't have to set it.
+                                         */
+                                        *nodep = wnode;
+                                        break;
+                                }
+                        } else if (result != ISC_R_NOTFOUND &&
+                                   result != DNS_R_PARTIALMATCH) {
+                                /*
+                                 * An error has occurred.  Bail out.
+                                 */
+                                break;
+                        }
+                }
+
+                if (active) {
+                        /*
+                         * The level node is active.  Any wildcarding
+                         * present at higher levels has no
+                         * effect and we're done.
+                         */
+                        result = ISC_R_NOTFOUND;
+                        break;
+                }
+
+                if (i > 0) {
+                        i--;
+                        node = search->chain.levels[i];
+                } else
+                        done = ISC_TRUE;
+        } while (!done);
+
+        return (result);
 }
 
 static inline isc_result_t
 find_closest_nsec(rbtdb_search_t *search, dns_dbnode_t **nodep,
-                 dns_name_t *foundname, dns_rdataset_t *rdataset,
-                 dns_rdataset_t *sigrdataset, isc_boolean_t need_sig)
+                  dns_name_t *foundname, dns_rdataset_t *rdataset,
+                  dns_rdataset_t *sigrdataset, isc_boolean_t need_sig)
 {
-       dns_rbtnode_t *node;
-       rdatasetheader_t *header, *header_next, *found, *foundsig;
-       isc_boolean_t empty_node;
-       isc_result_t result;
-       dns_fixedname_t fname, forigin;
-       dns_name_t *name, *origin;
-
-       do {
-               node = NULL;
-               dns_fixedname_init(&fname);
-               name = dns_fixedname_name(&fname);
-               dns_fixedname_init(&forigin);
-               origin = dns_fixedname_name(&forigin);
-               result = dns_rbtnodechain_current(&search->chain, name,
-                                                 origin, &node);
-               if (result != ISC_R_SUCCESS)
-                       return (result);
-               NODE_LOCK(&(search->rbtdb->node_locks[node->locknum].lock),
-                         isc_rwlocktype_read);
-               found = NULL;
-               foundsig = NULL;
-               empty_node = ISC_TRUE;
-               for (header = node->data;
-                    header != NULL;
-                    header = header_next) {
-                       header_next = header->next;
-                       /*
-                        * Look for an active, extant NSEC or RRSIG NSEC.
-                        */
-                       do {
-                               if (header->serial <= search->serial &&
-                                   !IGNORE(header)) {
-                                       /*
-                                        * Is this a "this rdataset doesn't
-                                        * exist" record?
-                                        */
-                                       if (NONEXISTENT(header))
-                                               header = NULL;
-                                       break;
-                               } else
-                                       header = header->down;
-                       } while (header != NULL);
-                       if (header != NULL) {
-                               /*
-                                * We now know that there is at least one
-                                * active rdataset at this node.
-                                */
-                               empty_node = ISC_FALSE;
-                               if (header->type == dns_rdatatype_nsec) {
-                                       found = header;
-                                       if (foundsig != NULL)
-                                               break;
-                               } else if (header->type ==
-                                          RBTDB_RDATATYPE_SIGNSEC) {
-                                       foundsig = header;
-                                       if (found != NULL)
-                                               break;
-                               }
-                       }
-               }
-               if (!empty_node) {
-                       if (found != NULL &&
-                           (foundsig != NULL || !need_sig))
-                       {
-                               /*
-                                * We've found the right NSEC record.
-                                *
-                                * Note: for this to really be the right
-                                * NSEC record, it's essential that the NSEC
-                                * records of any nodes obscured by a zone
-                                * cut have been removed; we assume this is
-                                * the case.
-                                */
-                               result = dns_name_concatenate(name, origin,
-                                                             foundname, NULL);
-                               if (result == ISC_R_SUCCESS) {
-                                       if (nodep != NULL) {
-                                               new_reference(search->rbtdb,
-                                                             node);
-                                               *nodep = node;
-                                       }
-                                       bind_rdataset(search->rbtdb, node,
-                                                     found, search->now,
-                                                     rdataset);
-                                       if (foundsig != NULL)
-                                               bind_rdataset(search->rbtdb,
-                                                             node,
-                                                             foundsig,
-                                                             search->now,
-                                                             sigrdataset);
-                               }
-                       } else if (found == NULL && foundsig == NULL) {
-                               /*
-                                * This node is active, but has no NSEC or
-                                * RRSIG NSEC.  That means it's glue or
-                                * other obscured zone data that isn't
-                                * relevant for our search.  Treat the
-                                * node as if it were empty and keep looking.
-                                */
-                               empty_node = ISC_TRUE;
-                               result = dns_rbtnodechain_prev(&search->chain,
-                                                              NULL, NULL);
-                       } else {
-                               /*
-                                * We found an active node, but either the
-                                * NSEC or the RRSIG NSEC is missing.  This
-                                * shouldn't happen.
-                                */
-                               result = DNS_R_BADDB;
-                       }
-               } else {
-                       /*
-                        * This node isn't active.  We've got to keep
-                        * looking.
-                        */
-                       result = dns_rbtnodechain_prev(&search->chain, NULL,
-                                                      NULL);
-               }
-               NODE_UNLOCK(&(search->rbtdb->node_locks[node->locknum].lock),
-                           isc_rwlocktype_read);
-       } while (empty_node && result == ISC_R_SUCCESS);
-
-       /*
-        * If the result is ISC_R_NOMORE, then we got to the beginning of
-        * the database and didn't find a NSEC record.  This shouldn't
-        * happen.
-        */
-       if (result == ISC_R_NOMORE)
-               result = DNS_R_BADDB;
-
-       return (result);
+        dns_rbtnode_t *node;
+        rdatasetheader_t *header, *header_next, *found, *foundsig;
+        isc_boolean_t empty_node;
+        isc_result_t result;
+        dns_fixedname_t fname, forigin;
+        dns_name_t *name, *origin;
+
+        do {
+                node = NULL;
+                dns_fixedname_init(&fname);
+                name = dns_fixedname_name(&fname);
+                dns_fixedname_init(&forigin);
+                origin = dns_fixedname_name(&forigin);
+                result = dns_rbtnodechain_current(&search->chain, name,
+                                                  origin, &node);
+                if (result != ISC_R_SUCCESS)
+                        return (result);
+                NODE_LOCK(&(search->rbtdb->node_locks[node->locknum].lock),
+                          isc_rwlocktype_read);
+                found = NULL;
+                foundsig = NULL;
+                empty_node = ISC_TRUE;
+                for (header = node->data;
+                     header != NULL;
+                     header = header_next) {
+                        header_next = header->next;
+                        /*
+                         * Look for an active, extant NSEC or RRSIG NSEC.
+                         */
+                        do {
+                                if (header->serial <= search->serial &&
+                                    !IGNORE(header)) {
+                                        /*
+                                         * Is this a "this rdataset doesn't
+                                         * exist" record?
+                                         */
+                                        if (NONEXISTENT(header))
+                                                header = NULL;
+                                        break;
+                                } else
+                                        header = header->down;
+                        } while (header != NULL);
+                        if (header != NULL) {
+                                /*
+                                 * We now know that there is at least one
+                                 * active rdataset at this node.
+                                 */
+                                empty_node = ISC_FALSE;
+                                if (header->type == dns_rdatatype_nsec) {
+                                        found = header;
+                                        if (foundsig != NULL)
+                                                break;
+                                } else if (header->type ==
+                                           RBTDB_RDATATYPE_SIGNSEC) {
+                                        foundsig = header;
+                                        if (found != NULL)
+                                                break;
+                                }
+                        }
+                }
+                if (!empty_node) {
+                        if (found != NULL &&
+                            (foundsig != NULL || !need_sig))
+                        {
+                                /*
+                                 * We've found the right NSEC record.
+                                 *
+                                 * Note: for this to really be the right
+                                 * NSEC record, it's essential that the NSEC
+                                 * records of any nodes obscured by a zone
+                                 * cut have been removed; we assume this is
+                                 * the case.
+                                 */
+                                result = dns_name_concatenate(name, origin,
+                                                              foundname, NULL);
+                                if (result == ISC_R_SUCCESS) {
+                                        if (nodep != NULL) {
+                                                new_reference(search->rbtdb,
+                                                              node);
+                                                *nodep = node;
+                                        }
+                                        bind_rdataset(search->rbtdb, node,
+                                                      found, search->now,
+                                                      rdataset);
+                                        if (foundsig != NULL)
+                                                bind_rdataset(search->rbtdb,
+                                                              node,
+                                                              foundsig,
+                                                              search->now,
+                                                              sigrdataset);
+                                }
+                        } else if (found == NULL && foundsig == NULL) {
+                                /*
+                                 * This node is active, but has no NSEC or
+                                 * RRSIG NSEC.  That means it's glue or
+                                 * other obscured zone data that isn't
+                                 * relevant for our search.  Treat the
+                                 * node as if it were empty and keep looking.
+                                 */
+                                empty_node = ISC_TRUE;
+                                result = dns_rbtnodechain_prev(&search->chain,
+                                                               NULL, NULL);
+                        } else {
+                                /*
+                                 * We found an active node, but either the
+                                 * NSEC or the RRSIG NSEC is missing.  This
+                                 * shouldn't happen.
+                                 */
+                                result = DNS_R_BADDB;
+                        }
+                } else {
+                        /*
+                         * This node isn't active.  We've got to keep
+                         * looking.
+                         */
+                        result = dns_rbtnodechain_prev(&search->chain, NULL,
+                                                       NULL);
+                }
+                NODE_UNLOCK(&(search->rbtdb->node_locks[node->locknum].lock),
+                            isc_rwlocktype_read);
+        } while (empty_node && result == ISC_R_SUCCESS);
+
+        /*
+         * If the result is ISC_R_NOMORE, then we got to the beginning of
+         * the database and didn't find a NSEC record.  This shouldn't
+         * happen.
+         */
+        if (result == ISC_R_NOMORE)
+                result = DNS_R_BADDB;
+
+        return (result);
 }
 
 static isc_result_t
 zone_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
-         dns_rdatatype_t type, unsigned int options, isc_stdtime_t now,
-         dns_dbnode_t **nodep, dns_name_t *foundname,
-         dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
+          dns_rdatatype_t type, unsigned int options, isc_stdtime_t now,
+          dns_dbnode_t **nodep, dns_name_t *foundname,
+          dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
 {
-       dns_rbtnode_t *node = NULL;
-       isc_result_t result;
-       rbtdb_search_t search;
-       isc_boolean_t cname_ok = ISC_TRUE;
-       isc_boolean_t close_version = ISC_FALSE;
-       isc_boolean_t maybe_zonecut = ISC_FALSE;
-       isc_boolean_t at_zonecut = ISC_FALSE;
-       isc_boolean_t wild;
-       isc_boolean_t empty_node;
-       rdatasetheader_t *header, *header_next, *found, *nsecheader;
-       rdatasetheader_t *foundsig, *cnamesig, *nsecsig;
-       rbtdb_rdatatype_t sigtype;
-       isc_boolean_t active;
-       dns_rbtnodechain_t chain;
-       nodelock_t *lock;
-
-
-       search.rbtdb = (dns_rbtdb_t *)db;
-
-       REQUIRE(VALID_RBTDB(search.rbtdb));
-
-       /*
-        * We don't care about 'now'.
-        */
-       UNUSED(now);
-
-       /*
-        * If the caller didn't supply a version, attach to the current
-        * version.
-        */
-       if (version == NULL) {
-               currentversion(db, &version);
-               close_version = ISC_TRUE;
-       }
-
-       search.rbtversion = version;
-       search.serial = search.rbtversion->serial;
-       search.options = options;
-       search.copy_name = ISC_FALSE;
-       search.need_cleanup = ISC_FALSE;
-       search.wild = ISC_FALSE;
-       search.zonecut = NULL;
-       dns_fixedname_init(&search.zonecut_name);
-       dns_rbtnodechain_init(&search.chain, search.rbtdb->common.mctx);
-       search.now = 0;
-
-       /*
-        * 'wild' will be true iff. we've matched a wildcard.
-        */
-       wild = ISC_FALSE;
-
-       RWLOCK(&search.rbtdb->tree_lock, isc_rwlocktype_read);
-
-       /*
-        * Search down from the root of the tree.  If, while going down, we
-        * encounter a callback node, zone_zonecut_callback() will search the
-        * rdatasets at the zone cut for active DNAME or NS rdatasets.
-        */
-       result = dns_rbt_findnode(search.rbtdb->tree, name, foundname, &node,
-                                 &search.chain, DNS_RBTFIND_EMPTYDATA,
-                                 zone_zonecut_callback, &search);
-
-       if (result == DNS_R_PARTIALMATCH) {
-       partial_match:
-               if (search.zonecut != NULL) {
-                   result = setup_delegation(&search, nodep, foundname,
-                                             rdataset, sigrdataset);
-                   goto tree_exit;
-               }
-
-               if (search.wild) {
-                       /*
-                        * At least one of the levels in the search chain
-                        * potentially has a wildcard.  For each such level,
-                        * we must see if there's a matching wildcard active
-                        * in the current version.
-                        */
-                       result = find_wildcard(&search, &node, name);
-                       if (result == ISC_R_SUCCESS) {
-                               result = dns_name_copy(name, foundname, NULL);
-                               if (result != ISC_R_SUCCESS)
-                                       goto tree_exit;
-                               wild = ISC_TRUE;
-                               goto found;
-                       }
-                       else if (result != ISC_R_NOTFOUND)
-                               goto tree_exit;
-               }
-
-               chain = search.chain;
-               active = activeempty(&search, &chain, name);
-
-               /*
-                * If we're here, then the name does not exist, is not
-                * beneath a zonecut, and there's no matching wildcard.
-                */
-               if (search.rbtdb->secure ||
-                   (search.options & DNS_DBFIND_FORCENSEC) != 0)
-               {
-                       result = find_closest_nsec(&search, nodep, foundname,
-                                                 rdataset, sigrdataset,
-                                                 search.rbtdb->secure);
-                       if (result == ISC_R_SUCCESS)
-                               result = active ? DNS_R_EMPTYNAME :
-                                                 DNS_R_NXDOMAIN;
-               } else
-                       result = active ? DNS_R_EMPTYNAME : DNS_R_NXDOMAIN;
-               goto tree_exit;
-       } else if (result != ISC_R_SUCCESS)
-               goto tree_exit;
+        dns_rbtnode_t *node = NULL;
+        isc_result_t result;
+        rbtdb_search_t search;
+        isc_boolean_t cname_ok = ISC_TRUE;
+        isc_boolean_t close_version = ISC_FALSE;
+        isc_boolean_t maybe_zonecut = ISC_FALSE;
+        isc_boolean_t at_zonecut = ISC_FALSE;
+        isc_boolean_t wild;
+        isc_boolean_t empty_node;
+        rdatasetheader_t *header, *header_next, *found, *nsecheader;
+        rdatasetheader_t *foundsig, *cnamesig, *nsecsig;
+        rbtdb_rdatatype_t sigtype;
+        isc_boolean_t active;
+        dns_rbtnodechain_t chain;
+        nodelock_t *lock;
+
+
+        search.rbtdb = (dns_rbtdb_t *)db;
+
+        REQUIRE(VALID_RBTDB(search.rbtdb));
+
+        /*
+         * We don't care about 'now'.
+         */
+        UNUSED(now);
+
+        /*
+         * If the caller didn't supply a version, attach to the current
+         * version.
+         */
+        if (version == NULL) {
+                currentversion(db, &version);
+                close_version = ISC_TRUE;
+        }
+
+        search.rbtversion = version;
+        search.serial = search.rbtversion->serial;
+        search.options = options;
+        search.copy_name = ISC_FALSE;
+        search.need_cleanup = ISC_FALSE;
+        search.wild = ISC_FALSE;
+        search.zonecut = NULL;
+        dns_fixedname_init(&search.zonecut_name);
+        dns_rbtnodechain_init(&search.chain, search.rbtdb->common.mctx);
+        search.now = 0;
+
+        /*
+         * 'wild' will be true iff. we've matched a wildcard.
+         */
+        wild = ISC_FALSE;
+
+        RWLOCK(&search.rbtdb->tree_lock, isc_rwlocktype_read);
+
+        /*
+         * Search down from the root of the tree.  If, while going down, we
+         * encounter a callback node, zone_zonecut_callback() will search the
+         * rdatasets at the zone cut for active DNAME or NS rdatasets.
+         */
+        result = dns_rbt_findnode(search.rbtdb->tree, name, foundname, &node,
+                                  &search.chain, DNS_RBTFIND_EMPTYDATA,
+                                  zone_zonecut_callback, &search);
+
+        if (result == DNS_R_PARTIALMATCH) {
+        partial_match:
+                if (search.zonecut != NULL) {
+                    result = setup_delegation(&search, nodep, foundname,
+                                              rdataset, sigrdataset);
+                    goto tree_exit;
+                }
+
+                if (search.wild) {
+                        /*
+                         * At least one of the levels in the search chain
+                         * potentially has a wildcard.  For each such level,
+                         * we must see if there's a matching wildcard active
+                         * in the current version.
+                         */
+                        result = find_wildcard(&search, &node, name);
+                        if (result == ISC_R_SUCCESS) {
+                                result = dns_name_copy(name, foundname, NULL);
+                                if (result != ISC_R_SUCCESS)
+                                        goto tree_exit;
+                                wild = ISC_TRUE;
+                                goto found;
+                        }
+                        else if (result != ISC_R_NOTFOUND)
+                                goto tree_exit;
+                }
+
+                chain = search.chain;
+                active = activeempty(&search, &chain, name);
+
+                /*
+                 * If we're here, then the name does not exist, is not
+                 * beneath a zonecut, and there's no matching wildcard.
+                 */
+                if (search.rbtdb->secure ||
+                    (search.options & DNS_DBFIND_FORCENSEC) != 0)
+                {
+                        result = find_closest_nsec(&search, nodep, foundname,
+                                                  rdataset, sigrdataset,
+                                                  search.rbtdb->secure);
+                        if (result == ISC_R_SUCCESS)
+                                result = active ? DNS_R_EMPTYNAME :
+                                                  DNS_R_NXDOMAIN;
+                } else
+                        result = active ? DNS_R_EMPTYNAME : DNS_R_NXDOMAIN;
+                goto tree_exit;
+        } else if (result != ISC_R_SUCCESS)
+                goto tree_exit;
 
  found:
-       /*
-        * We have found a node whose name is the desired name, or we
-        * have matched a wildcard.
-        */
-
-       if (search.zonecut != NULL) {
-               /*
-                * If we're beneath a zone cut, we don't want to look for
-                * CNAMEs because they're not legitimate zone glue.
-                */
-               cname_ok = ISC_FALSE;
-       } else {
-               /*
-                * The node may be a zone cut itself.  If it might be one,
-                * make sure we check for it later.
-                */
-               if (node->find_callback &&
-                   (node != search.rbtdb->origin_node ||
-                    IS_STUB(search.rbtdb)) &&
-                   !dns_rdatatype_atparent(type))
-                       maybe_zonecut = ISC_TRUE;
-       }
-
-       /*
-        * Certain DNSSEC types are not subject to CNAME matching
-        * (RFC4035, section 2.5 and RFC3007).
-        *
-        * We don't check for RRSIG, because we don't store RRSIG records
-        * directly.
-        */
-       if (type == dns_rdatatype_key || type == dns_rdatatype_nsec)
-               cname_ok = ISC_FALSE;
-
-       /*
-        * We now go looking for rdata...
-        */
-
-       NODE_LOCK(&(search.rbtdb->node_locks[node->locknum].lock),
-                 isc_rwlocktype_read);
-
-       found = NULL;
-       foundsig = NULL;
-       sigtype = RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, type);
-       nsecheader = NULL;
-       nsecsig = NULL;
-       cnamesig = NULL;
-       empty_node = ISC_TRUE;
-       for (header = node->data; header != NULL; header = header_next) {
-               header_next = header->next;
-               /*
-                * Look for an active, extant rdataset.
-                */
-               do {
-                       if (header->serial <= search.serial &&
-                           !IGNORE(header)) {
-                               /*
-                                * Is this a "this rdataset doesn't
-                                * exist" record?
-                                */
-                               if (NONEXISTENT(header))
-                                       header = NULL;
-                               break;
-                       } else
-                               header = header->down;
-               } while (header != NULL);
-               if (header != NULL) {
-                       /*
-                        * We now know that there is at least one active
-                        * rdataset at this node.
-                        */
-                       empty_node = ISC_FALSE;
-
-                       /*
-                        * Do special zone cut handling, if requested.
-                        */
-                       if (maybe_zonecut &&
-                           header->type == dns_rdatatype_ns) {
-                               /*
-                                * We increment the reference count on node to
-                                * ensure that search->zonecut_rdataset will
-                                * still be valid later.
-                                */
-                               new_reference(search.rbtdb, node);
-                               search.zonecut = node;
-                               search.zonecut_rdataset = header;
-                               search.zonecut_sigrdataset = NULL;
-                               search.need_cleanup = ISC_TRUE;
-                               maybe_zonecut = ISC_FALSE;
-                               at_zonecut = ISC_TRUE;
-                               /*
-                                * It is not clear if KEY should still be
-                                * allowed at the parent side of the zone
-                                * cut or not.  It is needed for RFC3007
-                                * validated updates.
-                                */
-                               if ((search.options & DNS_DBFIND_GLUEOK) == 0
-                                   && type != dns_rdatatype_nsec
-                                   && type != dns_rdatatype_key) {
-                                       /*
-                                        * Glue is not OK, but any answer we
-                                        * could return would be glue.  Return
-                                        * the delegation.
-                                        */
-                                       found = NULL;
-                                       break;
-                               }
-                               if (found != NULL && foundsig != NULL)
-                                       break;
-                       }
-
-                       /*
-                        * If we found a type we were looking for,
-                        * remember it.
-                        */
-                       if (header->type == type ||
-                           type == dns_rdatatype_any ||
-                           (header->type == dns_rdatatype_cname &&
-                            cname_ok)) {
-                               /*
-                                * We've found the answer!
-                                */
-                               found = header;
-                               if (header->type == dns_rdatatype_cname &&
-                                   cname_ok) {
-                                       /*
-                                        * We may be finding a CNAME instead
-                                        * of the desired type.
-                                        *
-                                        * If we've already got the CNAME RRSIG,
-                                        * use it, otherwise change sigtype
-                                        * so that we find it.
-                                        */
-                                       if (cnamesig != NULL)
-                                               foundsig = cnamesig;
-                                       else
-                                               sigtype =
-                                                   RBTDB_RDATATYPE_SIGCNAME;
-                               }
-                               /*
-                                * If we've got all we need, end the search.
-                                */
-                               if (!maybe_zonecut && foundsig != NULL)
-                                       break;
-                       } else if (header->type == sigtype) {
-                               /*
-                                * We've found the RRSIG rdataset for our
-                                * target type.  Remember it.
-                                */
-                               foundsig = header;
-                               /*
-                                * If we've got all we need, end the search.
-                                */
-                               if (!maybe_zonecut && found != NULL)
-                                       break;
-                       } else if (header->type == dns_rdatatype_nsec) {
-                               /*
-                                * Remember a NSEC rdataset even if we're
-                                * not specifically looking for it, because
-                                * we might need it later.
-                                */
-                               nsecheader = header;
-                       } else if (header->type == RBTDB_RDATATYPE_SIGNSEC) {
-                               /*
-                                * If we need the NSEC rdataset, we'll also
-                                * need its signature.
-                                */
-                               nsecsig = header;
-                       } else if (cname_ok &&
-                                  header->type == RBTDB_RDATATYPE_SIGCNAME) {
-                               /*
-                                * If we get a CNAME match, we'll also need
-                                * its signature.
-                                */
-                               cnamesig = header;
-                       }
-               }
-       }
-
-       if (empty_node) {
-               /*
-                * We have an exact match for the name, but there are no
-                * active rdatasets in the desired version.  That means that
-                * this node doesn't exist in the desired version, and that
-                * we really have a partial match.
-                */
-               if (!wild) {
-                       lock = &search.rbtdb->node_locks[node->locknum].lock;
-                       NODE_UNLOCK(lock, isc_rwlocktype_read);
-                       goto partial_match;
-               }
-       }
-
-       /*
-        * If we didn't find what we were looking for...
-        */
-       if (found == NULL) {
-               if (search.zonecut != NULL) {
-                       /*
-                        * We were trying to find glue at a node beneath a
-                        * zone cut, but didn't.
-                        *
-                        * Return the delegation.
-                        */
-                       lock = &search.rbtdb->node_locks[node->locknum].lock;
-                       NODE_UNLOCK(lock, isc_rwlocktype_read);
-                       result = setup_delegation(&search, nodep, foundname,
-                                                 rdataset, sigrdataset);
-                       goto tree_exit;
-               }
-               /*
-                * The desired type doesn't exist.
-                */
-               result = DNS_R_NXRRSET;
-               if (search.rbtdb->secure &&
-                   (nsecheader == NULL || nsecsig == NULL)) {
-                       /*
-                        * The zone is secure but there's no NSEC,
-                        * or the NSEC has no signature!
-                        */
-                       if (!wild) {
-                               result = DNS_R_BADDB;
-                               goto node_exit;
-                       }
-
-                       lock = &search.rbtdb->node_locks[node->locknum].lock;
-                       NODE_UNLOCK(lock, isc_rwlocktype_read);
-                       result = find_closest_nsec(&search, nodep, foundname,
-                                                  rdataset, sigrdataset,
-                                                  search.rbtdb->secure);
-                       if (result == ISC_R_SUCCESS)
-                               result = DNS_R_EMPTYWILD;
-                       goto tree_exit;
-               }
-               if ((search.options & DNS_DBFIND_FORCENSEC) != 0 &&
-                   nsecheader == NULL)
-               {
-                       /*
-                        * There's no NSEC record, and we were told
-                        * to find one.
-                        */
-                       result = DNS_R_BADDB;
-                       goto node_exit;
-               }
-               if (nodep != NULL) {
-                       new_reference(search.rbtdb, node);
-                       *nodep = node;
-               }
-               if (search.rbtdb->secure ||
-                   (search.options & DNS_DBFIND_FORCENSEC) != 0)
-               {
-                       bind_rdataset(search.rbtdb, node, nsecheader,
-                                     0, rdataset);
-                       if (nsecsig != NULL)
-                               bind_rdataset(search.rbtdb, node,
-                                             nsecsig, 0, sigrdataset);
-               }
-               if (wild)
-                       foundname->attributes |= DNS_NAMEATTR_WILDCARD;
-               goto node_exit;
-       }
-
-       /*
-        * We found what we were looking for, or we found a CNAME.
-        */
-
-       if (type != found->type &&
-           type != dns_rdatatype_any &&
-           found->type == dns_rdatatype_cname) {
-               /*
-                * We weren't doing an ANY query and we found a CNAME instead
-                * of the type we were looking for, so we need to indicate
-                * that result to the caller.
-                */
-               result = DNS_R_CNAME;
-       } else if (search.zonecut != NULL) {
-               /*
-                * If we're beneath a zone cut, we must indicate that the
-                * result is glue, unless we're actually at the zone cut
-                * and the type is NSEC or KEY.
-                */
-               if (search.zonecut == node) {
-                       /*
-                        * It is not clear if KEY should still be
-                        * allowed at the parent side of the zone
-                        * cut or not.  It is needed for RFC3007
-                        * validated updates.
-                        */
-                       if (type == dns_rdatatype_nsec ||
-                           type == dns_rdatatype_key)
-                               result = ISC_R_SUCCESS;
-                       else if (type == dns_rdatatype_any)
-                               result = DNS_R_ZONECUT;
-                       else
-                               result = DNS_R_GLUE;
-               } else
-                       result = DNS_R_GLUE;
-               /*
-                * We might have found data that isn't glue, but was occluded
-                * by a dynamic update.  If the caller cares about this, they
-                * will have told us to validate glue.
-                *
-                * XXX We should cache the glue validity state!
-                */
-               if (result == DNS_R_GLUE &&
-                   (search.options & DNS_DBFIND_VALIDATEGLUE) != 0 &&
-                   !valid_glue(&search, foundname, type, node)) {
-                       lock = &search.rbtdb->node_locks[node->locknum].lock;
-                       NODE_UNLOCK(lock, isc_rwlocktype_read);
-                       result = setup_delegation(&search, nodep, foundname,
-                                                 rdataset, sigrdataset);
-                   goto tree_exit;
-               }
-       } else {
-               /*
-                * An ordinary successful query!
-                */
-               result = ISC_R_SUCCESS;
-       }
-
-       if (nodep != NULL) {
-               if (!at_zonecut)
-                       new_reference(search.rbtdb, node);
-               else
-                       search.need_cleanup = ISC_FALSE;
-               *nodep = node;
-       }
-
-       if (type != dns_rdatatype_any) {
-               bind_rdataset(search.rbtdb, node, found, 0, rdataset);
-               if (foundsig != NULL)
-                       bind_rdataset(search.rbtdb, node, foundsig, 0,
-                                     sigrdataset);
-       }
-
-       if (wild)
-               foundname->attributes |= DNS_NAMEATTR_WILDCARD;
+        /*
+         * We have found a node whose name is the desired name, or we
+         * have matched a wildcard.
+         */
+
+        if (search.zonecut != NULL) {
+                /*
+                 * If we're beneath a zone cut, we don't want to look for
+                 * CNAMEs because they're not legitimate zone glue.
+                 */
+                cname_ok = ISC_FALSE;
+        } else {
+                /*
+                 * The node may be a zone cut itself.  If it might be one,
+                 * make sure we check for it later.
+                 */
+                if (node->find_callback &&
+                    (node != search.rbtdb->origin_node ||
+                     IS_STUB(search.rbtdb)) &&
+                    !dns_rdatatype_atparent(type))
+                        maybe_zonecut = ISC_TRUE;
+        }
+
+        /*
+         * Certain DNSSEC types are not subject to CNAME matching
+         * (RFC4035, section 2.5 and RFC3007).
+         *
+         * We don't check for RRSIG, because we don't store RRSIG records
+         * directly.
+         */
+        if (type == dns_rdatatype_key || type == dns_rdatatype_nsec)
+                cname_ok = ISC_FALSE;
+
+        /*
+         * We now go looking for rdata...
+         */
+
+        NODE_LOCK(&(search.rbtdb->node_locks[node->locknum].lock),
+                  isc_rwlocktype_read);
+
+        found = NULL;
+        foundsig = NULL;
+        sigtype = RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, type);
+        nsecheader = NULL;
+        nsecsig = NULL;
+        cnamesig = NULL;
+        empty_node = ISC_TRUE;
+        for (header = node->data; header != NULL; header = header_next) {
+                header_next = header->next;
+                /*
+                 * Look for an active, extant rdataset.
+                 */
+                do {
+                        if (header->serial <= search.serial &&
+                            !IGNORE(header)) {
+                                /*
+                                 * Is this a "this rdataset doesn't
+                                 * exist" record?
+                                 */
+                                if (NONEXISTENT(header))
+                                        header = NULL;
+                                break;
+                        } else
+                                header = header->down;
+                } while (header != NULL);
+                if (header != NULL) {
+                        /*
+                         * We now know that there is at least one active
+                         * rdataset at this node.
+                         */
+                        empty_node = ISC_FALSE;
+
+                        /*
+                         * Do special zone cut handling, if requested.
+                         */
+                        if (maybe_zonecut &&
+                            header->type == dns_rdatatype_ns) {
+                                /*
+                                 * We increment the reference count on node to
+                                 * ensure that search->zonecut_rdataset will
+                                 * still be valid later.
+                                 */
+                                new_reference(search.rbtdb, node);
+                                search.zonecut = node;
+                                search.zonecut_rdataset = header;
+                                search.zonecut_sigrdataset = NULL;
+                                search.need_cleanup = ISC_TRUE;
+                                maybe_zonecut = ISC_FALSE;
+                                at_zonecut = ISC_TRUE;
+                                /*
+                                 * It is not clear if KEY should still be
+                                 * allowed at the parent side of the zone
+                                 * cut or not.  It is needed for RFC3007
+                                 * validated updates.
+                                 */
+                                if ((search.options & DNS_DBFIND_GLUEOK) == 0
+                                    && type != dns_rdatatype_nsec
+                                    && type != dns_rdatatype_key) {
+                                        /*
+                                         * Glue is not OK, but any answer we
+                                         * could return would be glue.  Return
+                                         * the delegation.
+                                         */
+                                        found = NULL;
+                                        break;
+                                }
+                                if (found != NULL && foundsig != NULL)
+                                        break;
+                        }
+
+                        /*
+                         * If we found a type we were looking for,
+                         * remember it.
+                         */
+                        if (header->type == type ||
+                            type == dns_rdatatype_any ||
+                            (header->type == dns_rdatatype_cname &&
+                             cname_ok)) {
+                                /*
+                                 * We've found the answer!
+                                 */
+                                found = header;
+                                if (header->type == dns_rdatatype_cname &&
+                                    cname_ok) {
+                                        /*
+                                         * We may be finding a CNAME instead
+                                         * of the desired type.
+                                         *
+                                         * If we've already got the CNAME RRSIG,
+                                         * use it, otherwise change sigtype
+                                         * so that we find it.
+                                         */
+                                        if (cnamesig != NULL)
+                                                foundsig = cnamesig;
+                                        else
+                                                sigtype =
+                                                    RBTDB_RDATATYPE_SIGCNAME;
+                                }
+                                /*
+                                 * If we've got all we need, end the search.
+                                 */
+                                if (!maybe_zonecut && foundsig != NULL)
+                                        break;
+                        } else if (header->type == sigtype) {
+                                /*
+                                 * We've found the RRSIG rdataset for our
+                                 * target type.  Remember it.
+                                 */
+                                foundsig = header;
+                                /*
+                                 * If we've got all we need, end the search.
+                                 */
+                                if (!maybe_zonecut && found != NULL)
+                                        break;
+                        } else if (header->type == dns_rdatatype_nsec) {
+                                /*
+                                 * Remember a NSEC rdataset even if we're
+                                 * not specifically looking for it, because
+                                 * we might need it later.
+                                 */
+                                nsecheader = header;
+                        } else if (header->type == RBTDB_RDATATYPE_SIGNSEC) {
+                                /*
+                                 * If we need the NSEC rdataset, we'll also
+                                 * need its signature.
+                                 */
+                                nsecsig = header;
+                        } else if (cname_ok &&
+                                   header->type == RBTDB_RDATATYPE_SIGCNAME) {
+                                /*
+                                 * If we get a CNAME match, we'll also need
+                                 * its signature.
+                                 */
+                                cnamesig = header;
+                        }
+                }
+        }
+
+        if (empty_node) {
+                /*
+                 * We have an exact match for the name, but there are no
+                 * active rdatasets in the desired version.  That means that
+                 * this node doesn't exist in the desired version, and that
+                 * we really have a partial match.
+                 */
+                if (!wild) {
+                        lock = &search.rbtdb->node_locks[node->locknum].lock;
+                        NODE_UNLOCK(lock, isc_rwlocktype_read);
+                        goto partial_match;
+                }
+        }
+
+        /*
+         * If we didn't find what we were looking for...
+         */
+        if (found == NULL) {
+                if (search.zonecut != NULL) {
+                        /*
+                         * We were trying to find glue at a node beneath a
+                         * zone cut, but didn't.
+                         *
+                         * Return the delegation.
+                         */
+                        lock = &search.rbtdb->node_locks[node->locknum].lock;
+                        NODE_UNLOCK(lock, isc_rwlocktype_read);
+                        result = setup_delegation(&search, nodep, foundname,
+                                                  rdataset, sigrdataset);
+                        goto tree_exit;
+                }
+                /*
+                 * The desired type doesn't exist.
+                 */
+                result = DNS_R_NXRRSET;
+                if (search.rbtdb->secure &&
+                    (nsecheader == NULL || nsecsig == NULL)) {
+                        /*
+                         * The zone is secure but there's no NSEC,
+                         * or the NSEC has no signature!
+                         */
+                        if (!wild) {
+                                result = DNS_R_BADDB;
+                                goto node_exit;
+                        }
+
+                        lock = &search.rbtdb->node_locks[node->locknum].lock;
+                        NODE_UNLOCK(lock, isc_rwlocktype_read);
+                        result = find_closest_nsec(&search, nodep, foundname,
+                                                   rdataset, sigrdataset,
+                                                   search.rbtdb->secure);
+                        if (result == ISC_R_SUCCESS)
+                                result = DNS_R_EMPTYWILD;
+                        goto tree_exit;
+                }
+                if ((search.options & DNS_DBFIND_FORCENSEC) != 0 &&
+                    nsecheader == NULL)
+                {
+                        /*
+                         * There's no NSEC record, and we were told
+                         * to find one.
+                         */
+                        result = DNS_R_BADDB;
+                        goto node_exit;
+                }
+                if (nodep != NULL) {
+                        new_reference(search.rbtdb, node);
+                        *nodep = node;
+                }
+                if (search.rbtdb->secure ||
+                    (search.options & DNS_DBFIND_FORCENSEC) != 0)
+                {
+                        bind_rdataset(search.rbtdb, node, nsecheader,
+                                      0, rdataset);
+                        if (nsecsig != NULL)
+                                bind_rdataset(search.rbtdb, node,
+                                              nsecsig, 0, sigrdataset);
+                }
+                if (wild)
+                        foundname->attributes |= DNS_NAMEATTR_WILDCARD;
+                goto node_exit;
+        }
+
+        /*
+         * We found what we were looking for, or we found a CNAME.
+         */
+
+        if (type != found->type &&
+            type != dns_rdatatype_any &&
+            found->type == dns_rdatatype_cname) {
+                /*
+                 * We weren't doing an ANY query and we found a CNAME instead
+                 * of the type we were looking for, so we need to indicate
+                 * that result to the caller.
+                 */
+                result = DNS_R_CNAME;
+        } else if (search.zonecut != NULL) {
+                /*
+                 * If we're beneath a zone cut, we must indicate that the
+                 * result is glue, unless we're actually at the zone cut
+                 * and the type is NSEC or KEY.
+                 */
+                if (search.zonecut == node) {
+                        /*
+                         * It is not clear if KEY should still be
+                         * allowed at the parent side of the zone
+                         * cut or not.  It is needed for RFC3007
+                         * validated updates.
+                         */
+                        if (type == dns_rdatatype_nsec ||
+                            type == dns_rdatatype_key)
+                                result = ISC_R_SUCCESS;
+                        else if (type == dns_rdatatype_any)
+                                result = DNS_R_ZONECUT;
+                        else
+                                result = DNS_R_GLUE;
+                } else
+                        result = DNS_R_GLUE;
+                /*
+                 * We might have found data that isn't glue, but was occluded
+                 * by a dynamic update.  If the caller cares about this, they
+                 * will have told us to validate glue.
+                 *
+                 * XXX We should cache the glue validity state!
+                 */
+                if (result == DNS_R_GLUE &&
+                    (search.options & DNS_DBFIND_VALIDATEGLUE) != 0 &&
+                    !valid_glue(&search, foundname, type, node)) {
+                        lock = &search.rbtdb->node_locks[node->locknum].lock;
+                        NODE_UNLOCK(lock, isc_rwlocktype_read);
+                        result = setup_delegation(&search, nodep, foundname,
+                                                  rdataset, sigrdataset);
+                    goto tree_exit;
+                }
+        } else {
+                /*
+                 * An ordinary successful query!
+                 */
+                result = ISC_R_SUCCESS;
+        }
+
+        if (nodep != NULL) {
+                if (!at_zonecut)
+                        new_reference(search.rbtdb, node);
+                else
+                        search.need_cleanup = ISC_FALSE;
+                *nodep = node;
+        }
+
+        if (type != dns_rdatatype_any) {
+                bind_rdataset(search.rbtdb, node, found, 0, rdataset);
+                if (foundsig != NULL)
+                        bind_rdataset(search.rbtdb, node, foundsig, 0,
+                                      sigrdataset);
+        }
+
+        if (wild)
+                foundname->attributes |= DNS_NAMEATTR_WILDCARD;
 
  node_exit:
-       NODE_UNLOCK(&(search.rbtdb->node_locks[node->locknum].lock),
-                   isc_rwlocktype_read);
+        NODE_UNLOCK(&(search.rbtdb->node_locks[node->locknum].lock),
+                    isc_rwlocktype_read);
 
  tree_exit:
-       RWUNLOCK(&search.rbtdb->tree_lock, isc_rwlocktype_read);
+        RWUNLOCK(&search.rbtdb->tree_lock, isc_rwlocktype_read);
 
-       /*
-        * If we found a zonecut but aren't going to use it, we have to
-        * let go of it.
-        */
-       if (search.need_cleanup) {
-               node = search.zonecut;
-               lock = &(search.rbtdb->node_locks[node->locknum].lock);
+        /*
+         * If we found a zonecut but aren't going to use it, we have to
+         * let go of it.
+         */
+        if (search.need_cleanup) {
+                node = search.zonecut;
+                lock = &(search.rbtdb->node_locks[node->locknum].lock);
 
-               NODE_LOCK(lock, isc_rwlocktype_read);
-               decrement_reference(search.rbtdb, node, 0,
-                                   isc_rwlocktype_read, isc_rwlocktype_none);
-               NODE_UNLOCK(lock, isc_rwlocktype_read);
-       }
+                NODE_LOCK(lock, isc_rwlocktype_read);
+                decrement_reference(search.rbtdb, node, 0,
+                                    isc_rwlocktype_read, isc_rwlocktype_none);
+                NODE_UNLOCK(lock, isc_rwlocktype_read);
+        }
 
-       if (close_version)
-               closeversion(db, &version, ISC_FALSE);
+        if (close_version)
+                closeversion(db, &version, ISC_FALSE);
 
-       dns_rbtnodechain_reset(&search.chain);
+        dns_rbtnodechain_reset(&search.chain);
 
-       return (result);
+        return (result);
 }
 
 static isc_result_t
 zone_findzonecut(dns_db_t *db, dns_name_t *name, unsigned int options,
-                isc_stdtime_t now, dns_dbnode_t **nodep,
-                dns_name_t *foundname,
-                dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
+                 isc_stdtime_t now, dns_dbnode_t **nodep,
+                 dns_name_t *foundname,
+                 dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
 {
-       UNUSED(db);
-       UNUSED(name);
-       UNUSED(options);
-       UNUSED(now);
-       UNUSED(nodep);
-       UNUSED(foundname);
-       UNUSED(rdataset);
-       UNUSED(sigrdataset);
-
-       FATAL_ERROR(__FILE__, __LINE__, "zone_findzonecut() called!");
-
-       return (ISC_R_NOTIMPLEMENTED);
+        UNUSED(db);
+        UNUSED(name);
+        UNUSED(options);
+        UNUSED(now);
+        UNUSED(nodep);
+        UNUSED(foundname);
+        UNUSED(rdataset);
+        UNUSED(sigrdataset);
+
+        FATAL_ERROR(__FILE__, __LINE__, "zone_findzonecut() called!");
+
+        return (ISC_R_NOTIMPLEMENTED);
 }
 
 static isc_result_t
 cache_zonecut_callback(dns_rbtnode_t *node, dns_name_t *name, void *arg) {
-       rbtdb_search_t *search = arg;
-       rdatasetheader_t *header, *header_prev, *header_next;
-       rdatasetheader_t *dname_header, *sigdname_header;
-       isc_result_t result;
-       nodelock_t *lock;
-       isc_rwlocktype_t locktype;
-
-       /* XXX comment */
-
-       REQUIRE(search->zonecut == NULL);
-
-       /*
-        * Keep compiler silent.
-        */
-       UNUSED(name);
-
-       lock = &(search->rbtdb->node_locks[node->locknum].lock);
-       locktype = isc_rwlocktype_read; 
-       NODE_LOCK(lock, locktype);
-
-       /*
-        * Look for a DNAME or RRSIG DNAME rdataset.
-        */
-       dname_header = NULL;
-       sigdname_header = NULL;
-       header_prev = NULL;
-       for (header = node->data; header != NULL; header = header_next) {
-               header_next = header->next;
-               if (header->ttl <= search->now) {
-                       /*
-                        * This rdataset is stale.  If no one else is
-                        * using the node, we can clean it up right
-                        * now, otherwise we mark it as stale, and
-                        * the node as dirty, so it will get cleaned
-                        * up later.
-                        */
-                       if ((header->ttl <= search->now - RBTDB_VIRTUAL) &&
-                           (locktype == isc_rwlocktype_write ||
-                            NODE_TRYUPGRADE(lock) == ISC_R_SUCCESS)) {
-                               /*
-                                * We update the node's status only when we
-                                * can get write access; otherwise, we leave
-                                * others to this work.  Periodical cleaning
-                                * will eventually take the job as the last
-                                * resort.
-                                * We won't downgrade the lock, since other
-                                * rdatasets are probably stale, too. 
-                                */
-                               locktype = isc_rwlocktype_write;
-
-                               if (dns_rbtnode_refcurrent(node) == 0) {
-                                       isc_mem_t *mctx;
-
-                                       /*
-                                        * header->down can be non-NULL if the
-                                        * refcount has just decremented to 0
-                                        * but decrement_reference() has not
-                                        * performed clean_cache_node(), in
-                                        * which case we need to purge the
-                                        * stale headers first.
-                                        */
-                                       mctx = search->rbtdb->common.mctx;
-                                       clean_stale_headers(mctx, header);
-                                       if (header_prev != NULL)
-                                               header_prev->next =
-                                                       header->next;
-                                       else
-                                               node->data = header->next;
-                                       free_rdataset(mctx, header);
-                               } else {
-                                       header->attributes |=
-                                               RDATASET_ATTR_STALE;
-                                       node->dirty = 1;
-                                       header_prev = header;
-                               }
-                       } else
-                               header_prev = header;
-               } else if (header->type == dns_rdatatype_dname &&
-                          EXISTS(header)) {
-                       dname_header = header;
-                       header_prev = header;
-               } else if (header->type == RBTDB_RDATATYPE_SIGDNAME &&
-                        EXISTS(header)) {
-                       sigdname_header = header;
-                       header_prev = header;
-               } else
-                       header_prev = header;
-       }
-
-       if (dname_header != NULL &&
-           (dname_header->trust != dns_trust_pending ||
-            (search->options & DNS_DBFIND_PENDINGOK) != 0)) {
-               /*
-                * We increment the reference count on node to ensure that
-                * search->zonecut_rdataset will still be valid later.
-                */
-               new_reference(search->rbtdb, node);
-               search->zonecut = node;
-               search->zonecut_rdataset = dname_header;
-               search->zonecut_sigrdataset = sigdname_header;
-               search->need_cleanup = ISC_TRUE;
-               result = DNS_R_PARTIALMATCH;
-       } else
-               result = DNS_R_CONTINUE;
-
-       NODE_UNLOCK(lock, locktype);
-
-       return (result);
+        rbtdb_search_t *search = arg;
+        rdatasetheader_t *header, *header_prev, *header_next;
+        rdatasetheader_t *dname_header, *sigdname_header;
+        isc_result_t result;
+        nodelock_t *lock;
+        isc_rwlocktype_t locktype;
+
+        /* XXX comment */
+
+        REQUIRE(search->zonecut == NULL);
+
+        /*
+         * Keep compiler silent.
+         */
+        UNUSED(name);
+
+        lock = &(search->rbtdb->node_locks[node->locknum].lock);
+        locktype = isc_rwlocktype_read;
+        NODE_LOCK(lock, locktype);
+
+        /*
+         * Look for a DNAME or RRSIG DNAME rdataset.
+         */
+        dname_header = NULL;
+        sigdname_header = NULL;
+        header_prev = NULL;
+        for (header = node->data; header != NULL; header = header_next) {
+                header_next = header->next;
+                if (header->rdh_ttl <= search->now) {
+                        /*
+                         * This rdataset is stale.  If no one else is
+                         * using the node, we can clean it up right
+                         * now, otherwise we mark it as stale, and
+                         * the node as dirty, so it will get cleaned
+                         * up later.
+                         */
+                        if ((header->rdh_ttl <= search->now - RBTDB_VIRTUAL) &&
+                            (locktype == isc_rwlocktype_write ||
+                             NODE_TRYUPGRADE(lock) == ISC_R_SUCCESS)) {
+                                /*
+                                 * We update the node's status only when we
+                                 * can get write access; otherwise, we leave
+                                 * others to this work.  Periodical cleaning
+                                 * will eventually take the job as the last
+                                 * resort.
+                                 * We won't downgrade the lock, since other
+                                 * rdatasets are probably stale, too.
+                                 */
+                                locktype = isc_rwlocktype_write;
+
+                                if (dns_rbtnode_refcurrent(node) == 0) {
+                                        isc_mem_t *mctx;
+
+                                        /*
+                                         * header->down can be non-NULL if the
+                                         * refcount has just decremented to 0
+                                         * but decrement_reference() has not
+                                         * performed clean_cache_node(), in
+                                         * which case we need to purge the
+                                         * stale headers first.
+                                         */
+                                        mctx = search->rbtdb->common.mctx;
+                                        clean_stale_headers(search->rbtdb,
+                                                            mctx,
+                                                            header);
+                                        if (header_prev != NULL)
+                                                header_prev->next =
+                                                        header->next;
+                                        else
+                                                node->data = header->next;
+                                        free_rdataset(search->rbtdb, mctx,
+                                                      header);
+                                } else {
+                                        header->attributes |=
+                                                RDATASET_ATTR_STALE;
+                                        node->dirty = 1;
+                                        header_prev = header;
+                                }
+                        } else
+                                header_prev = header;
+                } else if (header->type == dns_rdatatype_dname &&
+                           EXISTS(header)) {
+                        dname_header = header;
+                        header_prev = header;
+                } else if (header->type == RBTDB_RDATATYPE_SIGDNAME &&
+                         EXISTS(header)) {
+                        sigdname_header = header;
+                        header_prev = header;
+                } else
+                        header_prev = header;
+        }
+
+        if (dname_header != NULL &&
+            (dname_header->trust != dns_trust_pending ||
+             (search->options & DNS_DBFIND_PENDINGOK) != 0)) {
+                /*
+                 * We increment the reference count on node to ensure that
+                 * search->zonecut_rdataset will still be valid later.
+                 */
+                new_reference(search->rbtdb, node);
+                search->zonecut = node;
+                search->zonecut_rdataset = dname_header;
+                search->zonecut_sigrdataset = sigdname_header;
+                search->need_cleanup = ISC_TRUE;
+                result = DNS_R_PARTIALMATCH;
+        } else
+                result = DNS_R_CONTINUE;
+
+        NODE_UNLOCK(lock, locktype);
+
+        return (result);
 }
 
 static inline isc_result_t
 find_deepest_zonecut(rbtdb_search_t *search, dns_rbtnode_t *node,
-                    dns_dbnode_t **nodep, dns_name_t *foundname,
-                    dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
+                     dns_dbnode_t **nodep, dns_name_t *foundname,
+                     dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
 {
-       unsigned int i;
-       dns_rbtnode_t *level_node;
-       rdatasetheader_t *header, *header_prev, *header_next;
-       rdatasetheader_t *found, *foundsig;
-       isc_result_t result = ISC_R_NOTFOUND;
-       dns_name_t name;
-       dns_rbtdb_t *rbtdb;
-       isc_boolean_t done;
-       nodelock_t *lock;
-       isc_rwlocktype_t locktype;
-
-       /*
-        * Caller must be holding the tree lock.
-        */
-
-       rbtdb = search->rbtdb;
-       i = search->chain.level_matches;
-       done = ISC_FALSE;
-       do {
-               locktype = isc_rwlocktype_read;
-               lock = &rbtdb->node_locks[node->locknum].lock;
-               NODE_LOCK(lock, locktype);
-
-               /*
-                * Look for NS and RRSIG NS rdatasets.
-                */
-               found = NULL;
-               foundsig = NULL;
-               header_prev = NULL;
-               for (header = node->data;
-                    header != NULL;
-                    header = header_next) {
-                       header_next = header->next;
-                       if (header->ttl <= search->now) {
-                               /*
-                                * This rdataset is stale.  If no one else is
-                                * using the node, we can clean it up right
-                                * now, otherwise we mark it as stale, and
-                                * the node as dirty, so it will get cleaned
-                                * up later.
-                                */
-                               if ((header->ttl <= search->now -
-                                                   RBTDB_VIRTUAL) &&
-                                   (locktype == isc_rwlocktype_write ||
-                                    NODE_TRYUPGRADE(lock) == ISC_R_SUCCESS)) {
-                                       /*
-                                        * We update the node's status only
-                                        * when we can get write access.
-                                        */
-                                       locktype = isc_rwlocktype_write;
-
-                                       if (dns_rbtnode_refcurrent(node)
-                                           == 0) {
-                                               isc_mem_t *m;
-
-                                               m = search->rbtdb->common.mctx;
-                                               clean_stale_headers(m, header);
-                                               if (header_prev != NULL)
-                                                       header_prev->next =
-                                                               header->next;
-                                               else
-                                                       node->data =
-                                                               header->next;
-                                               free_rdataset(m, header);
-                                       } else {
-                                               header->attributes |=
-                                                       RDATASET_ATTR_STALE;
-                                               node->dirty = 1;
-                                               header_prev = header;
-                                       }
-                               } else
-                                       header_prev = header;
-                       } else if (EXISTS(header)) {
-                               /*
-                                * We've found an extant rdataset.  See if
-                                * we're interested in it.
-                                */
-                               if (header->type == dns_rdatatype_ns) {
-                                       found = header;
-                                       if (foundsig != NULL)
-                                               break;
-                               } else if (header->type ==
-                                          RBTDB_RDATATYPE_SIGNS) {
-                                       foundsig = header;
-                                       if (found != NULL)
-                                               break;
-                               }
-                               header_prev = header;
-                       } else
-                               header_prev = header;
-               }
-
-               if (found != NULL) {
-                       /*
-                        * If we have to set foundname, we do it before
-                        * anything else.  If we were to set foundname after
-                        * we had set nodep or bound the rdataset, then we'd
-                        * have to undo that work if dns_name_concatenate()
-                        * failed.  By setting foundname first, there's
-                        * nothing to undo if we have trouble.
-                        */
-                       if (foundname != NULL) {
-                               dns_name_init(&name, NULL);
-                               dns_rbt_namefromnode(node, &name);
-                               result = dns_name_copy(&name, foundname, NULL);
-                               while (result == ISC_R_SUCCESS && i > 0) {
-                                       i--;
-                                       level_node = search->chain.levels[i];
-                                       dns_name_init(&name, NULL);
-                                       dns_rbt_namefromnode(level_node,
-                                                            &name);
-                                       result =
-                                               dns_name_concatenate(foundname,
-                                                                    &name,
-                                                                    foundname,
-                                                                    NULL);
-                               }
-                               if (result != ISC_R_SUCCESS) {
-                                       *nodep = NULL;
-                                       goto node_exit;
-                               }
-                       }
-                       result = DNS_R_DELEGATION;
-                       if (nodep != NULL) {
-                               new_reference(search->rbtdb, node);
-                               *nodep = node;
-                       }
-                       bind_rdataset(search->rbtdb, node, found, search->now,
-                                     rdataset);
-                       if (foundsig != NULL)
-                               bind_rdataset(search->rbtdb, node, foundsig,
-                                             search->now, sigrdataset);
-               }
-
-       node_exit:
-               NODE_UNLOCK(lock, locktype);
-
-               if (found == NULL && i > 0) {
-                       i--;
-                       node = search->chain.levels[i];
-               } else
-                       done = ISC_TRUE;
-
-       } while (!done);
-
-       return (result);
+        unsigned int i;
+        dns_rbtnode_t *level_node;
+        rdatasetheader_t *header, *header_prev, *header_next;
+        rdatasetheader_t *found, *foundsig;
+        isc_result_t result = ISC_R_NOTFOUND;
+        dns_name_t name;
+        dns_rbtdb_t *rbtdb;
+        isc_boolean_t done;
+        nodelock_t *lock;
+        isc_rwlocktype_t locktype;
+
+        /*
+         * Caller must be holding the tree lock.
+         */
+
+        rbtdb = search->rbtdb;
+        i = search->chain.level_matches;
+        done = ISC_FALSE;
+        do {
+                locktype = isc_rwlocktype_read;
+                lock = &rbtdb->node_locks[node->locknum].lock;
+                NODE_LOCK(lock, locktype);
+
+                /*
+                 * Look for NS and RRSIG NS rdatasets.
+                 */
+                found = NULL;
+                foundsig = NULL;
+                header_prev = NULL;
+                for (header = node->data;
+                     header != NULL;
+                     header = header_next) {
+                        header_next = header->next;
+                        if (header->rdh_ttl <= search->now) {
+                                /*
+                                 * This rdataset is stale.  If no one else is
+                                 * using the node, we can clean it up right
+                                 * now, otherwise we mark it as stale, and
+                                 * the node as dirty, so it will get cleaned
+                                 * up later.
+                                 */
+                                if ((header->rdh_ttl <= search->now -
+                                                    RBTDB_VIRTUAL) &&
+                                    (locktype == isc_rwlocktype_write ||
+                                     NODE_TRYUPGRADE(lock) == ISC_R_SUCCESS)) {
+                                        /*
+                                         * We update the node's status only
+                                         * when we can get write access.
+                                         */
+                                        locktype = isc_rwlocktype_write;
+
+                                        if (dns_rbtnode_refcurrent(node)
+                                            == 0) {
+                                                isc_mem_t *m;
+
+                                                m = search->rbtdb->common.mctx;
+                                                clean_stale_headers(
+                                                        search->rbtdb,
+                                                        m, header);
+                                                if (header_prev != NULL)
+                                                        header_prev->next =
+                                                                header->next;
+                                                else
+                                                        node->data =
+                                                                header->next;
+                                                free_rdataset(rbtdb, m,
+                                                              header);
+                                        } else {
+                                                header->attributes |=
+                                                        RDATASET_ATTR_STALE;
+                                                node->dirty = 1;
+                                                header_prev = header;
+                                        }
+                                } else
+                                        header_prev = header;
+                        } else if (EXISTS(header)) {
+                                /*
+                                 * We've found an extant rdataset.  See if
+                                 * we're interested in it.
+                                 */
+                                if (header->type == dns_rdatatype_ns) {
+                                        found = header;
+                                        if (foundsig != NULL)
+                                                break;
+                                } else if (header->type ==
+                                           RBTDB_RDATATYPE_SIGNS) {
+                                        foundsig = header;
+                                        if (found != NULL)
+                                                break;
+                                }
+                                header_prev = header;
+                        } else
+                                header_prev = header;
+                }
+
+                if (found != NULL) {
+                        /*
+                         * If we have to set foundname, we do it before
+                         * anything else.  If we were to set foundname after
+                         * we had set nodep or bound the rdataset, then we'd
+                         * have to undo that work if dns_name_concatenate()
+                         * failed.  By setting foundname first, there's
+                         * nothing to undo if we have trouble.
+                         */
+                        if (foundname != NULL) {
+                                dns_name_init(&name, NULL);
+                                dns_rbt_namefromnode(node, &name);
+                                result = dns_name_copy(&name, foundname, NULL);
+                                while (result == ISC_R_SUCCESS && i > 0) {
+                                        i--;
+                                        level_node = search->chain.levels[i];
+                                        dns_name_init(&name, NULL);
+                                        dns_rbt_namefromnode(level_node,
+                                                             &name);
+                                        result =
+                                                dns_name_concatenate(foundname,
+                                                                     &name,
+                                                                     foundname,
+                                                                     NULL);
+                                }
+                                if (result != ISC_R_SUCCESS) {
+                                        *nodep = NULL;
+                                        goto node_exit;
+                                }
+                        }
+                        result = DNS_R_DELEGATION;
+                        if (nodep != NULL) {
+                                new_reference(search->rbtdb, node);
+                                *nodep = node;
+                        }
+                        bind_rdataset(search->rbtdb, node, found, search->now,
+                                      rdataset);
+                        if (foundsig != NULL)
+                                bind_rdataset(search->rbtdb, node, foundsig,
+                                              search->now, sigrdataset);
+                        if (need_headerupdate(found, search->now) ||
+                            (foundsig != NULL &&
+                             need_headerupdate(foundsig, search->now))) {
+                                if (locktype != isc_rwlocktype_write) {
+                                        NODE_UNLOCK(lock, locktype);
+                                        NODE_LOCK(lock, isc_rwlocktype_write);
+                                        locktype = isc_rwlocktype_write;
+                                }
+                                if (need_headerupdate(found, search->now))
+                                        update_header(search->rbtdb, found,
+                                                      search->now);
+                                if (foundsig != NULL &&
+                                    need_headerupdate(foundsig, search->now)) {
+                                        update_header(search->rbtdb, foundsig,
+                                                      search->now);
+                                }
+                        }
+                }
+
+        node_exit:
+                NODE_UNLOCK(lock, locktype);
+
+                if (found == NULL && i > 0) {
+                        i--;
+                        node = search->chain.levels[i];
+                } else
+                        done = ISC_TRUE;
+
+        } while (!done);
+
+        return (result);
 }
 
 static isc_result_t
 find_coveringnsec(rbtdb_search_t *search, dns_dbnode_t **nodep,
-                 isc_stdtime_t now, dns_name_t *foundname,
-                 dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
+                  isc_stdtime_t now, dns_name_t *foundname,
+                  dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
 {
-       dns_rbtnode_t *node;
-       rdatasetheader_t *header, *header_next, *header_prev;
-       rdatasetheader_t *found, *foundsig;
-       isc_boolean_t empty_node;
-       isc_result_t result;
-       dns_fixedname_t fname, forigin;
-       dns_name_t *name, *origin;
-       rbtdb_rdatatype_t matchtype, sigmatchtype;
-       nodelock_t *lock;
-       isc_rwlocktype_t locktype;
-
-       matchtype = RBTDB_RDATATYPE_VALUE(dns_rdatatype_nsec, 0);
-       sigmatchtype = RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig,
-                                            dns_rdatatype_nsec);
-       
-       do {
-               node = NULL;
-               dns_fixedname_init(&fname);
-               name = dns_fixedname_name(&fname);
-               dns_fixedname_init(&forigin);
-               origin = dns_fixedname_name(&forigin);
-               result = dns_rbtnodechain_current(&search->chain, name,
-                                                 origin, &node);
-               if (result != ISC_R_SUCCESS)
-                       return (result);
-               locktype = isc_rwlocktype_read;
-               lock = &(search->rbtdb->node_locks[node->locknum].lock);
-               NODE_LOCK(lock, locktype);
-               found = NULL;
-               foundsig = NULL;
-               empty_node = ISC_TRUE;
-               header_prev = NULL;
-               for (header = node->data;
-                    header != NULL;
-                    header = header_next) {
-                       header_next = header->next;
-                       if (header->ttl <= now) {
-                               /*
-                                * This rdataset is stale.  If no one else is
-                                * using the node, we can clean it up right
-                                * now, otherwise we mark it as stale, and the
-                                * node as dirty, so it will get cleaned up 
-                                * later.
-                                */
-                               if ((header->ttl <= now - RBTDB_VIRTUAL) &&
-                                   (locktype == isc_rwlocktype_write ||
-                                    NODE_TRYUPGRADE(lock) == ISC_R_SUCCESS)) {
-                                       /*
-                                        * We update the node's status only
-                                        * when we can get write access.
-                                        */
-                                       locktype = isc_rwlocktype_write;
-
-                                       if (dns_rbtnode_refcurrent(node)
-                                           == 0) {
-                                               isc_mem_t *m;
-
-                                               m = search->rbtdb->common.mctx;
-                                               clean_stale_headers(m, header);
-                                               if (header_prev != NULL)
-                                                       header_prev->next =
-                                                               header->next;
-                                               else
-                                                       node->data = header->next;
-                                               free_rdataset(m, header);
-                                       } else {
-                                               header->attributes |=
-                                                       RDATASET_ATTR_STALE;
-                                               node->dirty = 1;
-                                               header_prev = header;
-                                       }
-                               } else
-                                       header_prev = header;
-                               continue;
-                       }
-                       if (NONEXISTENT(header) ||
-                           RBTDB_RDATATYPE_BASE(header->type) == 0) {
-                               header_prev = header;
-                               continue;
-                       }
-                       empty_node = ISC_FALSE;
-                       if (header->type == matchtype)
-                               found = header;
-                       else if (header->type == sigmatchtype)
-                               foundsig = header;
-                       header_prev = header;
-               }
-               if (found != NULL) {
-                       result = dns_name_concatenate(name, origin,
-                                                     foundname, NULL);
-                       if (result != ISC_R_SUCCESS)
-                               goto unlock_node;
-                       bind_rdataset(search->rbtdb, node, found,
-                                     now, rdataset);
-                       if (foundsig != NULL)
-                               bind_rdataset(search->rbtdb, node, foundsig,
-                                             now, sigrdataset);
-                       new_reference(search->rbtdb, node);
-                       *nodep = node;
-                       result = DNS_R_COVERINGNSEC;
-               } else if (!empty_node) {
-                       result = ISC_R_NOTFOUND;
-               } else
-                       result = dns_rbtnodechain_prev(&search->chain, NULL,
-                                                      NULL);
+        dns_rbtnode_t *node;
+        rdatasetheader_t *header, *header_next, *header_prev;
+        rdatasetheader_t *found, *foundsig;
+        isc_boolean_t empty_node;
+        isc_result_t result;
+        dns_fixedname_t fname, forigin;
+        dns_name_t *name, *origin;
+        rbtdb_rdatatype_t matchtype, sigmatchtype;
+        nodelock_t *lock;
+        isc_rwlocktype_t locktype;
+
+        matchtype = RBTDB_RDATATYPE_VALUE(dns_rdatatype_nsec, 0);
+        sigmatchtype = RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig,
+                                             dns_rdatatype_nsec);
+
+        do {
+                node = NULL;
+                dns_fixedname_init(&fname);
+                name = dns_fixedname_name(&fname);
+                dns_fixedname_init(&forigin);
+                origin = dns_fixedname_name(&forigin);
+                result = dns_rbtnodechain_current(&search->chain, name,
+                                                  origin, &node);
+                if (result != ISC_R_SUCCESS)
+                        return (result);
+                locktype = isc_rwlocktype_read;
+                lock = &(search->rbtdb->node_locks[node->locknum].lock);
+                NODE_LOCK(lock, locktype);
+                found = NULL;
+                foundsig = NULL;
+                empty_node = ISC_TRUE;
+                header_prev = NULL;
+                for (header = node->data;
+                     header != NULL;
+                     header = header_next) {
+                        header_next = header->next;
+                        if (header->rdh_ttl <= now) {
+                                /*
+                                 * This rdataset is stale.  If no one else is
+                                 * using the node, we can clean it up right
+                                 * now, otherwise we mark it as stale, and the
+                                 * node as dirty, so it will get cleaned up
+                                 * later.
+                                 */
+                                if ((header->rdh_ttl <= now - RBTDB_VIRTUAL) &&
+                                    (locktype == isc_rwlocktype_write ||
+                                     NODE_TRYUPGRADE(lock) == ISC_R_SUCCESS)) {
+                                        /*
+                                         * We update the node's status only
+                                         * when we can get write access.
+                                         */
+                                        locktype = isc_rwlocktype_write;
+
+                                        if (dns_rbtnode_refcurrent(node)
+                                            == 0) {
+                                                isc_mem_t *m;
+
+                                                m = search->rbtdb->common.mctx;
+                                                clean_stale_headers(
+                                                        search->rbtdb,
+                                                        m, header);
+                                                if (header_prev != NULL)
+                                                        header_prev->next =
+                                                                header->next;
+                                                else
+                                                        node->data = header->next;
+                                                free_rdataset(search->rbtdb, m,
+                                                              header);
+                                        } else {
+                                                header->attributes |=
+                                                        RDATASET_ATTR_STALE;
+                                                node->dirty = 1;
+                                                header_prev = header;
+                                        }
+                                } else
+                                        header_prev = header;
+                                continue;
+                        }
+                        if (NONEXISTENT(header) ||
+                            RBTDB_RDATATYPE_BASE(header->type) == 0) {
+                                header_prev = header;
+                                continue;
+                        }
+                        empty_node = ISC_FALSE;
+                        if (header->type == matchtype)
+                                found = header;
+                        else if (header->type == sigmatchtype)
+                                foundsig = header;
+                        header_prev = header;
+                }
+                if (found != NULL) {
+                        result = dns_name_concatenate(name, origin,
+                                                      foundname, NULL);
+                        if (result != ISC_R_SUCCESS)
+                                goto unlock_node;
+                        bind_rdataset(search->rbtdb, node, found,
+                                      now, rdataset);
+                        if (foundsig != NULL)
+                                bind_rdataset(search->rbtdb, node, foundsig,
+                                              now, sigrdataset);
+                        new_reference(search->rbtdb, node);
+                        *nodep = node;
+                        result = DNS_R_COVERINGNSEC;
+                } else if (!empty_node) {
+                        result = ISC_R_NOTFOUND;
+                } else
+                        result = dns_rbtnodechain_prev(&search->chain, NULL,
+                                                       NULL);
  unlock_node:
-               NODE_UNLOCK(lock, locktype);
-       } while (empty_node && result == ISC_R_SUCCESS);
-       return (result);
+                NODE_UNLOCK(lock, locktype);
+        } while (empty_node && result == ISC_R_SUCCESS);
+        return (result);
 }
 
 static isc_result_t
 cache_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
-          dns_rdatatype_t type, unsigned int options, isc_stdtime_t now,
-          dns_dbnode_t **nodep, dns_name_t *foundname,
-          dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
+           dns_rdatatype_t type, unsigned int options, isc_stdtime_t now,
+           dns_dbnode_t **nodep, dns_name_t *foundname,
+           dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
 {
-       dns_rbtnode_t *node = NULL;
-       isc_result_t result;
-       rbtdb_search_t search;
-       isc_boolean_t cname_ok = ISC_TRUE;
-       isc_boolean_t empty_node;
-       nodelock_t *lock;
-       isc_rwlocktype_t locktype;
-       rdatasetheader_t *header, *header_prev, *header_next;
-       rdatasetheader_t *found, *nsheader;
-       rdatasetheader_t *foundsig, *nssig, *cnamesig;
-       rbtdb_rdatatype_t sigtype, negtype;
-
-       UNUSED(version);
-
-       search.rbtdb = (dns_rbtdb_t *)db;
-
-       REQUIRE(VALID_RBTDB(search.rbtdb));
-       REQUIRE(version == NULL);
-
-       if (now == 0)
-               isc_stdtime_get(&now);
-
-       search.rbtversion = NULL;
-       search.serial = 1;
-       search.options = options;
-       search.copy_name = ISC_FALSE;
-       search.need_cleanup = ISC_FALSE;
-       search.wild = ISC_FALSE;
-       search.zonecut = NULL;
-       dns_fixedname_init(&search.zonecut_name);
-       dns_rbtnodechain_init(&search.chain, search.rbtdb->common.mctx);
-       search.now = now;
-
-       RWLOCK(&search.rbtdb->tree_lock, isc_rwlocktype_read);
-
-       /*
-        * Search down from the root of the tree.  If, while going down, we
-        * encounter a callback node, cache_zonecut_callback() will search the
-        * rdatasets at the zone cut for a DNAME rdataset.
-        */
-       result = dns_rbt_findnode(search.rbtdb->tree, name, foundname, &node,
-                                 &search.chain, DNS_RBTFIND_EMPTYDATA,
-                                 cache_zonecut_callback, &search);
-
-       if (result == DNS_R_PARTIALMATCH) {
-               if ((search.options & DNS_DBFIND_COVERINGNSEC) != 0) {
-                       result = find_coveringnsec(&search, nodep, now,
-                                                  foundname, rdataset,
-                                                  sigrdataset);
-                       if (result == DNS_R_COVERINGNSEC)
-                               goto tree_exit;
-               }
-               if (search.zonecut != NULL) {
-                   result = setup_delegation(&search, nodep, foundname,
-                                             rdataset, sigrdataset);
-                   goto tree_exit;
-               } else {
-               find_ns:
-                       result = find_deepest_zonecut(&search, node, nodep,
-                                                     foundname, rdataset,
-                                                     sigrdataset);
-                       goto tree_exit;
-               }
-       } else if (result != ISC_R_SUCCESS)
-               goto tree_exit;
-
-       /*
-        * Certain DNSSEC types are not subject to CNAME matching
-        * (RFC4035, section 2.5 and RFC3007).
-        *
-        * We don't check for RRSIG, because we don't store RRSIG records
-        * directly.
-        */
-       if (type == dns_rdatatype_key || type == dns_rdatatype_nsec)
-               cname_ok = ISC_FALSE;
-
-       /*
-        * We now go looking for rdata...
-        */
-
-       lock = &(search.rbtdb->node_locks[node->locknum].lock);
-       locktype = isc_rwlocktype_read;
-       NODE_LOCK(lock, locktype);
-
-       found = NULL;
-       foundsig = NULL;
-       sigtype = RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, type);
-       negtype = RBTDB_RDATATYPE_VALUE(0, type);
-       nsheader = NULL;
-       nssig = NULL;
-       cnamesig = NULL;
-       empty_node = ISC_TRUE;
-       header_prev = NULL;
-       for (header = node->data; header != NULL; header = header_next) {
-               header_next = header->next;
-               if (header->ttl <= now) {
-                       /*
-                        * This rdataset is stale.  If no one else is using the
-                        * node, we can clean it up right now, otherwise we
-                        * mark it as stale, and the node as dirty, so it will
-                        * get cleaned up later.
-                        */
-                       if ((header->ttl <= now - RBTDB_VIRTUAL) &&
-                           (locktype == isc_rwlocktype_write ||
-                            NODE_TRYUPGRADE(lock) == ISC_R_SUCCESS)) {
-                               /*
-                                * We update the node's status only when we
-                                * can get write access.
-                                */
-                               locktype = isc_rwlocktype_write;
-
-                               if (dns_rbtnode_refcurrent(node) == 0) {
-                                       isc_mem_t *mctx;
-
-                                       mctx = search.rbtdb->common.mctx;
-                                       clean_stale_headers(mctx, header);
-                                       if (header_prev != NULL)
-                                               header_prev->next =
-                                                       header->next;
-                                       else
-                                               node->data = header->next;
-                                       free_rdataset(mctx, header);
-                               } else {
-                                       header->attributes |=
-                                               RDATASET_ATTR_STALE;
-                                       node->dirty = 1;
-                                       header_prev = header;
-                               }
-                       } else
-                               header_prev = header;
-               } else if (EXISTS(header)) {
-                       /*
-                        * We now know that there is at least one active
-                        * non-stale rdataset at this node.
-                        */
-                       empty_node = ISC_FALSE;
-
-                       /*
-                        * If we found a type we were looking for, remember
-                        * it.
-                        */
-                       if (header->type == type ||
-                           (type == dns_rdatatype_any &&
-                            RBTDB_RDATATYPE_BASE(header->type) != 0) ||
-                           (cname_ok && header->type ==
-                            dns_rdatatype_cname)) {
-                               /*
-                                * We've found the answer.
-                                */
-                               found = header;
-                               if (header->type == dns_rdatatype_cname &&
-                                   cname_ok &&
-                                   cnamesig != NULL) {
-                                       /*
-                                        * If we've already got the CNAME RRSIG,
-                                        * use it, otherwise change sigtype
-                                        * so that we find it.
-                                        */
-                                       if (cnamesig != NULL)
-                                               foundsig = cnamesig;
-                                       else
-                                               sigtype =
-                                                   RBTDB_RDATATYPE_SIGCNAME;
-                                       foundsig = cnamesig;
-                               }
-                       } else if (header->type == sigtype) {
-                               /*
-                                * We've found the RRSIG rdataset for our
-                                * target type.  Remember it.
-                                */
-                               foundsig = header;
-                       } else if (header->type == RBTDB_RDATATYPE_NCACHEANY ||
-                                  header->type == negtype) {
-                               /*
-                                * We've found a negative cache entry.
-                                */
-                               found = header;
-                       } else if (header->type == dns_rdatatype_ns) {
-                               /*
-                                * Remember a NS rdataset even if we're
-                                * not specifically looking for it, because
-                                * we might need it later.
-                                */
-                               nsheader = header;
-                       } else if (header->type == RBTDB_RDATATYPE_SIGNS) {
-                               /*
-                                * If we need the NS rdataset, we'll also
-                                * need its signature.
-                                */
-                               nssig = header;
-                       } else if (cname_ok &&
-                                  header->type == RBTDB_RDATATYPE_SIGCNAME) {
-                               /*
-                                * If we get a CNAME match, we'll also need
-                                * its signature.
-                                */
-                               cnamesig = header;
-                       }
-                       header_prev = header;
-               } else
-                       header_prev = header;
-       }
-
-       if (empty_node) {
-               /*
-                * We have an exact match for the name, but there are no
-                * extant rdatasets.  That means that this node doesn't
-                * meaningfully exist, and that we really have a partial match.
-                */
-               NODE_UNLOCK(lock, locktype);
-               goto find_ns;
-       }
-
-       /*
-        * If we didn't find what we were looking for...
-        */
-       if (found == NULL ||
-           (found->trust == dns_trust_glue &&
-            ((options & DNS_DBFIND_GLUEOK) == 0)) ||
-           (found->trust == dns_trust_pending &&
-            ((options & DNS_DBFIND_PENDINGOK) == 0))) {
-               /*
-                * If there is an NS rdataset at this node, then this is the
-                * deepest zone cut.
-                */
-               if (nsheader != NULL) {
-                       if (nodep != NULL) {
-                               new_reference(search.rbtdb, node);
-                               *nodep = node;
-                       }
-                       bind_rdataset(search.rbtdb, node, nsheader, search.now,
-                                     rdataset);
-                       if (nssig != NULL)
-                               bind_rdataset(search.rbtdb, node, nssig,
-                                             search.now, sigrdataset);
-                       result = DNS_R_DELEGATION;
-                       goto node_exit;
-               }
-
-               /*
-                * Go find the deepest zone cut.
-                */
-               NODE_UNLOCK(lock, locktype);
-               goto find_ns;
-       }
-
-       /*
-        * We found what we were looking for, or we found a CNAME.
-        */
-
-       if (nodep != NULL) {
-               new_reference(search.rbtdb, node);
-               *nodep = node;
-       }
-
-       if (RBTDB_RDATATYPE_BASE(found->type) == 0) {
-               /*
-                * We found a negative cache entry.
-                */
-               if (NXDOMAIN(found))
-                       result = DNS_R_NCACHENXDOMAIN;
-               else
-                       result = DNS_R_NCACHENXRRSET;
-       } else if (type != found->type &&
-                  type != dns_rdatatype_any &&
-                  found->type == dns_rdatatype_cname) {
-               /*
-                * We weren't doing an ANY query and we found a CNAME instead
-                * of the type we were looking for, so we need to indicate
-                * that result to the caller.
-                */
-               result = DNS_R_CNAME;
-       } else {
-               /*
-                * An ordinary successful query!
-                */
-               result = ISC_R_SUCCESS;
-       }
-
-       if (type != dns_rdatatype_any || result == DNS_R_NCACHENXDOMAIN ||
-           result == DNS_R_NCACHENXRRSET) {
-               bind_rdataset(search.rbtdb, node, found, search.now,
-                             rdataset);
-               if (foundsig != NULL)
-                       bind_rdataset(search.rbtdb, node, foundsig, search.now,
-                                     sigrdataset);
-       }
+        dns_rbtnode_t *node = NULL;
+        isc_result_t result;
+        rbtdb_search_t search;
+        isc_boolean_t cname_ok = ISC_TRUE;
+        isc_boolean_t empty_node;
+        nodelock_t *lock;
+        isc_rwlocktype_t locktype;
+        rdatasetheader_t *header, *header_prev, *header_next;
+        rdatasetheader_t *found, *nsheader;
+        rdatasetheader_t *foundsig, *nssig, *cnamesig;
+        rdatasetheader_t *update, *updatesig;
+        rbtdb_rdatatype_t sigtype, negtype;
+
+        UNUSED(version);
+
+        search.rbtdb = (dns_rbtdb_t *)db;
+
+        REQUIRE(VALID_RBTDB(search.rbtdb));
+        REQUIRE(version == NULL);
+
+        if (now == 0)
+                isc_stdtime_get(&now);
+
+        search.rbtversion = NULL;
+        search.serial = 1;
+        search.options = options;
+        search.copy_name = ISC_FALSE;
+        search.need_cleanup = ISC_FALSE;
+        search.wild = ISC_FALSE;
+        search.zonecut = NULL;
+        dns_fixedname_init(&search.zonecut_name);
+        dns_rbtnodechain_init(&search.chain, search.rbtdb->common.mctx);
+        search.now = now;
+        update = NULL;
+        updatesig = NULL;
+
+        RWLOCK(&search.rbtdb->tree_lock, isc_rwlocktype_read);
+
+        /*
+         * Search down from the root of the tree.  If, while going down, we
+         * encounter a callback node, cache_zonecut_callback() will search the
+         * rdatasets at the zone cut for a DNAME rdataset.
+         */
+        result = dns_rbt_findnode(search.rbtdb->tree, name, foundname, &node,
+                                  &search.chain, DNS_RBTFIND_EMPTYDATA,
+                                  cache_zonecut_callback, &search);
+
+        if (result == DNS_R_PARTIALMATCH) {
+                if ((search.options & DNS_DBFIND_COVERINGNSEC) != 0) {
+                        result = find_coveringnsec(&search, nodep, now,
+                                                   foundname, rdataset,
+                                                   sigrdataset);
+                        if (result == DNS_R_COVERINGNSEC)
+                                goto tree_exit;
+                }
+                if (search.zonecut != NULL) {
+                    result = setup_delegation(&search, nodep, foundname,
+                                              rdataset, sigrdataset);
+                    goto tree_exit;
+                } else {
+                find_ns:
+                        result = find_deepest_zonecut(&search, node, nodep,
+                                                      foundname, rdataset,
+                                                      sigrdataset);
+                        goto tree_exit;
+                }
+        } else if (result != ISC_R_SUCCESS)
+                goto tree_exit;
+
+        /*
+         * Certain DNSSEC types are not subject to CNAME matching
+         * (RFC4035, section 2.5 and RFC3007).
+         *
+         * We don't check for RRSIG, because we don't store RRSIG records
+         * directly.
+         */
+        if (type == dns_rdatatype_key || type == dns_rdatatype_nsec)
+                cname_ok = ISC_FALSE;
+
+        /*
+         * We now go looking for rdata...
+         */
+
+        lock = &(search.rbtdb->node_locks[node->locknum].lock);
+        locktype = isc_rwlocktype_read;
+        NODE_LOCK(lock, locktype);
+
+        found = NULL;
+        foundsig = NULL;
+        sigtype = RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, type);
+        negtype = RBTDB_RDATATYPE_VALUE(0, type);
+        nsheader = NULL;
+        nssig = NULL;
+        cnamesig = NULL;
+        empty_node = ISC_TRUE;
+        header_prev = NULL;
+        for (header = node->data; header != NULL; header = header_next) {
+                header_next = header->next;
+                if (header->rdh_ttl <= now) {
+                        /*
+                         * This rdataset is stale.  If no one else is using the
+                         * node, we can clean it up right now, otherwise we
+                         * mark it as stale, and the node as dirty, so it will
+                         * get cleaned up later.
+                         */
+                        if ((header->rdh_ttl <= now - RBTDB_VIRTUAL) &&
+                            (locktype == isc_rwlocktype_write ||
+                             NODE_TRYUPGRADE(lock) == ISC_R_SUCCESS)) {
+                                /*
+                                 * We update the node's status only when we
+                                 * can get write access.
+                                 */
+                                locktype = isc_rwlocktype_write;
+
+                                if (dns_rbtnode_refcurrent(node) == 0) {
+                                        isc_mem_t *mctx;
+
+                                        mctx = search.rbtdb->common.mctx;
+                                        clean_stale_headers(search.rbtdb, mctx,
+                                                            header);
+                                        if (header_prev != NULL)
+                                                header_prev->next =
+                                                        header->next;
+                                        else
+                                                node->data = header->next;
+                                        free_rdataset(search.rbtdb, mctx,
+                                                      header);
+                                } else {
+                                        header->attributes |=
+                                                RDATASET_ATTR_STALE;
+                                        node->dirty = 1;
+                                        header_prev = header;
+                                }
+                        } else
+                                header_prev = header;
+                } else if (EXISTS(header)) {
+                        /*
+                         * We now know that there is at least one active
+                         * non-stale rdataset at this node.
+                         */
+                        empty_node = ISC_FALSE;
+
+                        /*
+                         * If we found a type we were looking for, remember
+                         * it.
+                         */
+                        if (header->type == type ||
+                            (type == dns_rdatatype_any &&
+                             RBTDB_RDATATYPE_BASE(header->type) != 0) ||
+                            (cname_ok && header->type ==
+                             dns_rdatatype_cname)) {
+                                /*
+                                 * We've found the answer.
+                                 */
+                                found = header;
+                                if (header->type == dns_rdatatype_cname &&
+                                    cname_ok &&
+                                    cnamesig != NULL) {
+                                        /*
+                                         * If we've already got the CNAME RRSIG,
+                                         * use it, otherwise change sigtype
+                                         * so that we find it.
+                                         */
+                                        if (cnamesig != NULL)
+                                                foundsig = cnamesig;
+                                        else
+                                                sigtype =
+                                                    RBTDB_RDATATYPE_SIGCNAME;
+                                        foundsig = cnamesig;
+                                }
+                        } else if (header->type == sigtype) {
+                                /*
+                                 * We've found the RRSIG rdataset for our
+                                 * target type.  Remember it.
+                                 */
+                                foundsig = header;
+                        } else if (header->type == RBTDB_RDATATYPE_NCACHEANY ||
+                                   header->type == negtype) {
+                                /*
+                                 * We've found a negative cache entry.
+                                 */
+                                found = header;
+                        } else if (header->type == dns_rdatatype_ns) {
+                                /*
+                                 * Remember a NS rdataset even if we're
+                                 * not specifically looking for it, because
+                                 * we might need it later.
+                                 */
+                                nsheader = header;
+                        } else if (header->type == RBTDB_RDATATYPE_SIGNS) {
+                                /*
+                                 * If we need the NS rdataset, we'll also
+                                 * need its signature.
+                                 */
+                                nssig = header;
+                        } else if (cname_ok &&
+                                   header->type == RBTDB_RDATATYPE_SIGCNAME) {
+                                /*
+                                 * If we get a CNAME match, we'll also need
+                                 * its signature.
+                                 */
+                                cnamesig = header;
+                        }
+                        header_prev = header;
+                } else
+                        header_prev = header;
+        }
+
+        if (empty_node) {
+                /*
+                 * We have an exact match for the name, but there are no
+                 * extant rdatasets.  That means that this node doesn't
+                 * meaningfully exist, and that we really have a partial match.
+                 */
+                NODE_UNLOCK(lock, locktype);
+                goto find_ns;
+        }
+
+        /*
+         * If we didn't find what we were looking for...
+         */
+        if (found == NULL ||
+            (found->trust == dns_trust_glue &&
+             ((options & DNS_DBFIND_GLUEOK) == 0)) ||
+            (found->trust == dns_trust_pending &&
+             ((options & DNS_DBFIND_PENDINGOK) == 0))) {
+                /*
+                 * If there is an NS rdataset at this node, then this is the
+                 * deepest zone cut.
+                 */
+                if (nsheader != NULL) {
+                        if (nodep != NULL) {
+                                new_reference(search.rbtdb, node);
+                                *nodep = node;
+                        }
+                        bind_rdataset(search.rbtdb, node, nsheader, search.now,
+                                      rdataset);
+                        if (need_headerupdate(nsheader, search.now))
+                                update = nsheader;
+                        if (nssig != NULL) {
+                                bind_rdataset(search.rbtdb, node, nssig,
+                                              search.now, sigrdataset);
+                                if (need_headerupdate(nssig, search.now))
+                                        updatesig = nssig;
+                        }
+                        result = DNS_R_DELEGATION;
+                        goto node_exit;
+                }
+
+                /*
+                 * Go find the deepest zone cut.
+                 */
+                NODE_UNLOCK(lock, locktype);
+                goto find_ns;
+        }
+
+        /*
+         * We found what we were looking for, or we found a CNAME.
+         */
+
+        if (nodep != NULL) {
+                new_reference(search.rbtdb, node);
+                *nodep = node;
+        }
+
+        if (RBTDB_RDATATYPE_BASE(found->type) == 0) {
+                /*
+                 * We found a negative cache entry.
+                 */
+                if (NXDOMAIN(found))
+                        result = DNS_R_NCACHENXDOMAIN;
+                else
+                        result = DNS_R_NCACHENXRRSET;
+        } else if (type != found->type &&
+                   type != dns_rdatatype_any &&
+                   found->type == dns_rdatatype_cname) {
+                /*
+                 * We weren't doing an ANY query and we found a CNAME instead
+                 * of the type we were looking for, so we need to indicate
+                 * that result to the caller.
+                 */
+                result = DNS_R_CNAME;
+        } else {
+                /*
+                 * An ordinary successful query!
+                 */
+                result = ISC_R_SUCCESS;
+        }
+
+        if (type != dns_rdatatype_any || result == DNS_R_NCACHENXDOMAIN ||
+            result == DNS_R_NCACHENXRRSET) {
+                bind_rdataset(search.rbtdb, node, found, search.now,
+                              rdataset);
+                if (need_headerupdate(found, search.now))
+                        update = found;
+                if (foundsig != NULL) {
+                        bind_rdataset(search.rbtdb, node, foundsig, search.now,
+                                      sigrdataset);
+                        if (need_headerupdate(foundsig, search.now))
+                                updatesig = foundsig;
+                }
+        }
 
  node_exit:
-       NODE_UNLOCK(lock, locktype);
+        if ((update != NULL || updatesig != NULL) &&
+            locktype != isc_rwlocktype_write) {
+                NODE_UNLOCK(lock, locktype);
+                NODE_LOCK(lock, isc_rwlocktype_write);
+                locktype = isc_rwlocktype_write;
+        }
+        if (update != NULL && need_headerupdate(update, search.now))
+                update_header(search.rbtdb, update, search.now);
+        if (updatesig != NULL && need_headerupdate(updatesig, search.now))
+                update_header(search.rbtdb, updatesig, search.now);
+
+        NODE_UNLOCK(lock, locktype);
 
  tree_exit:
-       RWUNLOCK(&search.rbtdb->tree_lock, isc_rwlocktype_read);
+        RWUNLOCK(&search.rbtdb->tree_lock, isc_rwlocktype_read);
 
-       /*
-        * If we found a zonecut but aren't going to use it, we have to
-        * let go of it.
-        */
-       if (search.need_cleanup) {
-               node = search.zonecut;
-               lock = &(search.rbtdb->node_locks[node->locknum].lock);
+        /*
+         * If we found a zonecut but aren't going to use it, we have to
+         * let go of it.
+         */
+        if (search.need_cleanup) {
+                node = search.zonecut;
+                lock = &(search.rbtdb->node_locks[node->locknum].lock);
 
-               NODE_LOCK(lock, isc_rwlocktype_read);
-               decrement_reference(search.rbtdb, node, 0,
-                                   isc_rwlocktype_read, isc_rwlocktype_none);
-               NODE_UNLOCK(lock, isc_rwlocktype_read);
-       }
+                NODE_LOCK(lock, isc_rwlocktype_read);
+                decrement_reference(search.rbtdb, node, 0,
+                                    isc_rwlocktype_read, isc_rwlocktype_none);
+                NODE_UNLOCK(lock, isc_rwlocktype_read);
+        }
 
-       dns_rbtnodechain_reset(&search.chain);
+        dns_rbtnodechain_reset(&search.chain);
 
-       return (result);
+        return (result);
 }
 
 static isc_result_t
 cache_findzonecut(dns_db_t *db, dns_name_t *name, unsigned int options,
-                 isc_stdtime_t now, dns_dbnode_t **nodep,
-                 dns_name_t *foundname,
-                 dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
+                  isc_stdtime_t now, dns_dbnode_t **nodep,
+                  dns_name_t *foundname,
+                  dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
 {
-       dns_rbtnode_t *node = NULL;
-       nodelock_t *lock;
-       isc_result_t result;
-       rbtdb_search_t search;
-       rdatasetheader_t *header, *header_prev, *header_next;
-       rdatasetheader_t *found, *foundsig;
-       unsigned int rbtoptions = DNS_RBTFIND_EMPTYDATA;
-       isc_rwlocktype_t locktype;
-
-       search.rbtdb = (dns_rbtdb_t *)db;
-
-       REQUIRE(VALID_RBTDB(search.rbtdb));
-
-       if (now == 0)
-               isc_stdtime_get(&now);
-
-       search.rbtversion = NULL;
-       search.serial = 1;
-       search.options = options;
-       search.copy_name = ISC_FALSE;
-       search.need_cleanup = ISC_FALSE;
-       search.wild = ISC_FALSE;
-       search.zonecut = NULL;
-       dns_fixedname_init(&search.zonecut_name);
-       dns_rbtnodechain_init(&search.chain, search.rbtdb->common.mctx);
-       search.now = now;
-
-       if ((options & DNS_DBFIND_NOEXACT) != 0)
-               rbtoptions |= DNS_RBTFIND_NOEXACT;
-
-       RWLOCK(&search.rbtdb->tree_lock, isc_rwlocktype_read);
-
-       /*
-        * Search down from the root of the tree.
-        */
-       result = dns_rbt_findnode(search.rbtdb->tree, name, foundname, &node,
-                                 &search.chain, rbtoptions, NULL, &search);
-
-       if (result == DNS_R_PARTIALMATCH) {
-       find_ns:
-               result = find_deepest_zonecut(&search, node, nodep, foundname,
-                                             rdataset, sigrdataset);
-               goto tree_exit;
-       } else if (result != ISC_R_SUCCESS)
-               goto tree_exit;
-
-       /*
-        * We now go looking for an NS rdataset at the node.
-        */
-
-       lock = &(search.rbtdb->node_locks[node->locknum].lock);
-       locktype = isc_rwlocktype_read;
-       NODE_LOCK(lock, locktype);
-
-       found = NULL;
-       foundsig = NULL;
-       header_prev = NULL;
-       for (header = node->data; header != NULL; header = header_next) {
-               header_next = header->next;
-               if (header->ttl <= now) {
-                       /*
-                        * This rdataset is stale.  If no one else is using the
-                        * node, we can clean it up right now, otherwise we
-                        * mark it as stale, and the node as dirty, so it will
-                        * get cleaned up later.
-                        */
-                       if ((header->ttl <= now - RBTDB_VIRTUAL) &&
-                           (locktype == isc_rwlocktype_write ||
-                            NODE_TRYUPGRADE(lock) == ISC_R_SUCCESS)) {
-                               /*
-                                * We update the node's status only when we
-                                * can get write access.
-                                */
-                               locktype = isc_rwlocktype_write;
-
-                               if (dns_rbtnode_refcurrent(node) == 0) {
-                                       isc_mem_t *mctx;
-
-                                       mctx = search.rbtdb->common.mctx;
-                                       clean_stale_headers(mctx, header);
-                                       if (header_prev != NULL)
-                                               header_prev->next =
-                                                       header->next;
-                                       else
-                                               node->data = header->next;
-                                       free_rdataset(mctx, header);
-                               } else {
-                                       header->attributes |=
-                                               RDATASET_ATTR_STALE;
-                                       node->dirty = 1;
-                                       header_prev = header;
-                               }
-                       } else
-                               header_prev = header;
-               } else if (EXISTS(header)) {
-                       /*
-                        * If we found a type we were looking for, remember
-                        * it.
-                        */
-                       if (header->type == dns_rdatatype_ns) {
-                               /*
-                                * Remember a NS rdataset even if we're
-                                * not specifically looking for it, because
-                                * we might need it later.
-                                */
-                               found = header;
-                       } else if (header->type == RBTDB_RDATATYPE_SIGNS) {
-                               /*
-                                * If we need the NS rdataset, we'll also
-                                * need its signature.
-                                */
-                               foundsig = header;
-                       }
-                       header_prev = header;
-               } else
-                       header_prev = header;
-       }
-
-       if (found == NULL) {
-               /*
-                * No NS records here.
-                */
-               NODE_UNLOCK(lock, locktype);
-               goto find_ns;
-       }
-
-       if (nodep != NULL) {
-               new_reference(search.rbtdb, node);
-               *nodep = node;
-       }
-
-       bind_rdataset(search.rbtdb, node, found, search.now, rdataset);
-       if (foundsig != NULL)
-               bind_rdataset(search.rbtdb, node, foundsig, search.now,
-                             sigrdataset);
-
-       NODE_UNLOCK(lock, locktype);
+        dns_rbtnode_t *node = NULL;
+        nodelock_t *lock;
+        isc_result_t result;
+        rbtdb_search_t search;
+        rdatasetheader_t *header, *header_prev, *header_next;
+        rdatasetheader_t *found, *foundsig;
+        unsigned int rbtoptions = DNS_RBTFIND_EMPTYDATA;
+        isc_rwlocktype_t locktype;
+
+        search.rbtdb = (dns_rbtdb_t *)db;
+
+        REQUIRE(VALID_RBTDB(search.rbtdb));
+
+        if (now == 0)
+                isc_stdtime_get(&now);
+
+        search.rbtversion = NULL;
+        search.serial = 1;
+        search.options = options;
+        search.copy_name = ISC_FALSE;
+        search.need_cleanup = ISC_FALSE;
+        search.wild = ISC_FALSE;
+        search.zonecut = NULL;
+        dns_fixedname_init(&search.zonecut_name);
+        dns_rbtnodechain_init(&search.chain, search.rbtdb->common.mctx);
+        search.now = now;
+
+        if ((options & DNS_DBFIND_NOEXACT) != 0)
+                rbtoptions |= DNS_RBTFIND_NOEXACT;
+
+        RWLOCK(&search.rbtdb->tree_lock, isc_rwlocktype_read);
+
+        /*
+         * Search down from the root of the tree.
+         */
+        result = dns_rbt_findnode(search.rbtdb->tree, name, foundname, &node,
+                                  &search.chain, rbtoptions, NULL, &search);
+
+        if (result == DNS_R_PARTIALMATCH) {
+        find_ns:
+                result = find_deepest_zonecut(&search, node, nodep, foundname,
+                                              rdataset, sigrdataset);
+                goto tree_exit;
+        } else if (result != ISC_R_SUCCESS)
+                goto tree_exit;
+
+        /*
+         * We now go looking for an NS rdataset at the node.
+         */
+
+        lock = &(search.rbtdb->node_locks[node->locknum].lock);
+        locktype = isc_rwlocktype_read;
+        NODE_LOCK(lock, locktype);
+
+        found = NULL;
+        foundsig = NULL;
+        header_prev = NULL;
+        for (header = node->data; header != NULL; header = header_next) {
+                header_next = header->next;
+                if (header->rdh_ttl <= now) {
+                        /*
+                         * This rdataset is stale.  If no one else is using the
+                         * node, we can clean it up right now, otherwise we
+                         * mark it as stale, and the node as dirty, so it will
+                         * get cleaned up later.
+                         */
+                        if ((header->rdh_ttl <= now - RBTDB_VIRTUAL) &&
+                            (locktype == isc_rwlocktype_write ||
+                             NODE_TRYUPGRADE(lock) == ISC_R_SUCCESS)) {
+                                /*
+                                 * We update the node's status only when we
+                                 * can get write access.
+                                 */
+                                locktype = isc_rwlocktype_write;
+
+                                if (dns_rbtnode_refcurrent(node) == 0) {
+                                        isc_mem_t *mctx;
+
+                                        mctx = search.rbtdb->common.mctx;
+                                        clean_stale_headers(search.rbtdb, mctx,
+                                                            header);
+                                        if (header_prev != NULL)
+                                                header_prev->next =
+                                                        header->next;
+                                        else
+                                                node->data = header->next;
+                                        free_rdataset(search.rbtdb, mctx,
+                                                      header);
+                                } else {
+                                        header->attributes |=
+                                                RDATASET_ATTR_STALE;
+                                        node->dirty = 1;
+                                        header_prev = header;
+                                }
+                        } else
+                                header_prev = header;
+                } else if (EXISTS(header)) {
+                        /*
+                         * If we found a type we were looking for, remember
+                         * it.
+                         */
+                        if (header->type == dns_rdatatype_ns) {
+                                /*
+                                 * Remember a NS rdataset even if we're
+                                 * not specifically looking for it, because
+                                 * we might need it later.
+                                 */
+                                found = header;
+                        } else if (header->type == RBTDB_RDATATYPE_SIGNS) {
+                                /*
+                                 * If we need the NS rdataset, we'll also
+                                 * need its signature.
+                                 */
+                                foundsig = header;
+                        }
+                        header_prev = header;
+                } else
+                        header_prev = header;
+        }
+
+        if (found == NULL) {
+                /*
+                 * No NS records here.
+                 */
+                NODE_UNLOCK(lock, locktype);
+                goto find_ns;
+        }
+
+        if (nodep != NULL) {
+                new_reference(search.rbtdb, node);
+                *nodep = node;
+        }
+
+        bind_rdataset(search.rbtdb, node, found, search.now, rdataset);
+        if (foundsig != NULL)
+                bind_rdataset(search.rbtdb, node, foundsig, search.now,
+                              sigrdataset);
+
+        if (need_headerupdate(found, search.now) ||
+            (foundsig != NULL &&  need_headerupdate(foundsig, search.now))) {
+                if (locktype != isc_rwlocktype_write) {
+                        NODE_UNLOCK(lock, locktype);
+                        NODE_LOCK(lock, isc_rwlocktype_write);
+                        locktype = isc_rwlocktype_write;
+                }
+                if (need_headerupdate(found, search.now))
+                        update_header(search.rbtdb, found, search.now);
+                if (foundsig != NULL &&
+                    need_headerupdate(foundsig, search.now)) {
+                        update_header(search.rbtdb, foundsig, search.now);
+                }
+        }
+
+        NODE_UNLOCK(lock, locktype);
 
  tree_exit:
-       RWUNLOCK(&search.rbtdb->tree_lock, isc_rwlocktype_read);
+        RWUNLOCK(&search.rbtdb->tree_lock, isc_rwlocktype_read);
 
-       INSIST(!search.need_cleanup);
+        INSIST(!search.need_cleanup);
 
-       dns_rbtnodechain_reset(&search.chain);
+        dns_rbtnodechain_reset(&search.chain);
 
-       if (result == DNS_R_DELEGATION)
-               result = ISC_R_SUCCESS;
+        if (result == DNS_R_DELEGATION)
+                result = ISC_R_SUCCESS;
 
-       return (result);
+        return (result);
 }
 
 static void
 attachnode(dns_db_t *db, dns_dbnode_t *source, dns_dbnode_t **targetp) {
-       dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
-       dns_rbtnode_t *node = (dns_rbtnode_t *)source;
-       unsigned int refs;
+        dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
+        dns_rbtnode_t *node = (dns_rbtnode_t *)source;
+        unsigned int refs;
 
-       REQUIRE(VALID_RBTDB(rbtdb));
-       REQUIRE(targetp != NULL && *targetp == NULL);
+        REQUIRE(VALID_RBTDB(rbtdb));
+        REQUIRE(targetp != NULL && *targetp == NULL);
 
-       NODE_STRONGLOCK(&rbtdb->node_locks[node->locknum].lock);
-       dns_rbtnode_refincrement(node, &refs);
-       INSIST(refs != 0);
-       NODE_STRONGUNLOCK(&rbtdb->node_locks[node->locknum].lock);
+        NODE_STRONGLOCK(&rbtdb->node_locks[node->locknum].lock);
+        dns_rbtnode_refincrement(node, &refs);
+        INSIST(refs != 0);
+        NODE_STRONGUNLOCK(&rbtdb->node_locks[node->locknum].lock);
 
-       *targetp = source;
+        *targetp = source;
 }
 
 static void
 detachnode(dns_db_t *db, dns_dbnode_t **targetp) {
-       dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
-       dns_rbtnode_t *node;
-       isc_boolean_t want_free = ISC_FALSE;
-       isc_boolean_t inactive = ISC_FALSE;
-       rbtdb_nodelock_t *nodelock;
-
-       REQUIRE(VALID_RBTDB(rbtdb));
-       REQUIRE(targetp != NULL && *targetp != NULL);
-
-       node = (dns_rbtnode_t *)(*targetp);
-       nodelock = &rbtdb->node_locks[node->locknum];
-
-       NODE_LOCK(&nodelock->lock, isc_rwlocktype_read);
-
-       if (decrement_reference(rbtdb, node, 0, isc_rwlocktype_read,
-                               isc_rwlocktype_none)) {
-               if (isc_refcount_current(&nodelock->references) == 0 &&
-                   nodelock->exiting) {
-                       inactive = ISC_TRUE;
-               }
-       }
-
-       NODE_UNLOCK(&nodelock->lock, isc_rwlocktype_read);
-
-       *targetp = NULL;
-
-       if (inactive) {
-               RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_write);
-               rbtdb->active--;
-               if (rbtdb->active == 0)
-                       want_free = ISC_TRUE;
-               RBTDB_UNLOCK(&rbtdb->lock, isc_rwlocktype_write);
-               if (want_free) {
-                       char buf[DNS_NAME_FORMATSIZE];
-                       if (dns_name_dynamic(&rbtdb->common.origin))
-                               dns_name_format(&rbtdb->common.origin, buf,
-                                               sizeof(buf));
-                       else
-                               strcpy(buf, "<UNKNOWN>");
-                       isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
-                                     DNS_LOGMODULE_CACHE, ISC_LOG_DEBUG(1),
-                                     "calling free_rbtdb(%s)", buf);
-                       free_rbtdb(rbtdb, ISC_TRUE, NULL);
-               }
-       }
+        dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
+        dns_rbtnode_t *node;
+        isc_boolean_t want_free = ISC_FALSE;
+        isc_boolean_t inactive = ISC_FALSE;
+        rbtdb_nodelock_t *nodelock;
+
+        REQUIRE(VALID_RBTDB(rbtdb));
+        REQUIRE(targetp != NULL && *targetp != NULL);
+
+        node = (dns_rbtnode_t *)(*targetp);
+        nodelock = &rbtdb->node_locks[node->locknum];
+
+        NODE_LOCK(&nodelock->lock, isc_rwlocktype_read);
+
+        if (decrement_reference(rbtdb, node, 0, isc_rwlocktype_read,
+                                isc_rwlocktype_none)) {
+                if (isc_refcount_current(&nodelock->references) == 0 &&
+                    nodelock->exiting) {
+                        inactive = ISC_TRUE;
+                }
+        }
+
+        NODE_UNLOCK(&nodelock->lock, isc_rwlocktype_read);
+
+        *targetp = NULL;
+
+        if (inactive) {
+                RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_write);
+                rbtdb->active--;
+                if (rbtdb->active == 0)
+                        want_free = ISC_TRUE;
+                RBTDB_UNLOCK(&rbtdb->lock, isc_rwlocktype_write);
+                if (want_free) {
+                        char buf[DNS_NAME_FORMATSIZE];
+                        if (dns_name_dynamic(&rbtdb->common.origin))
+                                dns_name_format(&rbtdb->common.origin, buf,
+                                                sizeof(buf));
+                        else
+                                strcpy(buf, "<UNKNOWN>");
+                        isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+                                      DNS_LOGMODULE_CACHE, ISC_LOG_DEBUG(1),
+                                      "calling free_rbtdb(%s)", buf);
+                        free_rbtdb(rbtdb, ISC_TRUE, NULL);
+                }
+        }
 }
 
 static isc_result_t
 expirenode(dns_db_t *db, dns_dbnode_t *node, isc_stdtime_t now) {
-       dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
-       dns_rbtnode_t *rbtnode = node;
-       rdatasetheader_t *header;
-       isc_boolean_t force_expire = ISC_FALSE;
-       /*
-        * These are the category and module used by the cache cleaner.
-        */
-       isc_boolean_t log = ISC_FALSE;
-       isc_logcategory_t *category = DNS_LOGCATEGORY_DATABASE;
-       isc_logmodule_t *module = DNS_LOGMODULE_CACHE;
-       int level = ISC_LOG_DEBUG(2);
-       char printname[DNS_NAME_FORMATSIZE];
-
-       REQUIRE(VALID_RBTDB(rbtdb));
-
-       /*
-        * Caller must hold a tree lock.
-        */
-
-       if (now == 0)
-               isc_stdtime_get(&now);
-
-       if (rbtdb->overmem) {
-               isc_uint32_t val;
-
-               isc_random_get(&val);
-               /*
-                * XXXDCL Could stand to have a better policy, like LRU.
-                */
-               force_expire = ISC_TF(rbtnode->down == NULL && val % 4 == 0);
-
-               /*
-                * Note that 'log' can be true IFF rbtdb->overmem is also true.
-                * rbtdb->ovemem can currently only be true for cache databases
-                * -- hence all of the "overmem cache" log strings.
-                */
-               log = ISC_TF(isc_log_wouldlog(dns_lctx, level));
-               if (log)
-                       isc_log_write(dns_lctx, category, module, level,
-                                     "overmem cache: %s %s",
-                                     force_expire ? "FORCE" : "check",
-                                     dns_rbt_formatnodename(rbtnode,
-                                                          printname,
-                                                          sizeof(printname)));
-       }
-
-       /*
-        * We may not need write access, but this code path is not performance
-        * sensitive, so it should be okay to always lock as a writer.
-        */
-       NODE_LOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
-                 isc_rwlocktype_write);
-
-       for (header = rbtnode->data; header != NULL; header = header->next)
-               if (header->ttl <= now - RBTDB_VIRTUAL) {
-                       /*
-                        * We don't check if refcurrent(rbtnode) == 0 and try
-                        * to free like we do in cache_find(), because
-                        * refcurrent(rbtnode) must be non-zero.  This is so
-                        * because 'node' is an argument to the function.
-                        */
-                       header->attributes |= RDATASET_ATTR_STALE;
-                       rbtnode->dirty = 1;
-                       if (log)
-                               isc_log_write(dns_lctx, category, module,
-                                             level, "overmem cache: stale %s",
-                                             printname);
-               } else if (force_expire) {
-                       if (! RETAIN(header)) {
-                               header->ttl = 0;
-                               header->attributes |= RDATASET_ATTR_STALE;
-                               rbtnode->dirty = 1;
-                       } else if (log) {
-                               isc_log_write(dns_lctx, category, module,
-                                             level, "overmem cache: "
-                                             "reprieve by RETAIN() %s",
-                                             printname);
-                       }
-               } else if (rbtdb->overmem && log)
-                       isc_log_write(dns_lctx, category, module, level,
-                                     "overmem cache: saved %s", printname);
-
-       NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
-                   isc_rwlocktype_write);
-
-       return (ISC_R_SUCCESS);
+        dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
+        dns_rbtnode_t *rbtnode = node;
+        rdatasetheader_t *header;
+        isc_boolean_t force_expire = ISC_FALSE;
+        /*
+         * These are the category and module used by the cache cleaner.
+         */
+        isc_boolean_t log = ISC_FALSE;
+        isc_logcategory_t *category = DNS_LOGCATEGORY_DATABASE;
+        isc_logmodule_t *module = DNS_LOGMODULE_CACHE;
+        int level = ISC_LOG_DEBUG(2);
+        char printname[DNS_NAME_FORMATSIZE];
+
+        REQUIRE(VALID_RBTDB(rbtdb));
+
+        /*
+         * Caller must hold a tree lock.
+         */
+
+        if (now == 0)
+                isc_stdtime_get(&now);
+
+        if (rbtdb->overmem) {
+                isc_uint32_t val;
+
+                isc_random_get(&val);
+                /*
+                 * XXXDCL Could stand to have a better policy, like LRU.
+                 */
+                force_expire = ISC_TF(rbtnode->down == NULL && val % 4 == 0);
+
+                /*
+                 * Note that 'log' can be true IFF rbtdb->overmem is also true.
+                 * rbtdb->ovemem can currently only be true for cache databases
+                 * -- hence all of the "overmem cache" log strings.
+                 */
+                log = ISC_TF(isc_log_wouldlog(dns_lctx, level));
+                if (log)
+                        isc_log_write(dns_lctx, category, module, level,
+                                      "overmem cache: %s %s",
+                                      force_expire ? "FORCE" : "check",
+                                      dns_rbt_formatnodename(rbtnode,
+                                                           printname,
+                                                           sizeof(printname)));
+        }
+
+        /*
+         * We may not need write access, but this code path is not performance
+         * sensitive, so it should be okay to always lock as a writer.
+         */
+        NODE_LOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
+                  isc_rwlocktype_write);
+
+        for (header = rbtnode->data; header != NULL; header = header->next)
+                if (header->rdh_ttl <= now - RBTDB_VIRTUAL) {
+                        /*
+                         * We don't check if refcurrent(rbtnode) == 0 and try
+                         * to free like we do in cache_find(), because
+                         * refcurrent(rbtnode) must be non-zero.  This is so
+                         * because 'node' is an argument to the function.
+                         */
+                        header->attributes |= RDATASET_ATTR_STALE;
+                        rbtnode->dirty = 1;
+                        if (log)
+                                isc_log_write(dns_lctx, category, module,
+                                              level, "overmem cache: stale %s",
+                                              printname);
+                } else if (force_expire) {
+                        if (! RETAIN(header)) {
+                                set_ttl(rbtdb, header, 0);
+                                header->attributes |= RDATASET_ATTR_STALE;
+                                rbtnode->dirty = 1;
+                        } else if (log) {
+                                isc_log_write(dns_lctx, category, module,
+                                              level, "overmem cache: "
+                                              "reprieve by RETAIN() %s",
+                                              printname);
+                        }
+                } else if (rbtdb->overmem && log)
+                        isc_log_write(dns_lctx, category, module, level,
+                                      "overmem cache: saved %s", printname);
+
+        NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
+                    isc_rwlocktype_write);
+
+        return (ISC_R_SUCCESS);
 }
 
 static void
 overmem(dns_db_t *db, isc_boolean_t overmem) {
-       dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
+        dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
+
+#ifdef LRU_DEBUG
+        /* XXX: see cache.c:timer_dump() */
+        if ((int)overmem == -1) {
+                if (!IS_CACHE(rbtdb) || db->rdclass != dns_rdataclass_in)
+                        return; /* for brevity */
+                isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+                              DNS_LOGMODULE_CACHE, ISC_LOG_INFO,
+                              "cache DB %p: mem inuse %lu, %u node, "
+                              "%d/%u current/total cache, %d/%u neg, %d/%u A, %d/%u AAAA, "
+                              "%d/%u NS, %d/%u PTR, %d/%u glue, "
+                              "%d/%u  additional, purge/scan=%u(%u expiry, %u lru)/%u, "
+                              "overmem=%d",
+                              rbtdb,
+                              (unsigned long)isc_mem_inuse(rbtdb->common.mctx),
+                              dns_rbt_nodecount(rbtdb->tree),
+                              rbtdb->cachestat.cache_current, rbtdb->cachestat.cache_total,
+                              rbtdb->cachestat.ncache_current, rbtdb->cachestat.ncache_total,
+                              rbtdb->cachestat.a_current, rbtdb->cachestat.a_total,
+                              rbtdb->cachestat.aaaa_current, rbtdb->cachestat.aaaa_total,
+                              rbtdb->cachestat.ns_current, rbtdb->cachestat.ns_total,
+                              rbtdb->cachestat.ptr_current, rbtdb->cachestat.ptr_total,
+                              rbtdb->cachestat.glue_current, rbtdb->cachestat.glue_total,
+                              rbtdb->cachestat.additional_current,
+                              rbtdb->cachestat.additional_total,
+                              rbtdb->cachestat.stale_purge, rbtdb->cachestat.stale_expire,
+                              rbtdb->cachestat.stale_lru, rbtdb->cachestat.stale_scan,
+                              rbtdb->overmem);
+                return;
+        }
+#endif
 
-       if (IS_CACHE(rbtdb)) {
-               rbtdb->overmem = overmem;
-       }
+        if (IS_CACHE(rbtdb)) {
+                rbtdb->overmem = overmem;
+        }
 }
 
 static void
 printnode(dns_db_t *db, dns_dbnode_t *node, FILE *out) {
-       dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
-       dns_rbtnode_t *rbtnode = node;
-       isc_boolean_t first;
-
-       REQUIRE(VALID_RBTDB(rbtdb));
-
-       NODE_LOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
-                 isc_rwlocktype_read);
-
-       fprintf(out, "node %p, %u references, locknum = %u\n",
-               rbtnode, dns_rbtnode_refcurrent(rbtnode),
-               rbtnode->locknum);
-       if (rbtnode->data != NULL) {
-               rdatasetheader_t *current, *top_next;
-
-               for (current = rbtnode->data; current != NULL;
-                    current = top_next) {
-                       top_next = current->next;
-                       first = ISC_TRUE;
-                       fprintf(out, "\ttype %u", current->type);
-                       do {
-                               if (!first)
-                                       fprintf(out, "\t");
-                               first = ISC_FALSE;
-                               fprintf(out,
-                                       "\tserial = %lu, ttl = %u, "
-                                       "trust = %u, attributes = %u\n",
-                                       (unsigned long)current->serial,
-                                       current->ttl,
-                                       current->trust,
-                                       current->attributes);
-                               current = current->down;
-                       } while (current != NULL);
-               }
-       } else
-               fprintf(out, "(empty)\n");
-
-       NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
-                   isc_rwlocktype_read);
+        dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
+        dns_rbtnode_t *rbtnode = node;
+        isc_boolean_t first;
+
+        REQUIRE(VALID_RBTDB(rbtdb));
+
+        NODE_LOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
+                  isc_rwlocktype_read);
+
+        fprintf(out, "node %p, %u references, locknum = %u\n",
+                rbtnode, dns_rbtnode_refcurrent(rbtnode),
+                rbtnode->locknum);
+        if (rbtnode->data != NULL) {
+                rdatasetheader_t *current, *top_next;
+
+                for (current = rbtnode->data; current != NULL;
+                     current = top_next) {
+                        top_next = current->next;
+                        first = ISC_TRUE;
+                        fprintf(out, "\ttype %u", current->type);
+                        do {
+                                if (!first)
+                                        fprintf(out, "\t");
+                                first = ISC_FALSE;
+                                fprintf(out,
+                                        "\tserial = %lu, ttl = %u, "
+                                        "trust = %u, attributes = %u\n",
+                                        (unsigned long)current->serial,
+                                        current->rdh_ttl,
+                                        current->trust,
+                                        current->attributes);
+                                current = current->down;
+                        } while (current != NULL);
+                }
+        } else
+                fprintf(out, "(empty)\n");
+
+        NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
+                    isc_rwlocktype_read);
 }
 
 static isc_result_t
 createiterator(dns_db_t *db, isc_boolean_t relative_names,
-              dns_dbiterator_t **iteratorp)
+               dns_dbiterator_t **iteratorp)
 {
-       dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
-       rbtdb_dbiterator_t *rbtdbiter;
-
-       REQUIRE(VALID_RBTDB(rbtdb));
-
-       rbtdbiter = isc_mem_get(rbtdb->common.mctx, sizeof(*rbtdbiter));
-       if (rbtdbiter == NULL)
-               return (ISC_R_NOMEMORY);
-
-       rbtdbiter->common.methods = &dbiterator_methods;
-       rbtdbiter->common.db = NULL;
-       dns_db_attach(db, &rbtdbiter->common.db);
-       rbtdbiter->common.relative_names = relative_names;
-       rbtdbiter->common.magic = DNS_DBITERATOR_MAGIC;
-       rbtdbiter->common.cleaning = ISC_FALSE;
-       rbtdbiter->paused = ISC_TRUE;
-       rbtdbiter->tree_locked = isc_rwlocktype_none;
-       rbtdbiter->result = ISC_R_SUCCESS;
-       dns_fixedname_init(&rbtdbiter->name);
-       dns_fixedname_init(&rbtdbiter->origin);
-       rbtdbiter->node = NULL;
-       rbtdbiter->delete = 0;
-       memset(rbtdbiter->deletions, 0, sizeof(rbtdbiter->deletions));
-       dns_rbtnodechain_init(&rbtdbiter->chain, db->mctx);
-
-       *iteratorp = (dns_dbiterator_t *)rbtdbiter;
-
-       return (ISC_R_SUCCESS);
+        dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
+        rbtdb_dbiterator_t *rbtdbiter;
+
+        REQUIRE(VALID_RBTDB(rbtdb));
+
+        rbtdbiter = isc_mem_get(rbtdb->common.mctx, sizeof(*rbtdbiter));
+        if (rbtdbiter == NULL)
+                return (ISC_R_NOMEMORY);
+
+        rbtdbiter->common.methods = &dbiterator_methods;
+        rbtdbiter->common.db = NULL;
+        dns_db_attach(db, &rbtdbiter->common.db);
+        rbtdbiter->common.relative_names = relative_names;
+        rbtdbiter->common.magic = DNS_DBITERATOR_MAGIC;
+        rbtdbiter->common.cleaning = ISC_FALSE;
+        rbtdbiter->paused = ISC_TRUE;
+        rbtdbiter->tree_locked = isc_rwlocktype_none;
+        rbtdbiter->result = ISC_R_SUCCESS;
+        dns_fixedname_init(&rbtdbiter->name);
+        dns_fixedname_init(&rbtdbiter->origin);
+        rbtdbiter->node = NULL;
+        rbtdbiter->delete = 0;
+        memset(rbtdbiter->deletions, 0, sizeof(rbtdbiter->deletions));
+        dns_rbtnodechain_init(&rbtdbiter->chain, db->mctx);
+
+        *iteratorp = (dns_dbiterator_t *)rbtdbiter;
+
+        return (ISC_R_SUCCESS);
 }
 
 static isc_result_t
 zone_findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
-                 dns_rdatatype_t type, dns_rdatatype_t covers,
-                 isc_stdtime_t now, dns_rdataset_t *rdataset,
-                 dns_rdataset_t *sigrdataset)
+                  dns_rdatatype_t type, dns_rdatatype_t covers,
+                  isc_stdtime_t now, dns_rdataset_t *rdataset,
+                  dns_rdataset_t *sigrdataset)
 {
-       dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
-       dns_rbtnode_t *rbtnode = (dns_rbtnode_t *)node;
-       rdatasetheader_t *header, *header_next, *found, *foundsig;
-       rbtdb_serial_t serial;
-       rbtdb_version_t *rbtversion = version;
-       isc_boolean_t close_version = ISC_FALSE;
-       rbtdb_rdatatype_t matchtype, sigmatchtype;
-
-       REQUIRE(VALID_RBTDB(rbtdb));
-       REQUIRE(type != dns_rdatatype_any);
-
-       if (rbtversion == NULL) {
-               currentversion(db, (dns_dbversion_t **) (void *)(&rbtversion));
-               close_version = ISC_TRUE;
-       }
-       serial = rbtversion->serial;
-       now = 0;
-
-       NODE_LOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
-                 isc_rwlocktype_read);
-
-       found = NULL;
-       foundsig = NULL;
-       matchtype = RBTDB_RDATATYPE_VALUE(type, covers);
-       if (covers == 0)
-               sigmatchtype = RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, type);
-       else
-               sigmatchtype = 0;
-
-       for (header = rbtnode->data; header != NULL; header = header_next) {
-               header_next = header->next;
-               do {
-                       if (header->serial <= serial &&
-                           !IGNORE(header)) {
-                               /*
-                                * Is this a "this rdataset doesn't
-                                * exist" record?
-                                */
-                               if (NONEXISTENT(header))
-                                       header = NULL;
-                               break;
-                       } else
-                               header = header->down;
-               } while (header != NULL);
-               if (header != NULL) {
-                       /*
-                        * We have an active, extant rdataset.  If it's a
-                        * type we're looking for, remember it.
-                        */
-                       if (header->type == matchtype) {
-                               found = header;
-                               if (foundsig != NULL)
-                                       break;
-                       } else if (header->type == sigmatchtype) {
-                               foundsig = header;
-                               if (found != NULL)
-                                       break;
-                       }
-               }
-       }
-       if (found != NULL) {
-               bind_rdataset(rbtdb, rbtnode, found, now, rdataset);
-               if (foundsig != NULL)
-                       bind_rdataset(rbtdb, rbtnode, foundsig, now,
-                                     sigrdataset);
-       }
-
-       NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
-                   isc_rwlocktype_read);
-
-       if (close_version)
-               closeversion(db, (dns_dbversion_t **) (void *)(&rbtversion),
-                            ISC_FALSE);
-
-       if (found == NULL)
-               return (ISC_R_NOTFOUND);
-
-       return (ISC_R_SUCCESS);
+        dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
+        dns_rbtnode_t *rbtnode = (dns_rbtnode_t *)node;
+        rdatasetheader_t *header, *header_next, *found, *foundsig;
+        rbtdb_serial_t serial;
+        rbtdb_version_t *rbtversion = version;
+        isc_boolean_t close_version = ISC_FALSE;
+        rbtdb_rdatatype_t matchtype, sigmatchtype;
+
+        REQUIRE(VALID_RBTDB(rbtdb));
+        REQUIRE(type != dns_rdatatype_any);
+
+        if (rbtversion == NULL) {
+                currentversion(db, (dns_dbversion_t **) (void *)(&rbtversion));
+                close_version = ISC_TRUE;
+        }
+        serial = rbtversion->serial;
+        now = 0;
+
+        NODE_LOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
+                  isc_rwlocktype_read);
+
+        found = NULL;
+        foundsig = NULL;
+        matchtype = RBTDB_RDATATYPE_VALUE(type, covers);
+        if (covers == 0)
+                sigmatchtype = RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, type);
+        else
+                sigmatchtype = 0;
+
+        for (header = rbtnode->data; header != NULL; header = header_next) {
+                header_next = header->next;
+                do {
+                        if (header->serial <= serial &&
+                            !IGNORE(header)) {
+                                /*
+                                 * Is this a "this rdataset doesn't
+                                 * exist" record?
+                                 */
+                                if (NONEXISTENT(header))
+                                        header = NULL;
+                                break;
+                        } else
+                                header = header->down;
+                } while (header != NULL);
+                if (header != NULL) {
+                        /*
+                         * We have an active, extant rdataset.  If it's a
+                         * type we're looking for, remember it.
+                         */
+                        if (header->type == matchtype) {
+                                found = header;
+                                if (foundsig != NULL)
+                                        break;
+                        } else if (header->type == sigmatchtype) {
+                                foundsig = header;
+                                if (found != NULL)
+                                        break;
+                        }
+                }
+        }
+        if (found != NULL) {
+                bind_rdataset(rbtdb, rbtnode, found, now, rdataset);
+                if (foundsig != NULL)
+                        bind_rdataset(rbtdb, rbtnode, foundsig, now,
+                                      sigrdataset);
+        }
+
+        NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
+                    isc_rwlocktype_read);
+
+        if (close_version)
+                closeversion(db, (dns_dbversion_t **) (void *)(&rbtversion),
+                             ISC_FALSE);
+
+        if (found == NULL)
+                return (ISC_R_NOTFOUND);
+
+        return (ISC_R_SUCCESS);
 }
 
 static isc_result_t
 cache_findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
-                  dns_rdatatype_t type, dns_rdatatype_t covers,
-                  isc_stdtime_t now, dns_rdataset_t *rdataset,
-                  dns_rdataset_t *sigrdataset)
+                   dns_rdatatype_t type, dns_rdatatype_t covers,
+                   isc_stdtime_t now, dns_rdataset_t *rdataset,
+                   dns_rdataset_t *sigrdataset)
 {
-       dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
-       dns_rbtnode_t *rbtnode = (dns_rbtnode_t *)node;
-       rdatasetheader_t *header, *header_next, *found, *foundsig;
-       rbtdb_rdatatype_t matchtype, sigmatchtype, negtype;
-       isc_result_t result;
-       nodelock_t *lock;
-       isc_rwlocktype_t locktype;
-
-       REQUIRE(VALID_RBTDB(rbtdb));
-       REQUIRE(type != dns_rdatatype_any);
-
-       UNUSED(version);
-
-       result = ISC_R_SUCCESS;
-
-       if (now == 0)
-               isc_stdtime_get(&now);
-
-       lock = &rbtdb->node_locks[rbtnode->locknum].lock;
-       locktype = isc_rwlocktype_read;
-       NODE_LOCK(lock, locktype);
-
-       found = NULL;
-       foundsig = NULL;
-       matchtype = RBTDB_RDATATYPE_VALUE(type, covers);
-       negtype = RBTDB_RDATATYPE_VALUE(0, type);
-       if (covers == 0)
-               sigmatchtype = RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, type);
-       else
-               sigmatchtype = 0;
-
-       for (header = rbtnode->data; header != NULL; header = header_next) {
-               header_next = header->next;
-               if (header->ttl <= now) {
-                       if ((header->ttl <= now - RBTDB_VIRTUAL) &&
-                           (locktype == isc_rwlocktype_write ||
-                            NODE_TRYUPGRADE(lock) == ISC_R_SUCCESS)) {
-                               /*
-                                * We update the node's status only when we
-                                * can get write access.
-                                */
-                               locktype = isc_rwlocktype_write;
-                               
-                               /*
-                                * We don't check if refcurrent(rbtnode) == 0
-                                * and try to free like we do in cache_find(),
-                                * because refcurrent(rbtnode) must be
-                                * non-zero.  This is so because 'node' is an
-                                * argument to the function.
-                                */
-                               header->attributes |= RDATASET_ATTR_STALE;
-                               rbtnode->dirty = 1;
-                       }
-               } else if (EXISTS(header)) {
-                       if (header->type == matchtype)
-                               found = header;
-                       else if (header->type == RBTDB_RDATATYPE_NCACHEANY ||
-                                header->type == negtype)
-                               found = header;
-                       else if (header->type == sigmatchtype)
-                               foundsig = header;
-               }
-       }
-       if (found != NULL) {
-               bind_rdataset(rbtdb, rbtnode, found, now, rdataset);
-               if (foundsig != NULL)
-                       bind_rdataset(rbtdb, rbtnode, foundsig, now,
-                                     sigrdataset);
-       }
-
-       NODE_UNLOCK(lock, locktype);
-
-       if (found == NULL)
-               return (ISC_R_NOTFOUND);
-
-       if (RBTDB_RDATATYPE_BASE(found->type) == 0) {
-               /*
-                * We found a negative cache entry.
-                */
-               if (NXDOMAIN(found))
-                       result = DNS_R_NCACHENXDOMAIN;
-               else
-                       result = DNS_R_NCACHENXRRSET;
-       }
-
-       return (result);
+        dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
+        dns_rbtnode_t *rbtnode = (dns_rbtnode_t *)node;
+        rdatasetheader_t *header, *header_next, *found, *foundsig;
+        rbtdb_rdatatype_t matchtype, sigmatchtype, negtype;
+        isc_result_t result;
+        nodelock_t *lock;
+        isc_rwlocktype_t locktype;
+
+        REQUIRE(VALID_RBTDB(rbtdb));
+        REQUIRE(type != dns_rdatatype_any);
+
+        UNUSED(version);
+
+        result = ISC_R_SUCCESS;
+
+        if (now == 0)
+                isc_stdtime_get(&now);
+
+        lock = &rbtdb->node_locks[rbtnode->locknum].lock;
+        locktype = isc_rwlocktype_read;
+        NODE_LOCK(lock, locktype);
+
+        found = NULL;
+        foundsig = NULL;
+        matchtype = RBTDB_RDATATYPE_VALUE(type, covers);
+        negtype = RBTDB_RDATATYPE_VALUE(0, type);
+        if (covers == 0)
+                sigmatchtype = RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, type);
+        else
+                sigmatchtype = 0;
+
+        for (header = rbtnode->data; header != NULL; header = header_next) {
+                header_next = header->next;
+                if (header->rdh_ttl <= now) {
+                        if ((header->rdh_ttl <= now - RBTDB_VIRTUAL) &&
+                            (locktype == isc_rwlocktype_write ||
+                             NODE_TRYUPGRADE(lock) == ISC_R_SUCCESS)) {
+                                /*
+                                 * We update the node's status only when we
+                                 * can get write access.
+                                 */
+                                locktype = isc_rwlocktype_write;
+
+                                /*
+                                 * We don't check if refcurrent(rbtnode) == 0
+                                 * and try to free like we do in cache_find(),
+                                 * because refcurrent(rbtnode) must be
+                                 * non-zero.  This is so because 'node' is an
+                                 * argument to the function.
+                                 */
+                                header->attributes |= RDATASET_ATTR_STALE;
+                                rbtnode->dirty = 1;
+                        }
+                } else if (EXISTS(header)) {
+                        if (header->type == matchtype)
+                                found = header;
+                        else if (header->type == RBTDB_RDATATYPE_NCACHEANY ||
+                                 header->type == negtype)
+                                found = header;
+                        else if (header->type == sigmatchtype)
+                                foundsig = header;
+                }
+        }
+        if (found != NULL) {
+                bind_rdataset(rbtdb, rbtnode, found, now, rdataset);
+                if (foundsig != NULL)
+                        bind_rdataset(rbtdb, rbtnode, foundsig, now,
+                                      sigrdataset);
+        }
+
+        NODE_UNLOCK(lock, locktype);
+
+        if (found == NULL)
+                return (ISC_R_NOTFOUND);
+
+        if (RBTDB_RDATATYPE_BASE(found->type) == 0) {
+                /*
+                 * We found a negative cache entry.
+                 */
+                if (NXDOMAIN(found))
+                        result = DNS_R_NCACHENXDOMAIN;
+                else
+                        result = DNS_R_NCACHENXRRSET;
+        }
+
+        return (result);
 }
 
 static isc_result_t
 allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
-            isc_stdtime_t now, dns_rdatasetiter_t **iteratorp)
+             isc_stdtime_t now, dns_rdatasetiter_t **iteratorp)
 {
-       dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
-       dns_rbtnode_t *rbtnode = (dns_rbtnode_t *)node;
-       rbtdb_version_t *rbtversion = version;
-       rbtdb_rdatasetiter_t *iterator;
-       unsigned int refs;
-
-       REQUIRE(VALID_RBTDB(rbtdb));
-
-       iterator = isc_mem_get(rbtdb->common.mctx, sizeof(*iterator));
-       if (iterator == NULL)
-               return (ISC_R_NOMEMORY);
-
-       if ((db->attributes & DNS_DBATTR_CACHE) == 0) {
-               now = 0;
-               if (rbtversion == NULL)
-                       currentversion(db,
-                                (dns_dbversion_t **) (void *)(&rbtversion));
-               else {
-                       unsigned int refs;
-
-                       isc_refcount_increment(&rbtversion->references,
-                                              &refs);
-                       INSIST(refs > 1);
-               }
-       } else {
-               if (now == 0)
-                       isc_stdtime_get(&now);
-               rbtversion = NULL;
-       }
-
-       iterator->common.magic = DNS_RDATASETITER_MAGIC;
-       iterator->common.methods = &rdatasetiter_methods;
-       iterator->common.db = db;
-       iterator->common.node = node;
-       iterator->common.version = (dns_dbversion_t *)rbtversion;
-       iterator->common.now = now;
-
-       NODE_STRONGLOCK(&rbtdb->node_locks[rbtnode->locknum].lock);
-
-       dns_rbtnode_refincrement(rbtnode, &refs);
-       INSIST(refs != 0);
-
-       iterator->current = NULL;
-
-       NODE_STRONGUNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock);
-
-       *iteratorp = (dns_rdatasetiter_t *)iterator;
-
-       return (ISC_R_SUCCESS);
+        dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
+        dns_rbtnode_t *rbtnode = (dns_rbtnode_t *)node;
+        rbtdb_version_t *rbtversion = version;
+        rbtdb_rdatasetiter_t *iterator;
+        unsigned int refs;
+
+        REQUIRE(VALID_RBTDB(rbtdb));
+
+        iterator = isc_mem_get(rbtdb->common.mctx, sizeof(*iterator));
+        if (iterator == NULL)
+                return (ISC_R_NOMEMORY);
+
+        if ((db->attributes & DNS_DBATTR_CACHE) == 0) {
+                now = 0;
+                if (rbtversion == NULL)
+                        currentversion(db,
+                                 (dns_dbversion_t **) (void *)(&rbtversion));
+                else {
+                        unsigned int refs;
+
+                        isc_refcount_increment(&rbtversion->references,
+                                               &refs);
+                        INSIST(refs > 1);
+                }
+        } else {
+                if (now == 0)
+                        isc_stdtime_get(&now);
+                rbtversion = NULL;
+        }
+
+        iterator->common.magic = DNS_RDATASETITER_MAGIC;
+        iterator->common.methods = &rdatasetiter_methods;
+        iterator->common.db = db;
+        iterator->common.node = node;
+        iterator->common.version = (dns_dbversion_t *)rbtversion;
+        iterator->common.now = now;
+
+        NODE_STRONGLOCK(&rbtdb->node_locks[rbtnode->locknum].lock);
+
+        dns_rbtnode_refincrement(rbtnode, &refs);
+        INSIST(refs != 0);
+
+        iterator->current = NULL;
+
+        NODE_STRONGUNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock);
+
+        *iteratorp = (dns_rdatasetiter_t *)iterator;
+
+        return (ISC_R_SUCCESS);
 }
 
 static isc_boolean_t
 cname_and_other_data(dns_rbtnode_t *node, rbtdb_serial_t serial) {
-       rdatasetheader_t *header, *header_next;
-       isc_boolean_t cname, other_data;
-       dns_rdatatype_t rdtype;
-
-       /*
-        * The caller must hold the node lock.
-        */
-
-       /*
-        * Look for CNAME and "other data" rdatasets active in our version.
-        */
-       cname = ISC_FALSE;
-       other_data = ISC_FALSE;
-       for (header = node->data; header != NULL; header = header_next) {
-               header_next = header->next;
-               if (header->type == dns_rdatatype_cname) {
-                       /*
-                        * Look for an active extant CNAME.
-                        */
-                       do {
-                               if (header->serial <= serial &&
-                                   !IGNORE(header)) {
-                                       /*
-                                        * Is this a "this rdataset doesn't
-                                        * exist" record?
-                                        */
-                                       if (NONEXISTENT(header))
-                                               header = NULL;
-                                       break;
-                               } else
-                                       header = header->down;
-                       } while (header != NULL);
-                       if (header != NULL)
-                               cname = ISC_TRUE;
-               } else {
-                       /*
-                        * Look for active extant "other data".
-                        *
-                        * "Other data" is any rdataset whose type is not
-                        * KEY, RRSIG KEY, NSEC, RRSIG NSEC or RRSIG CNAME.
-                        */
-                       rdtype = RBTDB_RDATATYPE_BASE(header->type);
-                       if (rdtype == dns_rdatatype_rrsig ||
-                           rdtype == dns_rdatatype_sig)
-                               rdtype = RBTDB_RDATATYPE_EXT(header->type);
-                       if (rdtype != dns_rdatatype_nsec &&
-                           rdtype != dns_rdatatype_key &&
-                           rdtype != dns_rdatatype_cname) {
-                               /*
-                                * We've found a type that isn't
-                                * NSEC, KEY, CNAME, or one of their
-                                * signatures.  Is it active and extant?
-                                */
-                               do {
-                                       if (header->serial <= serial &&
-                                           !IGNORE(header)) {
-                                               /*
-                                                * Is this a "this rdataset
-                                                * doesn't exist" record?
-                                                */
-                                               if (NONEXISTENT(header))
-                                                       header = NULL;
-                                               break;
-                                       } else
-                                               header = header->down;
-                               } while (header != NULL);
-                               if (header != NULL)
-                                       other_data = ISC_TRUE;
-                       }
-               }
-       }
-
-       if (cname && other_data)
-               return (ISC_TRUE);
-
-       return (ISC_FALSE);
+        rdatasetheader_t *header, *header_next;
+        isc_boolean_t cname, other_data;
+        dns_rdatatype_t rdtype;
+
+        /*
+         * The caller must hold the node lock.
+         */
+
+        /*
+         * Look for CNAME and "other data" rdatasets active in our version.
+         */
+        cname = ISC_FALSE;
+        other_data = ISC_FALSE;
+        for (header = node->data; header != NULL; header = header_next) {
+                header_next = header->next;
+                if (header->type == dns_rdatatype_cname) {
+                        /*
+                         * Look for an active extant CNAME.
+                         */
+                        do {
+                                if (header->serial <= serial &&
+                                    !IGNORE(header)) {
+                                        /*
+                                         * Is this a "this rdataset doesn't
+                                         * exist" record?
+                                         */
+                                        if (NONEXISTENT(header))
+                                                header = NULL;
+                                        break;
+                                } else
+                                        header = header->down;
+                        } while (header != NULL);
+                        if (header != NULL)
+                                cname = ISC_TRUE;
+                } else {
+                        /*
+                         * Look for active extant "other data".
+                         *
+                         * "Other data" is any rdataset whose type is not
+                         * KEY, RRSIG KEY, NSEC, RRSIG NSEC or RRSIG CNAME.
+                         */
+                        rdtype = RBTDB_RDATATYPE_BASE(header->type);
+                        if (rdtype == dns_rdatatype_rrsig ||
+                            rdtype == dns_rdatatype_sig)
+                                rdtype = RBTDB_RDATATYPE_EXT(header->type);
+                        if (rdtype != dns_rdatatype_nsec &&
+                            rdtype != dns_rdatatype_key &&
+                            rdtype != dns_rdatatype_cname) {
+                                /*
+                                 * We've found a type that isn't
+                                 * NSEC, KEY, CNAME, or one of their
+                                 * signatures.  Is it active and extant?
+                                 */
+                                do {
+                                        if (header->serial <= serial &&
+                                            !IGNORE(header)) {
+                                                /*
+                                                 * Is this a "this rdataset
+                                                 * doesn't exist" record?
+                                                 */
+                                                if (NONEXISTENT(header))
+                                                        header = NULL;
+                                                break;
+                                        } else
+                                                header = header->down;
+                                } while (header != NULL);
+                                if (header != NULL)
+                                        other_data = ISC_TRUE;
+                        }
+                }
+        }
+
+        if (cname && other_data)
+                return (ISC_TRUE);
+
+        return (ISC_FALSE);
+}
+
+#ifdef LRU_DEBUG
+static void
+cachestat_update(dns_rbtdb_t *rbtdb, rdatasetheader_t *header) {
+        if ((header->attributes & RDATASET_ATTR_CACHE) == 0)
+                return;
+
+        /* XXX: don't use lock for brevity */
+        rbtdb->cachestat.cache_total++;
+        if (RBTDB_RDATATYPE_BASE(header->type) == 0)
+                        rbtdb->cachestat.ncache_total++;
+        if (header->type == dns_rdatatype_a)
+                        rbtdb->cachestat.a_total++;
+        else if (header->type == dns_rdatatype_aaaa)
+                rbtdb->cachestat.aaaa_total++;
+        else if (header->type == dns_rdatatype_ns)
+                rbtdb->cachestat.ns_total++;
+        else if (header->type == dns_rdatatype_ptr)
+                rbtdb->cachestat.ptr_total++;
+
+        if (header->trust == dns_trust_glue &&
+            (header->type == dns_rdatatype_a ||
+             header->type == dns_rdatatype_aaaa)) {
+                rbtdb->cachestat.glue_total++;
+        }
+        if (header->trust == dns_trust_additional &&
+            (header->type == dns_rdatatype_a ||
+             header->type == dns_rdatatype_aaaa)) {
+                rbtdb->cachestat.additional_total++;
+        }
 }
+#endif
 
 static isc_result_t
 add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion,
     rdatasetheader_t *newheader, unsigned int options, isc_boolean_t loading,
     dns_rdataset_t *addedrdataset, isc_stdtime_t now)
 {
-       rbtdb_changed_t *changed = NULL;
-       rdatasetheader_t *topheader, *topheader_prev, *header;
-       unsigned char *merged;
-       isc_result_t result;
-       isc_boolean_t header_nx;
-       isc_boolean_t newheader_nx;
-       isc_boolean_t merge;
-       dns_rdatatype_t rdtype, covers;
-       rbtdb_rdatatype_t negtype;
-       dns_trust_t trust;
-
-       /*
-        * Add an rdatasetheader_t to a node.
-        */
-
-       /*
-        * Caller must be holding the node lock.
-        */
-
-       if ((options & DNS_DBADD_MERGE) != 0) {
-               REQUIRE(rbtversion != NULL);
-               merge = ISC_TRUE;
-       } else
-               merge = ISC_FALSE;
-
-       if ((options & DNS_DBADD_FORCE) != 0)
-               trust = dns_trust_ultimate;
-       else
-               trust = newheader->trust;
-
-       if (rbtversion != NULL && !loading) {
-               /*
-                * We always add a changed record, even if no changes end up
-                * being made to this node, because it's harmless and
-                * simplifies the code.
-                */
-               changed = add_changed(rbtdb, rbtversion, rbtnode);
-               if (changed == NULL) {
-                       free_rdataset(rbtdb->common.mctx, newheader);
-                       return (ISC_R_NOMEMORY);
-               }
-       }
-
-       newheader_nx = NONEXISTENT(newheader) ? ISC_TRUE : ISC_FALSE;
-       topheader_prev = NULL;
-
-       negtype = 0;
-       if (rbtversion == NULL && !newheader_nx) {
-               rdtype = RBTDB_RDATATYPE_BASE(newheader->type);
-               if (rdtype == 0) {
-                       /*
-                        * We're adding a negative cache entry.
-                        */
-                       covers = RBTDB_RDATATYPE_EXT(newheader->type);
-                       if (covers == dns_rdatatype_any) {
-                               /*
-                                * We're adding an negative cache entry
-                                * which covers all types (NXDOMAIN,
-                                * NODATA(QTYPE=ANY)).
-                                *
-                                * We make all other data stale so that the
-                                * only rdataset that can be found at this
-                                * node is the negative cache entry.
-                                */
-                               for (topheader = rbtnode->data;
-                                    topheader != NULL;
-                                    topheader = topheader->next) {
-                                       topheader->ttl = 0;
-                                       topheader->attributes |=
-                                               RDATASET_ATTR_STALE;
-                               }
-                               rbtnode->dirty = 1;
-                               goto find_header;
-                       }
-                       negtype = RBTDB_RDATATYPE_VALUE(covers, 0);
-               } else {
-                       /*
-                        * We're adding something that isn't a
-                        * negative cache entry.  Look for an extant
-                        * non-stale NXDOMAIN/NODATA(QTYPE=ANY) negative
-                        * cache entry.
-                        */
-                       for (topheader = rbtnode->data;
-                            topheader != NULL;
-                            topheader = topheader->next) {
-                               if (topheader->type == 
-                                   RBTDB_RDATATYPE_NCACHEANY)
-                                       break;
-                       }
-                       if (topheader != NULL && EXISTS(topheader) &&
-                           topheader->ttl > now) {
-                               /*
-                                * Found one.
-                                */
-                               if (trust < topheader->trust) {
-                                       /*
-                                        * The NXDOMAIN/NODATA(QTYPE=ANY)
-                                        * is more trusted.
-                                        */
-                                       
-                                       free_rdataset(rbtdb->common.mctx,
-                                                     newheader);
-                                       if (addedrdataset != NULL)
-                                               bind_rdataset(rbtdb, rbtnode,
-                                                             topheader, now,
-                                                             addedrdataset);
-                                       return (DNS_R_UNCHANGED);
-                               }
-                               /*
-                                * The new rdataset is better.  Expire the
-                                * NXDOMAIN/NODATA(QTYPE=ANY).
-                                */
-                               topheader->ttl = 0;
-                               topheader->attributes |= RDATASET_ATTR_STALE;
-                               rbtnode->dirty = 1;
-                               topheader = NULL;
-                               goto find_header;
-                       }
-                       negtype = RBTDB_RDATATYPE_VALUE(0, rdtype);
-               }
-       }
-
-       for (topheader = rbtnode->data;
-            topheader != NULL;
-            topheader = topheader->next) {
-               if (topheader->type == newheader->type ||
-                   topheader->type == negtype)
-                       break;
-               topheader_prev = topheader;
-       }
+        rbtdb_changed_t *changed = NULL;
+        rdatasetheader_t *topheader, *topheader_prev, *header;
+        unsigned char *merged;
+        isc_result_t result;
+        isc_boolean_t header_nx;
+        isc_boolean_t newheader_nx;
+        isc_boolean_t merge;
+        dns_rdatatype_t rdtype, covers;
+        rbtdb_rdatatype_t negtype;
+        dns_trust_t trust;
+
+        /*
+         * Add an rdatasetheader_t to a node.
+         */
+
+        /*
+         * Caller must be holding the node lock.
+         */
+
+        if ((options & DNS_DBADD_MERGE) != 0) {
+                REQUIRE(rbtversion != NULL);
+                merge = ISC_TRUE;
+        } else
+                merge = ISC_FALSE;
+
+        if ((options & DNS_DBADD_FORCE) != 0)
+                trust = dns_trust_ultimate;
+        else
+                trust = newheader->trust;
+
+        if (rbtversion != NULL && !loading) {
+                /*
+                 * We always add a changed record, even if no changes end up
+                 * being made to this node, because it's harmless and
+                 * simplifies the code.
+                 */
+                changed = add_changed(rbtdb, rbtversion, rbtnode);
+                if (changed == NULL) {
+                        free_rdataset(rbtdb, rbtdb->common.mctx, newheader);
+                        return (ISC_R_NOMEMORY);
+                }
+        }
+
+        newheader_nx = NONEXISTENT(newheader) ? ISC_TRUE : ISC_FALSE;
+        topheader_prev = NULL;
+
+        negtype = 0;
+        if (rbtversion == NULL && !newheader_nx) {
+                rdtype = RBTDB_RDATATYPE_BASE(newheader->type);
+                if (rdtype == 0) {
+                        /*
+                         * We're adding a negative cache entry.
+                         */
+                        covers = RBTDB_RDATATYPE_EXT(newheader->type);
+                        if (covers == dns_rdatatype_any) {
+                                /*
+                                 * We're adding an negative cache entry
+                                 * which covers all types (NXDOMAIN,
+                                 * NODATA(QTYPE=ANY)).
+                                 *
+                                 * We make all other data stale so that the
+                                 * only rdataset that can be found at this
+                                 * node is the negative cache entry.
+                                 */
+                                for (topheader = rbtnode->data;
+                                     topheader != NULL;
+                                     topheader = topheader->next) {
+                                        set_ttl(rbtdb, topheader, 0);
+                                        topheader->attributes |=
+                                                RDATASET_ATTR_STALE;
+                                }
+                                rbtnode->dirty = 1;
+                                goto find_header;
+                        }
+                        negtype = RBTDB_RDATATYPE_VALUE(covers, 0);
+                } else {
+                        /*
+                         * We're adding something that isn't a
+                         * negative cache entry.  Look for an extant
+                         * non-stale NXDOMAIN/NODATA(QTYPE=ANY) negative
+                         * cache entry.
+                         */
+                        for (topheader = rbtnode->data;
+                             topheader != NULL;
+                             topheader = topheader->next) {
+                                if (topheader->type ==
+                                    RBTDB_RDATATYPE_NCACHEANY)
+                                        break;
+                        }
+                        if (topheader != NULL && EXISTS(topheader) &&
+                            topheader->rdh_ttl > now) {
+                                /*
+                                 * Found one.
+                                 */
+                                if (trust < topheader->trust) {
+                                        /*
+                                         * The NXDOMAIN/NODATA(QTYPE=ANY)
+                                         * is more trusted.
+                                         */
+                                        /* set the flag for debug */
+                                        newheader->attributes |=
+                                                RDATASET_ATTR_CANCELED;
+                                        free_rdataset(rbtdb,
+                                                      rbtdb->common.mctx,
+                                                      newheader);
+                                        if (addedrdataset != NULL)
+                                                bind_rdataset(rbtdb, rbtnode,
+                                                              topheader, now,
+                                                              addedrdataset);
+                                        return (DNS_R_UNCHANGED);
+                                }
+                                /*
+                                 * The new rdataset is better.  Expire the
+                                 * NXDOMAIN/NODATA(QTYPE=ANY).
+                                 */
+                                set_ttl(rbtdb, topheader, 0);
+                                topheader->attributes |= RDATASET_ATTR_STALE;
+                                rbtnode->dirty = 1;
+                                topheader = NULL;
+                                goto find_header;
+                        }
+                        negtype = RBTDB_RDATATYPE_VALUE(0, rdtype);
+                }
+        }
+
+        for (topheader = rbtnode->data;
+             topheader != NULL;
+             topheader = topheader->next) {
+                if (topheader->type == newheader->type ||
+                    topheader->type == negtype)
+                        break;
+                topheader_prev = topheader;
+        }
 
  find_header:
-       /*
-        * If header isn't NULL, we've found the right type.  There may be
-        * IGNORE rdatasets between the top of the chain and the first real
-        * data.  We skip over them.
-        */
-       header = topheader;
-       while (header != NULL && IGNORE(header))
-               header = header->down;
-       if (header != NULL) {
-               header_nx = NONEXISTENT(header) ? ISC_TRUE : ISC_FALSE;
-
-               /*
-                * Deleting an already non-existent rdataset has no effect.
-                */
-               if (header_nx && newheader_nx) {
-                       free_rdataset(rbtdb->common.mctx, newheader);
-                       return (DNS_R_UNCHANGED);
-               }
-
-               /*
-                * Trying to add an rdataset with lower trust to a cache DB
-                * has no effect, provided that the cache data isn't stale.
-                */
-               if (rbtversion == NULL && trust < header->trust &&
-                   (header->ttl > now || header_nx)) {
-                       free_rdataset(rbtdb->common.mctx, newheader);
-                       if (addedrdataset != NULL)
-                               bind_rdataset(rbtdb, rbtnode, header, now,
-                                             addedrdataset);
-                       return (DNS_R_UNCHANGED);
-               }
-
-               /*
-                * Don't merge if a nonexistent rdataset is involved.
-                */
-               if (merge && (header_nx || newheader_nx))
-                       merge = ISC_FALSE;
-
-               /*
-                * If 'merge' is ISC_TRUE, we'll try to create a new rdataset
-                * that is the union of 'newheader' and 'header'.
-                */
-               if (merge) {
-                       unsigned int flags = 0;
-                       INSIST(rbtversion->serial >= header->serial);
-                       merged = NULL;
-                       result = ISC_R_SUCCESS;
-                       
-                       if ((options & DNS_DBADD_EXACT) != 0)
-                               flags |= DNS_RDATASLAB_EXACT;
-                       if ((options & DNS_DBADD_EXACTTTL) != 0 &&
-                            newheader->ttl != header->ttl)
-                                       result = DNS_R_NOTEXACT;
-                       else if (newheader->ttl != header->ttl)
-                               flags |= DNS_RDATASLAB_FORCE;
-                       if (result == ISC_R_SUCCESS)
-                               result = dns_rdataslab_merge(
-                                            (unsigned char *)header,
-                                            (unsigned char *)newheader,
-                                            (unsigned int)(sizeof(*newheader)),
-                                            rbtdb->common.mctx,
-                                            rbtdb->common.rdclass,
-                                            (dns_rdatatype_t)header->type,
-                                            flags, &merged);
-                       if (result == ISC_R_SUCCESS) {
-                               /*
-                                * If 'header' has the same serial number as
-                                * we do, we could clean it up now if we knew
-                                * that our caller had no references to it.
-                                * We don't know this, however, so we leave it
-                                * alone.  It will get cleaned up when
-                                * clean_zone_node() runs.
-                                */
-                               free_rdataset(rbtdb->common.mctx, newheader);
-                               newheader = (rdatasetheader_t *)merged;
-                       } else {
-                               free_rdataset(rbtdb->common.mctx, newheader);
-                               return (result);
-                       }
-               }
-               /*
-                * Don't replace existing NS, A and AAAA RRsets
-                * in the cache if they are already exist.  This
-                * prevents named being locked to old servers.
-                * Don't lower trust of existing record if the
-                * update is forced.
-                */
-               if (IS_CACHE(rbtdb) && header->ttl > now &&
-                   header->type == dns_rdatatype_ns &&
-                   !header_nx && !newheader_nx &&
-                   header->trust >= newheader->trust &&
-                   dns_rdataslab_equalx((unsigned char *)header,
-                                        (unsigned char *)newheader,
-                                        (unsigned int)(sizeof(*newheader)),
-                                        rbtdb->common.rdclass,
-                                        (dns_rdatatype_t)header->type)) {
-                       /*
-                        * Honour the new ttl if it is less than the
-                        * older one.
-                        */
-                       if (header->ttl > newheader->ttl)
-                               header->ttl = newheader->ttl;
-                       if (header->noqname == NULL &&
-                           newheader->noqname != NULL) {
-                               header->noqname = newheader->noqname;
-                               newheader->noqname = NULL;
-                       }
-                       free_rdataset(rbtdb->common.mctx, newheader);
-                       if (addedrdataset != NULL)
-                               bind_rdataset(rbtdb, rbtnode, header, now,
-                                             addedrdataset);
-                       return (ISC_R_SUCCESS);
-               }
-               if (IS_CACHE(rbtdb) && header->ttl > now &&
-                   (header->type == dns_rdatatype_a ||
-                    header->type == dns_rdatatype_aaaa) &&
-                   !header_nx && !newheader_nx &&
-                   header->trust >= newheader->trust &&
-                   dns_rdataslab_equal((unsigned char *)header,
-                                       (unsigned char *)newheader,
-                                       (unsigned int)(sizeof(*newheader)))) {
-                       /*
-                        * Honour the new ttl if it is less than the
-                        * older one.
-                        */
-                       if (header->ttl > newheader->ttl)
-                               header->ttl = newheader->ttl;
-                       if (header->noqname == NULL &&
-                           newheader->noqname != NULL) {
-                               header->noqname = newheader->noqname;
-                               newheader->noqname = NULL;
-                       }
-                       free_rdataset(rbtdb->common.mctx, newheader);
-                       if (addedrdataset != NULL)
-                               bind_rdataset(rbtdb, rbtnode, header, now,
-                                             addedrdataset);
-                       return (ISC_R_SUCCESS);
-               }
-               INSIST(rbtversion == NULL ||
-                      rbtversion->serial >= topheader->serial);
-               if (topheader_prev != NULL)
-                       topheader_prev->next = newheader;
-               else
-                       rbtnode->data = newheader;
-               newheader->next = topheader->next;
-               if (loading) {
-                       /*
-                        * There are no other references to 'header' when
-                        * loading, so we MAY clean up 'header' now.
-                        * Since we don't generate changed records when
-                        * loading, we MUST clean up 'header' now.
-                        */
-                       newheader->down = NULL;
-                       free_rdataset(rbtdb->common.mctx, header);
-               } else {
-                       newheader->down = topheader;
-                       topheader->next = newheader;
-                       rbtnode->dirty = 1;
-                       if (changed != NULL)
-                               changed->dirty = ISC_TRUE;
-                       if (rbtversion == NULL) {
-                               header->ttl = 0;
-                               header->attributes |= RDATASET_ATTR_STALE;
-                       }
-               }
-       } else {
-               /*
-                * No non-IGNORED rdatasets of the given type exist at
-                * this node.
-                */
-
-               /*
-                * If we're trying to delete the type, don't bother.
-                */
-               if (newheader_nx) {
-                       free_rdataset(rbtdb->common.mctx, newheader);
-                       return (DNS_R_UNCHANGED);
-               }
-
-               if (topheader != NULL) {
-                       /*
-                        * We have an list of rdatasets of the given type,
-                        * but they're all marked IGNORE.  We simply insert
-                        * the new rdataset at the head of the list.
-                        *
-                        * Ignored rdatasets cannot occur during loading, so
-                        * we INSIST on it.
-                        */
-                       INSIST(!loading);
-                       INSIST(rbtversion == NULL ||
-                              rbtversion->serial >= topheader->serial);
-                       if (topheader_prev != NULL)
-                               topheader_prev->next = newheader;
-                       else
-                               rbtnode->data = newheader;
-                       newheader->next = topheader->next;
-                       newheader->down = topheader;
-                       topheader->next = newheader;
-                       rbtnode->dirty = 1;
-                       if (changed != NULL)
-                               changed->dirty = ISC_TRUE;
-               } else {
-                       /*
-                        * No rdatasets of the given type exist at the node.
-                        */
-                       newheader->next = rbtnode->data;
-                       newheader->down = NULL;
-                       rbtnode->data = newheader;
-               }
-       }
-
-       /*
-        * Check if the node now contains CNAME and other data.
-        */
-       if (rbtversion != NULL &&
-           cname_and_other_data(rbtnode, rbtversion->serial))
-               return (DNS_R_CNAMEANDOTHER);
-
-       if (addedrdataset != NULL)
-               bind_rdataset(rbtdb, rbtnode, newheader, now, addedrdataset);
-
-       return (ISC_R_SUCCESS);
+        /*
+         * If header isn't NULL, we've found the right type.  There may be
+         * IGNORE rdatasets between the top of the chain and the first real
+         * data.  We skip over them.
+         */
+        header = topheader;
+        while (header != NULL && IGNORE(header))
+                header = header->down;
+        if (header != NULL) {
+                header_nx = NONEXISTENT(header) ? ISC_TRUE : ISC_FALSE;
+
+                /*
+                 * Deleting an already non-existent rdataset has no effect.
+                 */
+                if (header_nx && newheader_nx) {
+                        free_rdataset(rbtdb, rbtdb->common.mctx, newheader);
+                        return (DNS_R_UNCHANGED);
+                }
+
+                /*
+                 * Trying to add an rdataset with lower trust to a cache DB
+                 * has no effect, provided that the cache data isn't stale.
+                 */
+                if (rbtversion == NULL && trust < header->trust &&
+                    (header->rdh_ttl > now || header_nx)) {
+                        newheader->attributes |= RDATASET_ATTR_CANCELED;
+                        free_rdataset(rbtdb, rbtdb->common.mctx, newheader);
+                        if (addedrdataset != NULL)
+                                bind_rdataset(rbtdb, rbtnode, header, now,
+                                              addedrdataset);
+                        return (DNS_R_UNCHANGED);
+                }
+
+                /*
+                 * Don't merge if a nonexistent rdataset is involved.
+                 */
+                if (merge && (header_nx || newheader_nx))
+                        merge = ISC_FALSE;
+
+                /*
+                 * If 'merge' is ISC_TRUE, we'll try to create a new rdataset
+                 * that is the union of 'newheader' and 'header'.
+                 */
+                if (merge) {
+                        unsigned int flags = 0;
+                        INSIST(rbtversion->serial >= header->serial);
+                        merged = NULL;
+                        result = ISC_R_SUCCESS;
+
+                        if ((options & DNS_DBADD_EXACT) != 0)
+                                flags |= DNS_RDATASLAB_EXACT;
+                        if ((options & DNS_DBADD_EXACTTTL) != 0 &&
+                             newheader->rdh_ttl != header->rdh_ttl)
+                                        result = DNS_R_NOTEXACT;
+                        else if (newheader->rdh_ttl != header->rdh_ttl)
+                                flags |= DNS_RDATASLAB_FORCE;
+                        if (result == ISC_R_SUCCESS)
+                                result = dns_rdataslab_merge(
+                                             (unsigned char *)header,
+                                             (unsigned char *)newheader,
+                                             (unsigned int)(sizeof(*newheader)),
+                                             rbtdb->common.mctx,
+                                             rbtdb->common.rdclass,
+                                             (dns_rdatatype_t)header->type,
+                                             flags, &merged);
+                        if (result == ISC_R_SUCCESS) {
+                                /*
+                                 * If 'header' has the same serial number as
+                                 * we do, we could clean it up now if we knew
+                                 * that our caller had no references to it.
+                                 * We don't know this, however, so we leave it
+                                 * alone.  It will get cleaned up when
+                                 * clean_zone_node() runs.
+                                 */
+                                free_rdataset(rbtdb, rbtdb->common.mctx,
+                                              newheader);
+                                newheader = (rdatasetheader_t *)merged;
+                        } else {
+                                free_rdataset(rbtdb, rbtdb->common.mctx,
+                                              newheader);
+                                return (result);
+                        }
+                }
+                /*
+                 * Don't replace existing NS, A and AAAA RRsets
+                 * in the cache if they are already exist.  This
+                 * prevents named being locked to old servers.
+                 * Don't lower trust of existing record if the
+                 * update is forced.
+                 */
+                if (IS_CACHE(rbtdb) && header->rdh_ttl > now &&
+                    header->type == dns_rdatatype_ns &&
+                    !header_nx && !newheader_nx &&
+                    header->trust >= newheader->trust &&
+                    dns_rdataslab_equalx((unsigned char *)header,
+                                         (unsigned char *)newheader,
+                                         (unsigned int)(sizeof(*newheader)),
+                                         rbtdb->common.rdclass,
+                                         (dns_rdatatype_t)header->type)) {
+                        /*
+                         * Honour the new ttl if it is less than the
+                         * older one.
+                         */
+                        if (header->rdh_ttl > newheader->rdh_ttl)
+                                set_ttl(rbtdb, header, newheader->rdh_ttl);
+                        if (header->noqname == NULL &&
+                            newheader->noqname != NULL) {
+                                header->noqname = newheader->noqname;
+                                newheader->noqname = NULL;
+                        }
+                        newheader->attributes |= RDATASET_ATTR_CANCELED;
+                        free_rdataset(rbtdb, rbtdb->common.mctx, newheader);
+                        if (addedrdataset != NULL)
+                                bind_rdataset(rbtdb, rbtnode, header, now,
+                                              addedrdataset);
+                        return (ISC_R_SUCCESS);
+                }
+                if (IS_CACHE(rbtdb) && header->rdh_ttl > now &&
+                    (header->type == dns_rdatatype_a ||
+                     header->type == dns_rdatatype_aaaa) &&
+                    !header_nx && !newheader_nx &&
+                    header->trust >= newheader->trust &&
+                    dns_rdataslab_equal((unsigned char *)header,
+                                        (unsigned char *)newheader,
+                                        (unsigned int)(sizeof(*newheader)))) {
+                        /*
+                         * Honour the new ttl if it is less than the
+                         * older one.
+                         */
+                        if (header->rdh_ttl > newheader->rdh_ttl)
+                                set_ttl(rbtdb, header, newheader->rdh_ttl);
+                        if (header->noqname == NULL &&
+                            newheader->noqname != NULL) {
+                                header->noqname = newheader->noqname;
+                                newheader->noqname = NULL;
+                        }
+                        newheader->attributes |= RDATASET_ATTR_CANCELED;
+                        free_rdataset(rbtdb, rbtdb->common.mctx, newheader);
+                        if (addedrdataset != NULL)
+                                bind_rdataset(rbtdb, rbtnode, header, now,
+                                              addedrdataset);
+                        return (ISC_R_SUCCESS);
+                }
+                INSIST(rbtversion == NULL ||
+                       rbtversion->serial >= topheader->serial);
+                if (topheader_prev != NULL)
+                        topheader_prev->next = newheader;
+                else
+                        rbtnode->data = newheader;
+                newheader->next = topheader->next;
+                if (loading) {
+                        /*
+                         * There are no other references to 'header' when
+                         * loading, so we MAY clean up 'header' now.
+                         * Since we don't generate changed records when
+                         * loading, we MUST clean up 'header' now.
+                         */
+                        newheader->down = NULL;
+                        free_rdataset(rbtdb, rbtdb->common.mctx, header);
+                } else {
+                        newheader->down = topheader;
+                        topheader->next = newheader;
+                        rbtnode->dirty = 1;
+                        if (changed != NULL)
+                                changed->dirty = ISC_TRUE;
+                        if (rbtversion == NULL) {
+                                set_ttl(rbtdb, header, 0);
+                                header->attributes |= RDATASET_ATTR_STALE;
+                        }
+                        if (IS_CACHE(rbtdb)) {
+                                int idx = newheader->node->locknum;
+
+                                ISC_LIST_PREPEND(rbtdb->rdatasets[idx],
+                                                 newheader, lru_link);
+
+                                /*
+                                 * XXXMLG We don't check the return value
+                                 * here.  If it fails, we will not do TTL
+                                 * based expiry on this node.  However, we
+                                 * will do it on the LRU side, so memory
+                                 * will not leak... for long.
+                                 */
+                                isc_heap_insert(rbtdb->heaps[idx], newheader);
+                        }
+#ifdef LRU_DEBUG
+                        cachestat_update(rbtdb, newheader);
+#endif
+                }
+        } else {
+                /*
+                 * No non-IGNORED rdatasets of the given type exist at
+                 * this node.
+                 */
+
+                /*
+                 * If we're trying to delete the type, don't bother.
+                 */
+                if (newheader_nx) {
+                        free_rdataset(rbtdb, rbtdb->common.mctx, newheader);
+                        return (DNS_R_UNCHANGED);
+                }
+
+                if (topheader != NULL) {
+                        /*
+                         * We have an list of rdatasets of the given type,
+                         * but they're all marked IGNORE.  We simply insert
+                         * the new rdataset at the head of the list.
+                         *
+                         * Ignored rdatasets cannot occur during loading, so
+                         * we INSIST on it.
+                         */
+                        INSIST(!loading);
+                        INSIST(rbtversion == NULL ||
+                               rbtversion->serial >= topheader->serial);
+                        if (topheader_prev != NULL)
+                                topheader_prev->next = newheader;
+                        else
+                                rbtnode->data = newheader;
+                        newheader->next = topheader->next;
+                        newheader->down = topheader;
+                        topheader->next = newheader;
+                        rbtnode->dirty = 1;
+                        if (changed != NULL)
+                                changed->dirty = ISC_TRUE;
+                } else {
+                        /*
+                         * No rdatasets of the given type exist at the node.
+                         */
+                        newheader->next = rbtnode->data;
+                        newheader->down = NULL;
+                        rbtnode->data = newheader;
+                }
+                if (IS_CACHE(rbtdb)) {
+                        int idx = newheader->node->locknum;
+                        ISC_LIST_PREPEND(rbtdb->rdatasets[idx],
+                                         newheader, lru_link);
+                        isc_heap_insert(rbtdb->heaps[idx], newheader);
+                }
+#ifdef LRU_DEBUG
+                cachestat_update(rbtdb, newheader);
+#endif
+        }
+
+        /*
+         * Check if the node now contains CNAME and other data.
+         */
+        if (rbtversion != NULL &&
+            cname_and_other_data(rbtnode, rbtversion->serial))
+                return (DNS_R_CNAMEANDOTHER);
+
+        if (addedrdataset != NULL)
+                bind_rdataset(rbtdb, rbtnode, newheader, now, addedrdataset);
+
+        return (ISC_R_SUCCESS);
 }
 
 static inline isc_boolean_t
 delegating_type(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node,
-               rbtdb_rdatatype_t type)
+                rbtdb_rdatatype_t type)
 {
-       if (IS_CACHE(rbtdb)) {
-               if (type == dns_rdatatype_dname)
-                       return (ISC_TRUE);
-               else
-                       return (ISC_FALSE);
-       } else if (type == dns_rdatatype_dname ||
-                  (type == dns_rdatatype_ns &&
-                   (node != rbtdb->origin_node || IS_STUB(rbtdb))))
-               return (ISC_TRUE);
-       return (ISC_FALSE);
+        if (IS_CACHE(rbtdb)) {
+                if (type == dns_rdatatype_dname)
+                        return (ISC_TRUE);
+                else
+                        return (ISC_FALSE);
+        } else if (type == dns_rdatatype_dname ||
+                   (type == dns_rdatatype_ns &&
+                    (node != rbtdb->origin_node || IS_STUB(rbtdb))))
+                return (ISC_TRUE);
+        return (ISC_FALSE);
 }
 
 static inline isc_result_t
 addnoqname(dns_rbtdb_t *rbtdb, rdatasetheader_t *newheader,
-          dns_rdataset_t *rdataset)
+           dns_rdataset_t *rdataset)
 {
-       struct noqname *noqname;
-       isc_mem_t *mctx = rbtdb->common.mctx;
-       dns_name_t name;
-       dns_rdataset_t nsec, nsecsig;
-       isc_result_t result;
-       isc_region_t r;
-
-       dns_name_init(&name, NULL);
-       dns_rdataset_init(&nsec);
-       dns_rdataset_init(&nsecsig);
-
-       result = dns_rdataset_getnoqname(rdataset, &name, &nsec, &nsecsig);
-       RUNTIME_CHECK(result == ISC_R_SUCCESS);
-
-       noqname = isc_mem_get(mctx, sizeof(*noqname));
-       if (noqname == NULL) {
-               result = ISC_R_NOMEMORY;
-               goto cleanup;
-       }
-       dns_name_init(&noqname->name, NULL);
-       noqname->nsec = NULL;
-       noqname->nsecsig = NULL;
-       result = dns_name_dup(&name, mctx, &noqname->name);
-       if (result != ISC_R_SUCCESS)
-               goto cleanup;
-       result = dns_rdataslab_fromrdataset(&nsec, mctx, &r, 0);
-       if (result != ISC_R_SUCCESS)
-               goto cleanup;
-       noqname->nsec = r.base;
-       result = dns_rdataslab_fromrdataset(&nsecsig, mctx, &r, 0);
-       if (result != ISC_R_SUCCESS)
-               goto cleanup;
-       noqname->nsecsig = r.base;
-       dns_rdataset_disassociate(&nsec);
-       dns_rdataset_disassociate(&nsecsig);
-       newheader->noqname = noqname;
-       return (ISC_R_SUCCESS);
+        struct noqname *noqname;
+        isc_mem_t *mctx = rbtdb->common.mctx;
+        dns_name_t name;
+        dns_rdataset_t nsec, nsecsig;
+        isc_result_t result;
+        isc_region_t r;
+
+        dns_name_init(&name, NULL);
+        dns_rdataset_init(&nsec);
+        dns_rdataset_init(&nsecsig);
+
+        result = dns_rdataset_getnoqname(rdataset, &name, &nsec, &nsecsig);
+        RUNTIME_CHECK(result == ISC_R_SUCCESS);
+
+        noqname = isc_mem_get(mctx, sizeof(*noqname));
+        if (noqname == NULL) {
+                result = ISC_R_NOMEMORY;
+                goto cleanup;
+        }
+        dns_name_init(&noqname->name, NULL);
+        noqname->nsec = NULL;
+        noqname->nsecsig = NULL;
+        result = dns_name_dup(&name, mctx, &noqname->name);
+        if (result != ISC_R_SUCCESS)
+                goto cleanup;
+        result = dns_rdataslab_fromrdataset(&nsec, mctx, &r, 0);
+        if (result != ISC_R_SUCCESS)
+                goto cleanup;
+        noqname->nsec = r.base;
+        result = dns_rdataslab_fromrdataset(&nsecsig, mctx, &r, 0);
+        if (result != ISC_R_SUCCESS)
+                goto cleanup;
+        noqname->nsecsig = r.base;
+        dns_rdataset_disassociate(&nsec);
+        dns_rdataset_disassociate(&nsecsig);
+        newheader->noqname = noqname;
+        return (ISC_R_SUCCESS);
 
 cleanup:
-       dns_rdataset_disassociate(&nsec);
-       dns_rdataset_disassociate(&nsecsig);
-       free_noqname(mctx, &noqname);
-       return(result);
+        dns_rdataset_disassociate(&nsec);
+        dns_rdataset_disassociate(&nsecsig);
+        free_noqname(mctx, &noqname);
+        return(result);
 }
 
 static isc_result_t
 addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
-           isc_stdtime_t now, dns_rdataset_t *rdataset, unsigned int options,
-           dns_rdataset_t *addedrdataset)
+            isc_stdtime_t now, dns_rdataset_t *rdataset, unsigned int options,
+            dns_rdataset_t *addedrdataset)
 {
-       dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
-       dns_rbtnode_t *rbtnode = (dns_rbtnode_t *)node;
-       rbtdb_version_t *rbtversion = version;
-       isc_region_t region;
-       rdatasetheader_t *newheader;
-       isc_result_t result;
-       isc_boolean_t delegating;
-
-       REQUIRE(VALID_RBTDB(rbtdb));
-
-       if (rbtversion == NULL) {
-               if (now == 0)
-                       isc_stdtime_get(&now);
-       } else
-               now = 0;
-
-       result = dns_rdataslab_fromrdataset(rdataset, rbtdb->common.mctx,
-                                           &region,
-                                           sizeof(rdatasetheader_t));
-       if (result != ISC_R_SUCCESS)
-               return (result);
-
-       newheader = (rdatasetheader_t *)region.base;
-       newheader->ttl = rdataset->ttl + now;
-       newheader->type = RBTDB_RDATATYPE_VALUE(rdataset->type,
-                                               rdataset->covers);
-       newheader->attributes = 0;
-       newheader->noqname = NULL;
-       newheader->count = init_count++;
-       newheader->trust = rdataset->trust;
-       newheader->additional_auth = NULL;
-       newheader->additional_glue = NULL;
-       if (rbtversion != NULL) {
-               newheader->serial = rbtversion->serial;
-               now = 0;
-       } else {
-               newheader->serial = 1;
-               if ((rdataset->attributes & DNS_RDATASETATTR_NXDOMAIN) != 0)
-                       newheader->attributes |= RDATASET_ATTR_NXDOMAIN;
-               if ((rdataset->attributes & DNS_RDATASETATTR_NOQNAME) != 0) {
-                       result = addnoqname(rbtdb, newheader, rdataset);
-                       if (result != ISC_R_SUCCESS) {
-                               free_rdataset(rbtdb->common.mctx, newheader);
-                               return (result);
-                       }
-               }
-       }
-
-       /*
-        * If we're adding a delegation type (e.g. NS or DNAME for a zone,
-        * just DNAME for the cache), then we need to set the callback bit
-        * on the node, and to do that we must be holding an exclusive lock
-        * on the tree.
-        */
-       if (delegating_type(rbtdb, rbtnode, rdataset->type)) {
-               delegating = ISC_TRUE;
-               RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_write);
-       } else
-               delegating = ISC_FALSE;
-
-       NODE_LOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
-                 isc_rwlocktype_write);
-
-       result = add(rbtdb, rbtnode, rbtversion, newheader, options, ISC_FALSE,
-                    addedrdataset, now);
-       if (result == ISC_R_SUCCESS && delegating)
-               rbtnode->find_callback = 1;
-
-       NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
-                   isc_rwlocktype_write);
-
-       if (delegating)
-               RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_write);
-
-       /*
-        * Update the zone's secure status.  If version is non-NULL
-        * this is defered until closeversion() is called.
-        */
-       if (result == ISC_R_SUCCESS && version == NULL && !IS_CACHE(rbtdb))
-               rbtdb->secure = iszonesecure(db, rbtdb->origin_node);
-
-       return (result);
+        dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
+        dns_rbtnode_t *rbtnode = (dns_rbtnode_t *)node;
+        rbtdb_version_t *rbtversion = version;
+        isc_region_t region;
+        rdatasetheader_t *newheader;
+        isc_result_t result;
+        isc_boolean_t delegating;
+        isc_boolean_t tree_locked = ISC_FALSE;
+
+        REQUIRE(VALID_RBTDB(rbtdb));
+
+        if (rbtversion == NULL) {
+                if (now == 0)
+                        isc_stdtime_get(&now);
+        } else
+                now = 0;
+
+        result = dns_rdataslab_fromrdataset(rdataset, rbtdb->common.mctx,
+                                            &region,
+                                            sizeof(rdatasetheader_t));
+        if (result != ISC_R_SUCCESS)
+                return (result);
+
+        newheader = (rdatasetheader_t *)region.base;
+        init_rdataset(rbtdb, newheader);
+        set_ttl(rbtdb, newheader, rdataset->ttl + now);
+        newheader->type = RBTDB_RDATATYPE_VALUE(rdataset->type,
+                                                rdataset->covers);
+        newheader->attributes = 0;
+        newheader->noqname = NULL;
+        newheader->count = init_count++;
+        newheader->trust = rdataset->trust;
+        newheader->additional_auth = NULL;
+        newheader->additional_glue = NULL;
+        newheader->last_used = now;
+        newheader->node = rbtnode;
+        if (rbtversion != NULL) {
+                newheader->serial = rbtversion->serial;
+                now = 0;
+        } else {
+                newheader->serial = 1;
+                if ((rdataset->attributes & DNS_RDATASETATTR_NXDOMAIN) != 0)
+                        newheader->attributes |= RDATASET_ATTR_NXDOMAIN;
+                if ((rdataset->attributes & DNS_RDATASETATTR_NOQNAME) != 0) {
+                        result = addnoqname(rbtdb, newheader, rdataset);
+                        if (result != ISC_R_SUCCESS) {
+                                free_rdataset(rbtdb, rbtdb->common.mctx,
+                                              newheader);
+                                return (result);
+                        }
+                }
+        }
+
+        /*
+         * If we're adding a delegation type (e.g. NS or DNAME for a zone,
+         * just DNAME for the cache), then we need to set the callback bit
+         * on the node.
+         */
+        if (delegating_type(rbtdb, rbtnode, rdataset->type))
+                delegating = ISC_TRUE;
+        else
+                delegating = ISC_FALSE;
+
+        /*
+         * If we're adding a delegation type or the DB is a cache in an overmem
+         * state, hold an exclusive lock on the tree.  In the latter case
+         * the lock does not necessarily have to be acquired but it will help
+         * purge stale entries more effectively.
+         */
+        if (delegating || (IS_CACHE(rbtdb) && rbtdb->overmem)) {
+                tree_locked = ISC_TRUE;
+                RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_write);
+        }
+
+        NODE_LOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
+                  isc_rwlocktype_write);
+
+#ifdef LRU_DEBUG
+        /* for debug: statistics update */
+        if (IS_CACHE(rbtdb) && rdataset->rdclass == dns_rdataclass_in) {
+                /* XXX: don't use lock for brevity */
+                newheader->attributes |= RDATASET_ATTR_CACHE;
+                rbtdb->cachestat.cache_total++;
+                rbtdb->cachestat.cache_current++;
+                if (rdataset->type == 0) {
+                        rbtdb->cachestat.ncache_total++;
+                        rbtdb->cachestat.ncache_current++;
+                }
+                if (rdataset->type == dns_rdatatype_a) {
+                        rbtdb->cachestat.a_total++;
+                        rbtdb->cachestat.a_current++;
+                } else if (rdataset->type == dns_rdatatype_aaaa) {
+                        rbtdb->cachestat.aaaa_total++;
+                        rbtdb->cachestat.aaaa_current++;
+                } else if (rdataset->type == dns_rdatatype_ns) {
+                        rbtdb->cachestat.ns_total++;
+                        rbtdb->cachestat.ns_current++;
+                } else if (rdataset->type == dns_rdatatype_ptr) {
+                        rbtdb->cachestat.ptr_total++;
+                        rbtdb->cachestat.ptr_current++;
+                }
+                if (rdataset->trust == dns_trust_glue &&
+                    (rdataset->type == dns_rdatatype_a ||
+                     rdataset->type == dns_rdatatype_aaaa)) {
+                        rbtdb->cachestat.glue_total++;
+                        rbtdb->cachestat.glue_current++;
+                }
+                if (rdataset->trust == dns_trust_additional &&
+                    (rdataset->type == dns_rdatatype_a ||
+                     rdataset->type == dns_rdatatype_aaaa)) {
+                        rbtdb->cachestat.additional_total++;
+                        rbtdb->cachestat.additional_current++;
+                }
+        }
+#endif
+
+        if (IS_CACHE(rbtdb)) {
+                if (tree_locked)
+                        cleanup_dead_nodes(rbtdb, rbtnode->locknum);
+                check_stale_cache(rbtdb, rbtnode, now, tree_locked);
+
+                /*
+                 * If we've been holding a write lock on the tree just for
+                 * cleaning, we can release it now.  However, we still need the
+                 * node lock.
+                 */
+                if (tree_locked && !delegating) {
+                        RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_write);
+                        tree_locked = ISC_FALSE;
+                }
+        }
+
+        result = add(rbtdb, rbtnode, rbtversion, newheader, options, ISC_FALSE,
+                     addedrdataset, now);
+        if (result == ISC_R_SUCCESS && delegating)
+                rbtnode->find_callback = 1;
+
+        NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
+                    isc_rwlocktype_write);
+
+        if (tree_locked)
+                RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_write);
+
+        /*
+         * Update the zone's secure status.  If version is non-NULL
+         * this is defered until closeversion() is called.
+         */
+        if (result == ISC_R_SUCCESS && version == NULL && !IS_CACHE(rbtdb))
+                rbtdb->secure = iszonesecure(db, rbtdb->origin_node);
+
+        return (result);
 }
 
 static isc_result_t
 subtractrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
-                dns_rdataset_t *rdataset, unsigned int options,
-                dns_rdataset_t *newrdataset)
+                 dns_rdataset_t *rdataset, unsigned int options,
+                 dns_rdataset_t *newrdataset)
 {
-       dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
-       dns_rbtnode_t *rbtnode = (dns_rbtnode_t *)node;
-       rbtdb_version_t *rbtversion = version;
-       rdatasetheader_t *topheader, *topheader_prev, *header, *newheader;
-       unsigned char *subresult;
-       isc_region_t region;
-       isc_result_t result;
-       rbtdb_changed_t *changed;
-
-       REQUIRE(VALID_RBTDB(rbtdb));
-
-       result = dns_rdataslab_fromrdataset(rdataset, rbtdb->common.mctx,
-                                           &region,
-                                           sizeof(rdatasetheader_t));
-       if (result != ISC_R_SUCCESS)
-               return (result);
-       newheader = (rdatasetheader_t *)region.base;
-       newheader->ttl = rdataset->ttl;
-       newheader->type = RBTDB_RDATATYPE_VALUE(rdataset->type,
-                                               rdataset->covers);
-       newheader->attributes = 0;
-       newheader->serial = rbtversion->serial;
-       newheader->trust = 0;
-       newheader->noqname = NULL;
-       newheader->count = init_count++;
-       newheader->additional_auth = NULL;
-       newheader->additional_glue = NULL;
-
-       NODE_LOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
-                 isc_rwlocktype_write);
-
-       changed = add_changed(rbtdb, rbtversion, rbtnode);
-       if (changed == NULL) {
-               free_rdataset(rbtdb->common.mctx, newheader);
-               NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
-                           isc_rwlocktype_write);
-               return (ISC_R_NOMEMORY);
-       }
-
-       topheader_prev = NULL;
-       for (topheader = rbtnode->data;
-            topheader != NULL;
-            topheader = topheader->next) {
-               if (topheader->type == newheader->type)
-                       break;
-               topheader_prev = topheader;
-       }
-       /*
-        * If header isn't NULL, we've found the right type.  There may be
-        * IGNORE rdatasets between the top of the chain and the first real
-        * data.  We skip over them.
-        */
-       header = topheader;
-       while (header != NULL && IGNORE(header))
-               header = header->down;
-       if (header != NULL && EXISTS(header)) {
-               unsigned int flags = 0;
-               subresult = NULL;
-               result = ISC_R_SUCCESS;
-               if ((options & DNS_DBSUB_EXACT) != 0) {
-                       flags |= DNS_RDATASLAB_EXACT;
-                       if (newheader->ttl != header->ttl)
-                               result = DNS_R_NOTEXACT;
-               }
-               if (result == ISC_R_SUCCESS)
-                       result = dns_rdataslab_subtract(
-                                       (unsigned char *)header,
-                                       (unsigned char *)newheader,
-                                       (unsigned int)(sizeof(*newheader)),
-                                       rbtdb->common.mctx,
-                                       rbtdb->common.rdclass,
-                                       (dns_rdatatype_t)header->type,
-                                       flags, &subresult);
-               if (result == ISC_R_SUCCESS) {
-                       free_rdataset(rbtdb->common.mctx, newheader);
-                       newheader = (rdatasetheader_t *)subresult;
-                       /*
-                        * We have to set the serial since the rdataslab
-                        * subtraction routine copies the reserved portion of
-                        * header, not newheader.
-                        */
-                       newheader->serial = rbtversion->serial;
-                       /*
-                        * XXXJT: dns_rdataslab_subtract() copied the pointers
-                        * to additional info.  We need to clear these fields
-                        * to avoid having duplicated references.
-                        */
-                       newheader->additional_auth = NULL;
-                       newheader->additional_glue = NULL;
-               } else if (result == DNS_R_NXRRSET) {
-                       /*
-                        * This subtraction would remove all of the rdata;
-                        * add a nonexistent header instead.
-                        */
-                       free_rdataset(rbtdb->common.mctx, newheader);
-                       newheader = isc_mem_get(rbtdb->common.mctx,
-                                               sizeof(*newheader));
-                       if (newheader == NULL) {
-                               result = ISC_R_NOMEMORY;
-                               goto unlock;
-                       }
-                       newheader->ttl = 0;
-                       newheader->type = topheader->type;
-                       newheader->attributes = RDATASET_ATTR_NONEXISTENT;
-                       newheader->trust = 0;
-                       newheader->serial = rbtversion->serial;
-                       newheader->noqname = NULL;
-                       newheader->count = 0;
-                       newheader->additional_auth = NULL;
-                       newheader->additional_glue = NULL;
-               } else {
-                       free_rdataset(rbtdb->common.mctx, newheader);
-                       goto unlock;
-               }
-
-               /*
-                * If we're here, we want to link newheader in front of
-                * topheader.
-                */
-               INSIST(rbtversion->serial >= topheader->serial);
-               if (topheader_prev != NULL)
-                       topheader_prev->next = newheader;
-               else
-                       rbtnode->data = newheader;
-               newheader->next = topheader->next;
-               newheader->down = topheader;
-               topheader->next = newheader;
-               rbtnode->dirty = 1;
-               changed->dirty = ISC_TRUE;
-       } else {
-               /*
-                * The rdataset doesn't exist, so we don't need to do anything
-                * to satisfy the deletion request.
-                */
-               free_rdataset(rbtdb->common.mctx, newheader);
-               if ((options & DNS_DBSUB_EXACT) != 0)
-                       result = DNS_R_NOTEXACT;
-               else
-                       result = DNS_R_UNCHANGED;                       
-       }
-
-       if (result == ISC_R_SUCCESS && newrdataset != NULL)
-               bind_rdataset(rbtdb, rbtnode, newheader, 0, newrdataset);
+        dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
+        dns_rbtnode_t *rbtnode = (dns_rbtnode_t *)node;
+        rbtdb_version_t *rbtversion = version;
+        rdatasetheader_t *topheader, *topheader_prev, *header, *newheader;
+        unsigned char *subresult;
+        isc_region_t region;
+        isc_result_t result;
+        rbtdb_changed_t *changed;
+
+        REQUIRE(VALID_RBTDB(rbtdb));
+
+        result = dns_rdataslab_fromrdataset(rdataset, rbtdb->common.mctx,
+                                            &region,
+                                            sizeof(rdatasetheader_t));
+        if (result != ISC_R_SUCCESS)
+                return (result);
+        newheader = (rdatasetheader_t *)region.base;
+        init_rdataset(rbtdb, newheader);
+        set_ttl(rbtdb, newheader, rdataset->ttl);
+        newheader->type = RBTDB_RDATATYPE_VALUE(rdataset->type,
+                                                rdataset->covers);
+        newheader->attributes = 0;
+        newheader->serial = rbtversion->serial;
+        newheader->trust = 0;
+        newheader->noqname = NULL;
+        newheader->count = init_count++;
+        newheader->additional_auth = NULL;
+        newheader->additional_glue = NULL;
+        newheader->last_used = 0;
+        newheader->node = rbtnode;
+
+        NODE_LOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
+                  isc_rwlocktype_write);
+
+        changed = add_changed(rbtdb, rbtversion, rbtnode);
+        if (changed == NULL) {
+                free_rdataset(rbtdb, rbtdb->common.mctx, newheader);
+                NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
+                            isc_rwlocktype_write);
+                return (ISC_R_NOMEMORY);
+        }
+
+        topheader_prev = NULL;
+        for (topheader = rbtnode->data;
+             topheader != NULL;
+             topheader = topheader->next) {
+                if (topheader->type == newheader->type)
+                        break;
+                topheader_prev = topheader;
+        }
+        /*
+         * If header isn't NULL, we've found the right type.  There may be
+         * IGNORE rdatasets between the top of the chain and the first real
+         * data.  We skip over them.
+         */
+        header = topheader;
+        while (header != NULL && IGNORE(header))
+                header = header->down;
+        if (header != NULL && EXISTS(header)) {
+                unsigned int flags = 0;
+                subresult = NULL;
+                result = ISC_R_SUCCESS;
+                if ((options & DNS_DBSUB_EXACT) != 0) {
+                        flags |= DNS_RDATASLAB_EXACT;
+                        if (newheader->rdh_ttl != header->rdh_ttl)
+                                result = DNS_R_NOTEXACT;
+                }
+                if (result == ISC_R_SUCCESS)
+                        result = dns_rdataslab_subtract(
+                                        (unsigned char *)header,
+                                        (unsigned char *)newheader,
+                                        (unsigned int)(sizeof(*newheader)),
+                                        rbtdb->common.mctx,
+                                        rbtdb->common.rdclass,
+                                        (dns_rdatatype_t)header->type,
+                                        flags, &subresult);
+                if (result == ISC_R_SUCCESS) {
+                        free_rdataset(rbtdb, rbtdb->common.mctx, newheader);
+                        newheader = (rdatasetheader_t *)subresult;
+                        /*
+                         * We have to set the serial since the rdataslab
+                         * subtraction routine copies the reserved portion of
+                         * header, not newheader.
+                         */
+                        newheader->serial = rbtversion->serial;
+                        /*
+                         * XXXJT: dns_rdataslab_subtract() copied the pointers
+                         * to additional info.  We need to clear these fields
+                         * to avoid having duplicated references.
+                         */
+                        newheader->additional_auth = NULL;
+                        newheader->additional_glue = NULL;
+                } else if (result == DNS_R_NXRRSET) {
+                        /*
+                         * This subtraction would remove all of the rdata;
+                         * add a nonexistent header instead.
+                         */
+                        free_rdataset(rbtdb, rbtdb->common.mctx, newheader);
+                        newheader = new_rdataset(rbtdb, rbtdb->common.mctx);
+                        if (newheader == NULL) {
+                                result = ISC_R_NOMEMORY;
+                                goto unlock;
+                        }
+                        set_ttl(rbtdb, newheader, 0);
+                        newheader->type = topheader->type;
+                        newheader->attributes = RDATASET_ATTR_NONEXISTENT;
+                        newheader->trust = 0;
+                        newheader->serial = rbtversion->serial;
+                        newheader->noqname = NULL;
+                        newheader->count = 0;
+                        newheader->additional_auth = NULL;
+                        newheader->additional_glue = NULL;
+                } else {
+                        free_rdataset(rbtdb, rbtdb->common.mctx, newheader);
+                        goto unlock;
+                }
+
+                /*
+                 * If we're here, we want to link newheader in front of
+                 * topheader.
+                 */
+                INSIST(rbtversion->serial >= topheader->serial);
+                if (topheader_prev != NULL)
+                        topheader_prev->next = newheader;
+                else
+                        rbtnode->data = newheader;
+                newheader->next = topheader->next;
+                newheader->down = topheader;
+                topheader->next = newheader;
+                rbtnode->dirty = 1;
+                changed->dirty = ISC_TRUE;
+        } else {
+                /*
+                 * The rdataset doesn't exist, so we don't need to do anything
+                 * to satisfy the deletion request.
+                 */
+                free_rdataset(rbtdb, rbtdb->common.mctx, newheader);
+                if ((options & DNS_DBSUB_EXACT) != 0)
+                        result = DNS_R_NOTEXACT;
+                else
+                        result = DNS_R_UNCHANGED;
+        }
+
+        if (result == ISC_R_SUCCESS && newrdataset != NULL)
+                bind_rdataset(rbtdb, rbtnode, newheader, 0, newrdataset);
 
  unlock:
-       NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
-                   isc_rwlocktype_write);
+        NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
+                    isc_rwlocktype_write);
 
-       /*
-        * Update the zone's secure status.  If version is non-NULL
-        * this is defered until closeversion() is called.
-        */
-       if (result == ISC_R_SUCCESS && version == NULL && !IS_CACHE(rbtdb))
-               rbtdb->secure = iszonesecure(db, rbtdb->origin_node);
+        /*
+         * Update the zone's secure status.  If version is non-NULL
+         * this is defered until closeversion() is called.
+         */
+        if (result == ISC_R_SUCCESS && version == NULL && !IS_CACHE(rbtdb))
+                rbtdb->secure = iszonesecure(db, rbtdb->origin_node);
 
-       return (result);
+        return (result);
 }
 
 static isc_result_t
 deleterdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
-              dns_rdatatype_t type, dns_rdatatype_t covers)
+               dns_rdatatype_t type, dns_rdatatype_t covers)
 {
-       dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
-       dns_rbtnode_t *rbtnode = (dns_rbtnode_t *)node;
-       rbtdb_version_t *rbtversion = version;
-       isc_result_t result;
-       rdatasetheader_t *newheader;
-
-       REQUIRE(VALID_RBTDB(rbtdb));
-
-       if (type == dns_rdatatype_any)
-               return (ISC_R_NOTIMPLEMENTED);
-       if (type == dns_rdatatype_rrsig && covers == 0)
-               return (ISC_R_NOTIMPLEMENTED);
-
-       newheader = isc_mem_get(rbtdb->common.mctx, sizeof(*newheader));
-       if (newheader == NULL)
-               return (ISC_R_NOMEMORY);
-       newheader->ttl = 0;
-       newheader->type = RBTDB_RDATATYPE_VALUE(type, covers);
-       newheader->attributes = RDATASET_ATTR_NONEXISTENT;
-       newheader->trust = 0;
-       newheader->noqname = NULL;
-       newheader->additional_auth = NULL;
-       newheader->additional_glue = NULL;
-       if (rbtversion != NULL)
-               newheader->serial = rbtversion->serial;
-       else
-               newheader->serial = 0;
-       newheader->count = 0;
-
-       NODE_LOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
-                 isc_rwlocktype_write);
-
-       result = add(rbtdb, rbtnode, rbtversion, newheader, DNS_DBADD_FORCE,
-                    ISC_FALSE, NULL, 0);
-
-       NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
-                   isc_rwlocktype_write);
-
-       /*
-        * Update the zone's secure status.  If version is non-NULL
-        * this is defered until closeversion() is called.
-        */
-       if (result == ISC_R_SUCCESS && version == NULL && !IS_CACHE(rbtdb))
-               rbtdb->secure = iszonesecure(db, rbtdb->origin_node);
-
-       return (result);
+        dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
+        dns_rbtnode_t *rbtnode = (dns_rbtnode_t *)node;
+        rbtdb_version_t *rbtversion = version;
+        isc_result_t result;
+        rdatasetheader_t *newheader;
+
+        REQUIRE(VALID_RBTDB(rbtdb));
+
+        if (type == dns_rdatatype_any)
+                return (ISC_R_NOTIMPLEMENTED);
+        if (type == dns_rdatatype_rrsig && covers == 0)
+                return (ISC_R_NOTIMPLEMENTED);
+
+        newheader = new_rdataset(rbtdb, rbtdb->common.mctx);
+        if (newheader == NULL)
+                return (ISC_R_NOMEMORY);
+        set_ttl(rbtdb, newheader, 0);
+        newheader->type = RBTDB_RDATATYPE_VALUE(type, covers);
+        newheader->attributes = RDATASET_ATTR_NONEXISTENT;
+        newheader->trust = 0;
+        newheader->noqname = NULL;
+        newheader->additional_auth = NULL;
+        newheader->additional_glue = NULL;
+        if (rbtversion != NULL)
+                newheader->serial = rbtversion->serial;
+        else
+                newheader->serial = 0;
+        newheader->count = 0;
+        newheader->last_used = 0;
+        newheader->node = rbtnode;
+
+        NODE_LOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
+                  isc_rwlocktype_write);
+
+        result = add(rbtdb, rbtnode, rbtversion, newheader, DNS_DBADD_FORCE,
+                     ISC_FALSE, NULL, 0);
+
+        NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
+                    isc_rwlocktype_write);
+
+        /*
+         * Update the zone's secure status.  If version is non-NULL
+         * this is defered until closeversion() is called.
+         */
+        if (result == ISC_R_SUCCESS && version == NULL && !IS_CACHE(rbtdb))
+                rbtdb->secure = iszonesecure(db, rbtdb->origin_node);
+
+        return (result);
 }
 
 static isc_result_t
 loading_addrdataset(void *arg, dns_name_t *name, dns_rdataset_t *rdataset) {
-       rbtdb_load_t *loadctx = arg;
-       dns_rbtdb_t *rbtdb = loadctx->rbtdb;
-       dns_rbtnode_t *node;
-       isc_result_t result;
-       isc_region_t region;
-       rdatasetheader_t *newheader;
-
-       /*
-        * This routine does no node locking.  See comments in
-        * 'load' below for more information on loading and
-        * locking.
-        */
-
-
-       /*
-        * SOA records are only allowed at top of zone.
-        */
-       if (rdataset->type == dns_rdatatype_soa &&
-           !IS_CACHE(rbtdb) && !dns_name_equal(name, &rbtdb->common.origin))
-               return (DNS_R_NOTZONETOP);
-
-       add_empty_wildcards(rbtdb, name);
-
-       if (dns_name_iswildcard(name)) {
-               /*
-                * NS record owners cannot legally be wild cards.
-                */
-               if (rdataset->type == dns_rdatatype_ns)
-                       return (DNS_R_INVALIDNS);
-               result = add_wildcard_magic(rbtdb, name);
-               if (result != ISC_R_SUCCESS)
-                       return (result);
-       }
-
-       node = NULL;
-       result = dns_rbt_addnode(rbtdb->tree, name, &node);
-       if (result != ISC_R_SUCCESS && result != ISC_R_EXISTS)
-               return (result);
-       if (result != ISC_R_EXISTS) {
-               dns_name_t foundname;
-               dns_name_init(&foundname, NULL);
-               dns_rbt_namefromnode(node, &foundname);
+        rbtdb_load_t *loadctx = arg;
+        dns_rbtdb_t *rbtdb = loadctx->rbtdb;
+        dns_rbtnode_t *node;
+        isc_result_t result;
+        isc_region_t region;
+        rdatasetheader_t *newheader;
+
+        /*
+         * This routine does no node locking.  See comments in
+         * 'load' below for more information on loading and
+         * locking.
+         */
+
+
+        /*
+         * SOA records are only allowed at top of zone.
+         */
+        if (rdataset->type == dns_rdatatype_soa &&
+            !IS_CACHE(rbtdb) && !dns_name_equal(name, &rbtdb->common.origin))
+                return (DNS_R_NOTZONETOP);
+
+        add_empty_wildcards(rbtdb, name);
+
+        if (dns_name_iswildcard(name)) {
+                /*
+                 * NS record owners cannot legally be wild cards.
+                 */
+                if (rdataset->type == dns_rdatatype_ns)
+                        return (DNS_R_INVALIDNS);
+                result = add_wildcard_magic(rbtdb, name);
+                if (result != ISC_R_SUCCESS)
+                        return (result);
+        }
+
+        node = NULL;
+        result = dns_rbt_addnode(rbtdb->tree, name, &node);
+        if (result != ISC_R_SUCCESS && result != ISC_R_EXISTS)
+                return (result);
+        if (result != ISC_R_EXISTS) {
+                dns_name_t foundname;
+                dns_name_init(&foundname, NULL);
+                dns_rbt_namefromnode(node, &foundname);
 #ifdef DNS_RBT_USEHASH
-               node->locknum = node->hashval % rbtdb->node_lock_count;
+                node->locknum = node->hashval % rbtdb->node_lock_count;
 #else
-               node->locknum = dns_name_hash(&foundname, ISC_TRUE) %
-                       rbtdb->node_lock_count;
+                node->locknum = dns_name_hash(&foundname, ISC_TRUE) %
+                        rbtdb->node_lock_count;
 #endif
-       }
-
-       result = dns_rdataslab_fromrdataset(rdataset, rbtdb->common.mctx,
-                                           &region,
-                                           sizeof(rdatasetheader_t));
-       if (result != ISC_R_SUCCESS)
-               return (result);
-       newheader = (rdatasetheader_t *)region.base;
-       newheader->ttl = rdataset->ttl + loadctx->now; /* XXX overflow check */
-       newheader->type = RBTDB_RDATATYPE_VALUE(rdataset->type,
-                                               rdataset->covers);
-       newheader->attributes = 0;
-       newheader->trust = rdataset->trust;
-       newheader->serial = 1;
-       newheader->noqname = NULL;
-       newheader->count = init_count++;
-       newheader->additional_auth = NULL;
-       newheader->additional_glue = NULL;
-
-       result = add(rbtdb, node, rbtdb->current_version, newheader,
-                    DNS_DBADD_MERGE, ISC_TRUE, NULL, 0);
-       if (result == ISC_R_SUCCESS &&
-           delegating_type(rbtdb, node, rdataset->type))
-               node->find_callback = 1;
-       else if (result == DNS_R_UNCHANGED)
-               result = ISC_R_SUCCESS;
-
-       return (result);
+        }
+
+        result = dns_rdataslab_fromrdataset(rdataset, rbtdb->common.mctx,
+                                            &region,
+                                            sizeof(rdatasetheader_t));
+        if (result != ISC_R_SUCCESS)
+                return (result);
+        newheader = (rdatasetheader_t *)region.base;
+        init_rdataset(rbtdb, newheader);
+        set_ttl(rbtdb, newheader,
+                rdataset->ttl + loadctx->now); /* XXX overflow check */
+        newheader->type = RBTDB_RDATATYPE_VALUE(rdataset->type,
+                                                rdataset->covers);
+        newheader->attributes = 0;
+        newheader->trust = rdataset->trust;
+        newheader->serial = 1;
+        newheader->noqname = NULL;
+        newheader->count = init_count++;
+        newheader->additional_auth = NULL;
+        newheader->additional_glue = NULL;
+        /* won't be used, but initialize anyway */
+        newheader->last_used = 0;
+        newheader->node = node;
+
+        result = add(rbtdb, node, rbtdb->current_version, newheader,
+                     DNS_DBADD_MERGE, ISC_TRUE, NULL, 0);
+        if (result == ISC_R_SUCCESS &&
+            delegating_type(rbtdb, node, rdataset->type))
+                node->find_callback = 1;
+        else if (result == DNS_R_UNCHANGED)
+                result = ISC_R_SUCCESS;
+
+        return (result);
 }
 
 static isc_result_t
 beginload(dns_db_t *db, dns_addrdatasetfunc_t *addp, dns_dbload_t **dbloadp) {
-       rbtdb_load_t *loadctx;
-       dns_rbtdb_t *rbtdb;
+        rbtdb_load_t *loadctx;
+        dns_rbtdb_t *rbtdb;
 
-       rbtdb = (dns_rbtdb_t *)db;
+        rbtdb = (dns_rbtdb_t *)db;
 
-       REQUIRE(VALID_RBTDB(rbtdb));
+        REQUIRE(VALID_RBTDB(rbtdb));
 
-       loadctx = isc_mem_get(rbtdb->common.mctx, sizeof(*loadctx));
-       if (loadctx == NULL)
-               return (ISC_R_NOMEMORY);
+        loadctx = isc_mem_get(rbtdb->common.mctx, sizeof(*loadctx));
+        if (loadctx == NULL)
+                return (ISC_R_NOMEMORY);
 
-       loadctx->rbtdb = rbtdb;
-       if (IS_CACHE(rbtdb))
-               isc_stdtime_get(&loadctx->now);
-       else
-               loadctx->now = 0;
+        loadctx->rbtdb = rbtdb;
+        if (IS_CACHE(rbtdb))
+                isc_stdtime_get(&loadctx->now);
+        else
+                loadctx->now = 0;
 
-       RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_write);
+        RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_write);
 
-       REQUIRE((rbtdb->attributes & (RBTDB_ATTR_LOADED|RBTDB_ATTR_LOADING))
-               == 0);
-       rbtdb->attributes |= RBTDB_ATTR_LOADING;
+        REQUIRE((rbtdb->attributes & (RBTDB_ATTR_LOADED|RBTDB_ATTR_LOADING))
+                == 0);
+        rbtdb->attributes |= RBTDB_ATTR_LOADING;
 
-       RBTDB_UNLOCK(&rbtdb->lock, isc_rwlocktype_write);
+        RBTDB_UNLOCK(&rbtdb->lock, isc_rwlocktype_write);
 
-       *addp = loading_addrdataset;
-       *dbloadp = loadctx;
+        *addp = loading_addrdataset;
+        *dbloadp = loadctx;
 
-       return (ISC_R_SUCCESS);
+        return (ISC_R_SUCCESS);
 }
 
 static isc_result_t
 endload(dns_db_t *db, dns_dbload_t **dbloadp) {
-       rbtdb_load_t *loadctx;
-       dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
+        rbtdb_load_t *loadctx;
+        dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
 
-       REQUIRE(VALID_RBTDB(rbtdb));
-       REQUIRE(dbloadp != NULL);
-       loadctx = *dbloadp;
-       REQUIRE(loadctx->rbtdb == rbtdb);
+        REQUIRE(VALID_RBTDB(rbtdb));
+        REQUIRE(dbloadp != NULL);
+        loadctx = *dbloadp;
+        REQUIRE(loadctx->rbtdb == rbtdb);
 
-       RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_write);
+        RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_write);
 
-       REQUIRE((rbtdb->attributes & RBTDB_ATTR_LOADING) != 0);
-       REQUIRE((rbtdb->attributes & RBTDB_ATTR_LOADED) == 0);
+        REQUIRE((rbtdb->attributes & RBTDB_ATTR_LOADING) != 0);
+        REQUIRE((rbtdb->attributes & RBTDB_ATTR_LOADED) == 0);
 
-       rbtdb->attributes &= ~RBTDB_ATTR_LOADING;
-       rbtdb->attributes |= RBTDB_ATTR_LOADED;
+        rbtdb->attributes &= ~RBTDB_ATTR_LOADING;
+        rbtdb->attributes |= RBTDB_ATTR_LOADED;
 
-       RBTDB_UNLOCK(&rbtdb->lock, isc_rwlocktype_write);
+        RBTDB_UNLOCK(&rbtdb->lock, isc_rwlocktype_write);
 
-       /*
-        * If there's a KEY rdataset at the zone origin containing a
-        * zone key, we consider the zone secure.
-        */
-       if (! IS_CACHE(rbtdb))
-               rbtdb->secure = iszonesecure(db, rbtdb->origin_node);
+        /*
+         * If there's a KEY rdataset at the zone origin containing a
+         * zone key, we consider the zone secure.
+         */
+        if (! IS_CACHE(rbtdb))
+                rbtdb->secure = iszonesecure(db, rbtdb->origin_node);
 
-       *dbloadp = NULL;
+        *dbloadp = NULL;
 
-       isc_mem_put(rbtdb->common.mctx, loadctx, sizeof(*loadctx));
+        isc_mem_put(rbtdb->common.mctx, loadctx, sizeof(*loadctx));
 
-       return (ISC_R_SUCCESS);
+        return (ISC_R_SUCCESS);
 }
 
 static isc_result_t
 dump(dns_db_t *db, dns_dbversion_t *version, const char *filename,
      dns_masterformat_t masterformat) {
-       dns_rbtdb_t *rbtdb;
+        dns_rbtdb_t *rbtdb;
 
-       rbtdb = (dns_rbtdb_t *)db;
+        rbtdb = (dns_rbtdb_t *)db;
 
-       REQUIRE(VALID_RBTDB(rbtdb));
+        REQUIRE(VALID_RBTDB(rbtdb));
 
-       return (dns_master_dump2(rbtdb->common.mctx, db, version,
-                                &dns_master_style_default,
-                                filename, masterformat));
+        return (dns_master_dump2(rbtdb->common.mctx, db, version,
+                                 &dns_master_style_default,
+                                 filename, masterformat));
 }
 
 static void
 delete_callback(void *data, void *arg) {
-       dns_rbtdb_t *rbtdb = arg;
-       rdatasetheader_t *current, *next;
+        dns_rbtdb_t *rbtdb = arg;
+        rdatasetheader_t *current, *next;
 
-       for (current = data; current != NULL; current = next) {
-               next = current->next;
-               free_rdataset(rbtdb->common.mctx, current);
-       }
+        for (current = data; current != NULL; current = next) {
+                next = current->next;
+                free_rdataset(rbtdb, rbtdb->common.mctx, current);
+        }
 }
 
 static isc_boolean_t
 issecure(dns_db_t *db) {
-       dns_rbtdb_t *rbtdb;
-       isc_boolean_t secure;
+        dns_rbtdb_t *rbtdb;
+        isc_boolean_t secure;
 
-       rbtdb = (dns_rbtdb_t *)db;
+        rbtdb = (dns_rbtdb_t *)db;
 
-       REQUIRE(VALID_RBTDB(rbtdb));
+        REQUIRE(VALID_RBTDB(rbtdb));
 
-       RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
-       secure = rbtdb->secure;
-       RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
+        RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
+        secure = rbtdb->secure;
+        RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
 
-       return (secure);
+        return (secure);
 }
 
 static unsigned int
 nodecount(dns_db_t *db) {
-       dns_rbtdb_t *rbtdb;
-       unsigned int count;
+        dns_rbtdb_t *rbtdb;
+        unsigned int count;
 
-       rbtdb = (dns_rbtdb_t *)db;
+        rbtdb = (dns_rbtdb_t *)db;
 
-       REQUIRE(VALID_RBTDB(rbtdb));
+        REQUIRE(VALID_RBTDB(rbtdb));
 
-       RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
-       count = dns_rbt_nodecount(rbtdb->tree);
-       RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
+        RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
+        count = dns_rbt_nodecount(rbtdb->tree);
+        RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
 
-       return (count);
+        return (count);
 }
 
 static void
 settask(dns_db_t *db, isc_task_t *task) {
-       dns_rbtdb_t *rbtdb;
+        dns_rbtdb_t *rbtdb;
 
-       rbtdb = (dns_rbtdb_t *)db;
+        rbtdb = (dns_rbtdb_t *)db;
 
-       REQUIRE(VALID_RBTDB(rbtdb));
+        REQUIRE(VALID_RBTDB(rbtdb));
 
-       RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_write);
-       if (rbtdb->task != NULL)
-               isc_task_detach(&rbtdb->task);
-       if (task != NULL)
-               isc_task_attach(task, &rbtdb->task);
-       RBTDB_UNLOCK(&rbtdb->lock, isc_rwlocktype_write);
+        RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_write);
+        if (rbtdb->task != NULL)
+                isc_task_detach(&rbtdb->task);
+        if (task != NULL)
+                isc_task_attach(task, &rbtdb->task);
+        RBTDB_UNLOCK(&rbtdb->lock, isc_rwlocktype_write);
 }
 
 static isc_boolean_t
 ispersistent(dns_db_t *db) {
-       UNUSED(db);
-       return (ISC_FALSE);
+        UNUSED(db);
+        return (ISC_FALSE);
 }
 
 static isc_result_t
 getoriginnode(dns_db_t *db, dns_dbnode_t **nodep) {
-       dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
-       dns_rbtnode_t *onode;
-       isc_result_t result = ISC_R_SUCCESS;
-
-       REQUIRE(VALID_RBTDB(rbtdb));
-       REQUIRE(nodep != NULL && *nodep == NULL);
-
-       /* Note that the access to origin_node doesn't require a DB lock */
-       onode = (dns_rbtnode_t *)rbtdb->origin_node;
-       if (onode != NULL) {
-               NODE_STRONGLOCK(&rbtdb->node_locks[onode->locknum].lock);
-               new_reference(rbtdb, onode);
-               NODE_STRONGUNLOCK(&rbtdb->node_locks[onode->locknum].lock);
-
-               *nodep = rbtdb->origin_node;
-       } else {
-               INSIST(!IS_CACHE(rbtdb));
-               result = ISC_R_NOTFOUND;
-       }
-
-       return (result);
+        dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
+        dns_rbtnode_t *onode;
+        isc_result_t result = ISC_R_SUCCESS;
+
+        REQUIRE(VALID_RBTDB(rbtdb));
+        REQUIRE(nodep != NULL && *nodep == NULL);
+
+        /* Note that the access to origin_node doesn't require a DB lock */
+        onode = (dns_rbtnode_t *)rbtdb->origin_node;
+        if (onode != NULL) {
+                NODE_STRONGLOCK(&rbtdb->node_locks[onode->locknum].lock);
+                new_reference(rbtdb, onode);
+                NODE_STRONGUNLOCK(&rbtdb->node_locks[onode->locknum].lock);
+
+                *nodep = rbtdb->origin_node;
+        } else {
+                INSIST(!IS_CACHE(rbtdb));
+                result = ISC_R_NOTFOUND;
+        }
+
+        return (result);
 }
 
 static dns_dbmethods_t zone_methods = {
-       attach,
-       detach,
-       beginload,
-       endload,
-       dump,
-       currentversion,
-       newversion,
-       attachversion,
-       closeversion,
-       findnode,
-       zone_find,
-       zone_findzonecut,
-       attachnode,
-       detachnode,
-       expirenode,
-       printnode,
-       createiterator,
-       zone_findrdataset,
-       allrdatasets,
-       addrdataset,
-       subtractrdataset,
-       deleterdataset,
-       issecure,
-       nodecount,
-       ispersistent,
-       overmem,
-       settask,
-       getoriginnode,
-       NULL,
+        attach,
+        detach,
+        beginload,
+        endload,
+        dump,
+        currentversion,
+        newversion,
+        attachversion,
+        closeversion,
+        findnode,
+        zone_find,
+        zone_findzonecut,
+        attachnode,
+        detachnode,
+        expirenode,
+        printnode,
+        createiterator,
+        zone_findrdataset,
+        allrdatasets,
+        addrdataset,
+        subtractrdataset,
+        deleterdataset,
+        issecure,
+        nodecount,
+        ispersistent,
+        overmem,
+        settask,
+        getoriginnode,
+        NULL,
 };
 
 static dns_dbmethods_t cache_methods = {
-       attach,
-       detach,
-       beginload,
-       endload,
-       dump,
-       currentversion,
-       newversion,
-       attachversion,
-       closeversion,
-       findnode,
-       cache_find,
-       cache_findzonecut,
-       attachnode,
-       detachnode,
-       expirenode,
-       printnode,
-       createiterator,
-       cache_findrdataset,
-       allrdatasets,
-       addrdataset,
-       subtractrdataset,
-       deleterdataset,
-       issecure,
-       nodecount,
-       ispersistent,
-       overmem,
-       settask,
-       getoriginnode,
-       NULL
+        attach,
+        detach,
+        beginload,
+        endload,
+        dump,
+        currentversion,
+        newversion,
+        attachversion,
+        closeversion,
+        findnode,
+        cache_find,
+        cache_findzonecut,
+        attachnode,
+        detachnode,
+        expirenode,
+        printnode,
+        createiterator,
+        cache_findrdataset,
+        allrdatasets,
+        addrdataset,
+        subtractrdataset,
+        deleterdataset,
+        issecure,
+        nodecount,
+        ispersistent,
+        overmem,
+        settask,
+        getoriginnode,
+        NULL
 };
 
 isc_result_t
@@ -5443,201 +6085,263 @@ dns_rbtdb64_create
 #else
 dns_rbtdb_create
 #endif
-               (isc_mem_t *mctx, dns_name_t *origin, dns_dbtype_t type,
-                dns_rdataclass_t rdclass, unsigned int argc, char *argv[],
-                void *driverarg, dns_db_t **dbp)
+                (isc_mem_t *mctx, dns_name_t *origin, dns_dbtype_t type,
+                 dns_rdataclass_t rdclass, unsigned int argc, char *argv[],
+                 void *driverarg, dns_db_t **dbp)
 {
-       dns_rbtdb_t *rbtdb;
-       isc_result_t result;
-       int i;
-       dns_name_t name;
-
-       /* Keep the compiler happy. */
-       UNUSED(argc);
-       UNUSED(argv);
-       UNUSED(driverarg);
-
-       rbtdb = isc_mem_get(mctx, sizeof(*rbtdb));
-       if (rbtdb == NULL)
-               return (ISC_R_NOMEMORY);
-
-       memset(rbtdb, '\0', sizeof(*rbtdb));
-       dns_name_init(&rbtdb->common.origin, NULL);
-       rbtdb->common.attributes = 0;
-       if (type == dns_dbtype_cache) {
-               rbtdb->common.methods = &cache_methods;
-               rbtdb->common.attributes |= DNS_DBATTR_CACHE;
-       } else if (type == dns_dbtype_stub) {
-               rbtdb->common.methods = &zone_methods;
-               rbtdb->common.attributes |= DNS_DBATTR_STUB;
-       } else
-               rbtdb->common.methods = &zone_methods;
-       rbtdb->common.rdclass = rdclass;
-       rbtdb->common.mctx = NULL;
-
-       result = RBTDB_INITLOCK(&rbtdb->lock);
-       if (result != ISC_R_SUCCESS)
-               goto cleanup_rbtdb;
-
-       result = isc_rwlock_init(&rbtdb->tree_lock, 0, 0);
-       if (result != ISC_R_SUCCESS)
-               goto cleanup_lock;
-
-       if (rbtdb->node_lock_count == 0) {
-               if (IS_CACHE(rbtdb))
-                       rbtdb->node_lock_count = DEFAULT_CACHE_NODE_LOCK_COUNT;
-               else
-                       rbtdb->node_lock_count = DEFAULT_NODE_LOCK_COUNT;
-       }
-       INSIST(rbtdb->node_lock_count < (1 << DNS_RBT_LOCKLENGTH));
-       rbtdb->node_locks = isc_mem_get(mctx, rbtdb->node_lock_count *
-                                       sizeof(rbtdb_nodelock_t));
-       if (rbtdb->node_locks == NULL) {
-               result = ISC_R_NOMEMORY;
-               goto cleanup_tree_lock;
-       }
-
-       rbtdb->active = rbtdb->node_lock_count;
-
-       for (i = 0; i < (int)(rbtdb->node_lock_count); i++) {
-               result = NODE_INITLOCK(&rbtdb->node_locks[i].lock);
-               if (result == ISC_R_SUCCESS) {
-                       result = isc_refcount_init(&rbtdb->node_locks[i].references, 0);
-                       if (result != ISC_R_SUCCESS)
-                               NODE_DESTROYLOCK(&rbtdb->node_locks[i].lock);
-               }
-               if (result != ISC_R_SUCCESS) {
-                       while (i-- > 0) {
-                               NODE_DESTROYLOCK(&rbtdb->node_locks[i].lock);
-                               isc_refcount_decrement(&rbtdb->node_locks[i].references, NULL);
-                               isc_refcount_destroy(&rbtdb->node_locks[i].references);
-                       }
-                       goto cleanup_node_locks;
-               }
-               rbtdb->node_locks[i].exiting = ISC_FALSE;
-       }
-       
-       /*
-        * Attach to the mctx.  The database will persist so long as there
-        * are references to it, and attaching to the mctx ensures that our
-        * mctx won't disappear out from under us.
-        */
-       isc_mem_attach(mctx, &rbtdb->common.mctx);
-
-       /*
-        * Must be initalized before free_rbtdb() is called.
-        */
-       isc_ondestroy_init(&rbtdb->common.ondest);
-
-       /*
-        * Make a copy of the origin name.
-        */
-       result = dns_name_dupwithoffsets(origin, mctx, &rbtdb->common.origin);
-       if (result != ISC_R_SUCCESS) {
-               free_rbtdb(rbtdb, ISC_FALSE, NULL);
-               return (result);
-       }
-
-       /*
-        * Make the Red-Black Tree.
-        */
-       result = dns_rbt_create(mctx, delete_callback, rbtdb, &rbtdb->tree);
-       if (result != ISC_R_SUCCESS) {
-               free_rbtdb(rbtdb, ISC_FALSE, NULL);
-               return (result);
-       }
-       /*
-        * In order to set the node callback bit correctly in zone databases,
-        * we need to know if the node has the origin name of the zone.
-        * In loading_addrdataset() we could simply compare the new name
-        * to the origin name, but this is expensive.  Also, we don't know the
-        * node name in addrdataset(), so we need another way of knowing the
-        * zone's top.
-        *
-        * We now explicitly create a node for the zone's origin, and then
-        * we simply remember the node's address.  This is safe, because
-        * the top-of-zone node can never be deleted, nor can its address
-        * change.
-        */
-       if (!IS_CACHE(rbtdb)) {
-               rbtdb->origin_node = NULL;
-               result = dns_rbt_addnode(rbtdb->tree, &rbtdb->common.origin,
-                                        &rbtdb->origin_node);
-               if (result != ISC_R_SUCCESS) {
-                       INSIST(result != ISC_R_EXISTS);
-                       free_rbtdb(rbtdb, ISC_FALSE, NULL);
-                       return (result);
-               }
-               /*
-                * We need to give the origin node the right locknum.
-                */
-               dns_name_init(&name, NULL);
-               dns_rbt_namefromnode(rbtdb->origin_node, &name);
+        dns_rbtdb_t *rbtdb;
+        isc_result_t result;
+        int i;
+        dns_name_t name;
+
+        /* Keep the compiler happy. */
+        UNUSED(argc);
+        UNUSED(argv);
+        UNUSED(driverarg);
+
+        rbtdb = isc_mem_get(mctx, sizeof(*rbtdb));
+        if (rbtdb == NULL)
+                return (ISC_R_NOMEMORY);
+
+        memset(rbtdb, '\0', sizeof(*rbtdb));
+        dns_name_init(&rbtdb->common.origin, NULL);
+        rbtdb->common.attributes = 0;
+        if (type == dns_dbtype_cache) {
+                rbtdb->common.methods = &cache_methods;
+                rbtdb->common.attributes |= DNS_DBATTR_CACHE;
+        } else if (type == dns_dbtype_stub) {
+                rbtdb->common.methods = &zone_methods;
+                rbtdb->common.attributes |= DNS_DBATTR_STUB;
+        } else
+                rbtdb->common.methods = &zone_methods;
+        rbtdb->common.rdclass = rdclass;
+        rbtdb->common.mctx = NULL;
+
+        result = RBTDB_INITLOCK(&rbtdb->lock);
+        if (result != ISC_R_SUCCESS)
+                goto cleanup_rbtdb;
+
+        result = isc_rwlock_init(&rbtdb->tree_lock, 0, 0);
+        if (result != ISC_R_SUCCESS)
+                goto cleanup_lock;
+
+        if (rbtdb->node_lock_count == 0) {
+                if (IS_CACHE(rbtdb))
+                        rbtdb->node_lock_count = DEFAULT_CACHE_NODE_LOCK_COUNT;
+                else
+                        rbtdb->node_lock_count = DEFAULT_NODE_LOCK_COUNT;
+        }
+        INSIST(rbtdb->node_lock_count < (1 << DNS_RBT_LOCKLENGTH));
+        rbtdb->node_locks = isc_mem_get(mctx, rbtdb->node_lock_count *
+                                        sizeof(rbtdb_nodelock_t));
+        if (rbtdb->node_locks == NULL) {
+                result = ISC_R_NOMEMORY;
+                goto cleanup_tree_lock;
+        }
+
+        if (IS_CACHE(rbtdb)) {
+                rbtdb->rdatasets = isc_mem_get(mctx, rbtdb->node_lock_count *
+                                               sizeof(rdatasetheaderlist_t));
+                if (rbtdb->rdatasets == NULL) {
+                        result = ISC_R_NOMEMORY;
+                        goto cleanup_node_locks;
+                }
+                for (i = 0; i < (int)rbtdb->node_lock_count; i++)
+                        ISC_LIST_INIT(rbtdb->rdatasets[i]);
+
+                rbtdb->deadnodes = isc_mem_get(mctx, rbtdb->node_lock_count *
+                                               sizeof(rbtnodelist_t));
+                if (rbtdb->deadnodes == NULL) {
+                        result = ISC_R_NOMEMORY;
+                        goto cleanup_rdatasets;
+                }
+                for (i = 0; i < (int)rbtdb->node_lock_count; i++)
+                        ISC_LIST_INIT(rbtdb->deadnodes[i]);
+
+                /*
+                 * Create the heaps.
+                 */
+                rbtdb->heaps = isc_mem_get(mctx, rbtdb->node_lock_count *
+                                           sizeof(isc_heap_t *));
+                if (rbtdb->heaps == NULL) {
+                        result = ISC_R_NOMEMORY;
+                        goto cleanup_deadnodes;
+                }
+                for (i = 0; i < (int)rbtdb->node_lock_count; i++)
+                        rbtdb->heaps[i] = NULL;
+                for (i = 0; i < (int)rbtdb->node_lock_count; i++) {
+                        result = isc_heap_create(mctx, ttl_sooner,
+                                                 ttl_set_index, 0,
+                                                 &rbtdb->heaps[i]);
+                        if (result != ISC_R_SUCCESS)
+                                goto cleanup_heaps;
+                }
+        } else {
+                rbtdb->rdatasets = NULL;
+                rbtdb->deadnodes = NULL;
+                rbtdb->heaps = NULL;
+        }
+
+        rbtdb->active = rbtdb->node_lock_count;
+
+        for (i = 0; i < (int)(rbtdb->node_lock_count); i++) {
+                result = NODE_INITLOCK(&rbtdb->node_locks[i].lock);
+                if (result == ISC_R_SUCCESS) {
+                        result = isc_refcount_init(&rbtdb->node_locks[i].references, 0);
+                        if (result != ISC_R_SUCCESS)
+                                NODE_DESTROYLOCK(&rbtdb->node_locks[i].lock);
+                }
+                if (result != ISC_R_SUCCESS) {
+                        while (i-- > 0) {
+                                NODE_DESTROYLOCK(&rbtdb->node_locks[i].lock);
+                                isc_refcount_decrement(&rbtdb->node_locks[i].references, NULL);
+                                isc_refcount_destroy(&rbtdb->node_locks[i].references);
+                        }
+                        goto cleanup_heaps;
+                }
+                rbtdb->node_locks[i].exiting = ISC_FALSE;
+        }
+
+        /*
+         * Attach to the mctx.  The database will persist so long as there
+         * are references to it, and attaching to the mctx ensures that our
+         * mctx won't disappear out from under us.
+         */
+        isc_mem_attach(mctx, &rbtdb->common.mctx);
+
+        /*
+         * Must be initalized before free_rbtdb() is called.
+         */
+        isc_ondestroy_init(&rbtdb->common.ondest);
+
+        /*
+         * Make a copy of the origin name.
+         */
+        result = dns_name_dupwithoffsets(origin, mctx, &rbtdb->common.origin);
+        if (result != ISC_R_SUCCESS) {
+                free_rbtdb(rbtdb, ISC_FALSE, NULL);
+                return (result);
+        }
+
+        /*
+         * Make the Red-Black Tree.
+         */
+        result = dns_rbt_create(mctx, delete_callback, rbtdb, &rbtdb->tree);
+        if (result != ISC_R_SUCCESS) {
+                free_rbtdb(rbtdb, ISC_FALSE, NULL);
+                return (result);
+        }
+        /*
+         * In order to set the node callback bit correctly in zone databases,
+         * we need to know if the node has the origin name of the zone.
+         * In loading_addrdataset() we could simply compare the new name
+         * to the origin name, but this is expensive.  Also, we don't know the
+         * node name in addrdataset(), so we need another way of knowing the
+         * zone's top.
+         *
+         * We now explicitly create a node for the zone's origin, and then
+         * we simply remember the node's address.  This is safe, because
+         * the top-of-zone node can never be deleted, nor can its address
+         * change.
+         */
+        if (!IS_CACHE(rbtdb)) {
+                rbtdb->origin_node = NULL;
+                result = dns_rbt_addnode(rbtdb->tree, &rbtdb->common.origin,
+                                         &rbtdb->origin_node);
+                if (result != ISC_R_SUCCESS) {
+                        INSIST(result != ISC_R_EXISTS);
+                        free_rbtdb(rbtdb, ISC_FALSE, NULL);
+                        return (result);
+                }
+                /*
+                 * We need to give the origin node the right locknum.
+                 */
+                dns_name_init(&name, NULL);
+                dns_rbt_namefromnode(rbtdb->origin_node, &name);
 #ifdef DNS_RBT_USEHASH
-               rbtdb->origin_node->locknum =
-                       rbtdb->origin_node->hashval %
-                       rbtdb->node_lock_count;
+                rbtdb->origin_node->locknum =
+                        rbtdb->origin_node->hashval %
+                        rbtdb->node_lock_count;
 #else
-               rbtdb->origin_node->locknum =
-                       dns_name_hash(&name, ISC_TRUE) %
-                       rbtdb->node_lock_count;
+                rbtdb->origin_node->locknum =
+                        dns_name_hash(&name, ISC_TRUE) %
+                        rbtdb->node_lock_count;
 #endif
-       }
-
-       /*
-        * Misc. Initialization.
-        */
-       result = isc_refcount_init(&rbtdb->references, 1);
-       if (result != ISC_R_SUCCESS) {
-               free_rbtdb(rbtdb, ISC_FALSE, NULL);
-               return (result);
-       }
-       rbtdb->attributes = 0;
-       rbtdb->secure = ISC_FALSE;
-       rbtdb->overmem = ISC_FALSE;
-       rbtdb->task = NULL;
-
-       /*
-        * Version Initialization.
-        */
-       rbtdb->current_serial = 1;
-       rbtdb->least_serial = 1;
-       rbtdb->next_serial = 2;
-       rbtdb->current_version = allocate_version(mctx, 1, 1, ISC_FALSE);
-       if (rbtdb->current_version == NULL) {
-               isc_refcount_decrement(&rbtdb->references, NULL);
-               isc_refcount_destroy(&rbtdb->references);
-               free_rbtdb(rbtdb, ISC_FALSE, NULL);
-               return (ISC_R_NOMEMORY);
-       }
-       rbtdb->future_version = NULL;
-       ISC_LIST_INIT(rbtdb->open_versions);
-       /*
-        * Keep the current version in the open list so that list operation
-        * won't happen in normal lookup operations.
-        */
-       PREPEND(rbtdb->open_versions, rbtdb->current_version, link);
-
-       rbtdb->common.magic = DNS_DB_MAGIC;
-       rbtdb->common.impmagic = RBTDB_MAGIC;
-
-       *dbp = (dns_db_t *)rbtdb;
-
-       return (ISC_R_SUCCESS);
+        }
+
+        /*
+         * Misc. Initialization.
+         */
+        result = isc_refcount_init(&rbtdb->references, 1);
+        if (result != ISC_R_SUCCESS) {
+                free_rbtdb(rbtdb, ISC_FALSE, NULL);
+                return (result);
+        }
+        rbtdb->attributes = 0;
+        rbtdb->secure = ISC_FALSE;
+        rbtdb->overmem = ISC_FALSE;
+        rbtdb->task = NULL;
+
+        /*
+         * Version Initialization.
+         */
+        rbtdb->current_serial = 1;
+        rbtdb->least_serial = 1;
+        rbtdb->next_serial = 2;
+        rbtdb->current_version = allocate_version(mctx, 1, 1, ISC_FALSE);
+        if (rbtdb->current_version == NULL) {
+                isc_refcount_decrement(&rbtdb->references, NULL);
+                isc_refcount_destroy(&rbtdb->references);
+                free_rbtdb(rbtdb, ISC_FALSE, NULL);
+                return (ISC_R_NOMEMORY);
+        }
+        rbtdb->future_version = NULL;
+        ISC_LIST_INIT(rbtdb->open_versions);
+        /*
+         * Keep the current version in the open list so that list operation
+         * won't happen in normal lookup operations.
+         */
+        PREPEND(rbtdb->open_versions, rbtdb->current_version, link);
+
+        rbtdb->common.magic = DNS_DB_MAGIC;
+        rbtdb->common.impmagic = RBTDB_MAGIC;
+
+        *dbp = (dns_db_t *)rbtdb;
+
+        return (ISC_R_SUCCESS);
+
+ cleanup_heaps:
+        if (rbtdb->heaps != NULL) {
+                for (i = 0 ; i < (int)rbtdb->node_lock_count ; i++)
+                        if (rbtdb->heaps[i] != NULL)
+                                isc_heap_destroy(&rbtdb->heaps[i]);
+                isc_mem_put(mctx, rbtdb->heaps,
+                            rbtdb->node_lock_count * sizeof(isc_heap_t *));
+        }
+
+ cleanup_deadnodes:
+        if (rbtdb->deadnodes != NULL)
+                isc_mem_put(mctx, rbtdb->deadnodes,
+                            rbtdb->node_lock_count * sizeof(rbtnodelist_t));
+
+ cleanup_rdatasets:
+        if (rbtdb->rdatasets != NULL)
+                isc_mem_put(mctx, rbtdb->rdatasets, rbtdb->node_lock_count *
+                            sizeof(rdatasetheaderlist_t));
 
  cleanup_node_locks:
-       isc_mem_put(mctx, rbtdb->node_locks,
-                   rbtdb->node_lock_count * sizeof(rbtdb_nodelock_t));
+        isc_mem_put(mctx, rbtdb->node_locks,
+                    rbtdb->node_lock_count * sizeof(rbtdb_nodelock_t));
 
  cleanup_tree_lock:
-       isc_rwlock_destroy(&rbtdb->tree_lock);
+        isc_rwlock_destroy(&rbtdb->tree_lock);
 
  cleanup_lock:
-       RBTDB_DESTROYLOCK(&rbtdb->lock);
+        RBTDB_DESTROYLOCK(&rbtdb->lock);
 
  cleanup_rbtdb:
-       isc_mem_put(mctx, rbtdb,  sizeof(*rbtdb));
-       return (result);
+        isc_mem_put(mctx, rbtdb,  sizeof(*rbtdb));
+        return (result);
 }
 
 
@@ -5647,178 +6351,178 @@ dns_rbtdb_create
 
 static void
 rdataset_disassociate(dns_rdataset_t *rdataset) {
-       dns_db_t *db = rdataset->private1;
-       dns_dbnode_t *node = rdataset->private2;
+        dns_db_t *db = rdataset->private1;
+        dns_dbnode_t *node = rdataset->private2;
 
-       detachnode(db, &node);
+        detachnode(db, &node);
 }
 
 static isc_result_t
 rdataset_first(dns_rdataset_t *rdataset) {
-       unsigned char *raw = rdataset->private3;        /* RDATASLAB */
-       unsigned int count;
-
-       count = raw[0] * 256 + raw[1];
-       if (count == 0) {
-               rdataset->private5 = NULL;
-               return (ISC_R_NOMORE);
-       }
-       
+        unsigned char *raw = rdataset->private3;        /* RDATASLAB */
+        unsigned int count;
+
+        count = raw[0] * 256 + raw[1];
+        if (count == 0) {
+                rdataset->private5 = NULL;
+                return (ISC_R_NOMORE);
+        }
+
 #if DNS_RDATASET_FIXED
-       if ((rdataset->attributes & DNS_RDATASETATTR_LOADORDER) == 0)
-               raw += 2 + (4 * count);
-       else
+        if ((rdataset->attributes & DNS_RDATASETATTR_LOADORDER) == 0)
+                raw += 2 + (4 * count);
+        else
 #endif
-               raw += 2;
-
-       /*
-        * The privateuint4 field is the number of rdata beyond the
-        * cursor position, so we decrement the total count by one
-        * before storing it.
-        *
-        * If DNS_RDATASETATTR_LOADORDER is not set 'raw' points to the
-        * first record.  If DNS_RDATASETATTR_LOADORDER is set 'raw' points
-        * to the first entry in the offset table.
-        */
-       count--;
-       rdataset->privateuint4 = count;
-       rdataset->private5 = raw;
-
-       return (ISC_R_SUCCESS);
+                raw += 2;
+
+        /*
+         * The privateuint4 field is the number of rdata beyond the
+         * cursor position, so we decrement the total count by one
+         * before storing it.
+         *
+         * If DNS_RDATASETATTR_LOADORDER is not set 'raw' points to the
+         * first record.  If DNS_RDATASETATTR_LOADORDER is set 'raw' points
+         * to the first entry in the offset table.
+         */
+        count--;
+        rdataset->privateuint4 = count;
+        rdataset->private5 = raw;
+
+        return (ISC_R_SUCCESS);
 }
 
 static isc_result_t
 rdataset_next(dns_rdataset_t *rdataset) {
-       unsigned int count;
-       unsigned int length;
-       unsigned char *raw;     /* RDATASLAB */
-
-       count = rdataset->privateuint4;
-       if (count == 0)
-               return (ISC_R_NOMORE);
-       count--;
-       rdataset->privateuint4 = count;
-
-       /*
-        * Skip forward one record (length + 4) or one offset (4).
-        */
-       raw = rdataset->private5;
+        unsigned int count;
+        unsigned int length;
+        unsigned char *raw;     /* RDATASLAB */
+
+        count = rdataset->privateuint4;
+        if (count == 0)
+                return (ISC_R_NOMORE);
+        count--;
+        rdataset->privateuint4 = count;
+
+        /*
+         * Skip forward one record (length + 4) or one offset (4).
+         */
+        raw = rdataset->private5;
 #if DNS_RDATASET_FIXED
-       if ((rdataset->attributes & DNS_RDATASETATTR_LOADORDER) == 0) {
+        if ((rdataset->attributes & DNS_RDATASETATTR_LOADORDER) == 0) {
 #endif
-               length = raw[0] * 256 + raw[1];
-               raw += length;
+                length = raw[0] * 256 + raw[1];
+                raw += length;
 #if DNS_RDATASET_FIXED
-       }
-       rdataset->private5 = raw + 4;           /* length(2) + order(2) */
+        }
+        rdataset->private5 = raw + 4;           /* length(2) + order(2) */
 #else
-       rdataset->private5 = raw + 2;           /* length(2) */
+        rdataset->private5 = raw + 2;           /* length(2) */
 #endif
 
-       return (ISC_R_SUCCESS);
+        return (ISC_R_SUCCESS);
 }
 
 static void
 rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
-       unsigned char *raw = rdataset->private5;        /* RDATASLAB */
+        unsigned char *raw = rdataset->private5;        /* RDATASLAB */
 #if DNS_RDATASET_FIXED
-       unsigned int offset;
+        unsigned int offset;
 #endif
-       isc_region_t r;
+        isc_region_t r;
 
-       REQUIRE(raw != NULL);
+        REQUIRE(raw != NULL);
 
-       /*
-        * Find the start of the record if not already in private5
-        * then skip the length and order fields.
-        */
+        /*
+         * Find the start of the record if not already in private5
+         * then skip the length and order fields.
+         */
 #if DNS_RDATASET_FIXED
-       if ((rdataset->attributes & DNS_RDATASETATTR_LOADORDER) != 0) {
-               offset = (raw[0] << 24) + (raw[1] << 16) +
-                        (raw[2] << 8) + raw[3];
-               raw = rdataset->private3;
-               raw += offset;
-       }
+        if ((rdataset->attributes & DNS_RDATASETATTR_LOADORDER) != 0) {
+                offset = (raw[0] << 24) + (raw[1] << 16) +
+                         (raw[2] << 8) + raw[3];
+                raw = rdataset->private3;
+                raw += offset;
+        }
 #endif
-       r.length = raw[0] * 256 + raw[1];
+        r.length = raw[0] * 256 + raw[1];
 
 #if DNS_RDATASET_FIXED
-       raw += 4;
+        raw += 4;
 #else
-       raw += 2;
+        raw += 2;
 #endif
-       r.base = raw;
-       dns_rdata_fromregion(rdata, rdataset->rdclass, rdataset->type, &r);
+        r.base = raw;
+        dns_rdata_fromregion(rdata, rdataset->rdclass, rdataset->type, &r);
 }
 
 static void
 rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
-       dns_db_t *db = source->private1;
-       dns_dbnode_t *node = source->private2;
-       dns_dbnode_t *cloned_node = NULL;
-
-       attachnode(db, node, &cloned_node);
-       *target = *source;
-
-       /*
-        * Reset iterator state.
-        */
-       target->privateuint4 = 0;
-       target->private5 = NULL;
+        dns_db_t *db = source->private1;
+        dns_dbnode_t *node = source->private2;
+        dns_dbnode_t *cloned_node = NULL;
+
+        attachnode(db, node, &cloned_node);
+        *target = *source;
+
+        /*
+         * Reset iterator state.
+         */
+        target->privateuint4 = 0;
+        target->private5 = NULL;
 }
 
 static unsigned int
 rdataset_count(dns_rdataset_t *rdataset) {
-       unsigned char *raw = rdataset->private3;        /* RDATASLAB */
-       unsigned int count;
+        unsigned char *raw = rdataset->private3;        /* RDATASLAB */
+        unsigned int count;
 
-       count = raw[0] * 256 + raw[1];
+        count = raw[0] * 256 + raw[1];
 
-       return (count);
+        return (count);
 }
 
 static isc_result_t
 rdataset_getnoqname(dns_rdataset_t *rdataset, dns_name_t *name,
-                   dns_rdataset_t *nsec, dns_rdataset_t *nsecsig)
+                    dns_rdataset_t *nsec, dns_rdataset_t *nsecsig)
 {
-       dns_db_t *db = rdataset->private1;
-       dns_dbnode_t *node = rdataset->private2;
-       dns_dbnode_t *cloned_node;
-       struct noqname *noqname = rdataset->private6;
-
-       cloned_node = NULL;
-       attachnode(db, node, &cloned_node);
-       nsec->methods = &rdataset_methods;
-       nsec->rdclass = db->rdclass;
-       nsec->type = dns_rdatatype_nsec;
-       nsec->covers = 0;
-       nsec->ttl = rdataset->ttl;
-       nsec->trust = rdataset->trust;
-       nsec->private1 = rdataset->private1;
-       nsec->private2 = rdataset->private2;
-       nsec->private3 = noqname->nsec;
-       nsec->privateuint4 = 0;
-       nsec->private5 = NULL;
-       nsec->private6 = NULL;
-
-       cloned_node = NULL;
-       attachnode(db, node, &cloned_node);
-       nsecsig->methods = &rdataset_methods;
-       nsecsig->rdclass = db->rdclass;
-       nsecsig->type = dns_rdatatype_rrsig;
-       nsecsig->covers = dns_rdatatype_nsec;
-       nsecsig->ttl = rdataset->ttl;
-       nsecsig->trust = rdataset->trust;
-       nsecsig->private1 = rdataset->private1;
-       nsecsig->private2 = rdataset->private2;
-       nsecsig->private3 = noqname->nsecsig;
-       nsecsig->privateuint4 = 0;
-       nsecsig->private5 = NULL;
-       nsec->private6 = NULL;
-
-       dns_name_clone(&noqname->name, name);
-
-       return (ISC_R_SUCCESS);
+        dns_db_t *db = rdataset->private1;
+        dns_dbnode_t *node = rdataset->private2;
+        dns_dbnode_t *cloned_node;
+        struct noqname *noqname = rdataset->private6;
+
+        cloned_node = NULL;
+        attachnode(db, node, &cloned_node);
+        nsec->methods = &rdataset_methods;
+        nsec->rdclass = db->rdclass;
+        nsec->type = dns_rdatatype_nsec;
+        nsec->covers = 0;
+        nsec->ttl = rdataset->ttl;
+        nsec->trust = rdataset->trust;
+        nsec->private1 = rdataset->private1;
+        nsec->private2 = rdataset->private2;
+        nsec->private3 = noqname->nsec;
+        nsec->privateuint4 = 0;
+        nsec->private5 = NULL;
+        nsec->private6 = NULL;
+
+        cloned_node = NULL;
+        attachnode(db, node, &cloned_node);
+        nsecsig->methods = &rdataset_methods;
+        nsecsig->rdclass = db->rdclass;
+        nsecsig->type = dns_rdatatype_rrsig;
+        nsecsig->covers = dns_rdatatype_nsec;
+        nsecsig->ttl = rdataset->ttl;
+        nsecsig->trust = rdataset->trust;
+        nsecsig->private1 = rdataset->private1;
+        nsecsig->private2 = rdataset->private2;
+        nsecsig->private3 = noqname->nsecsig;
+        nsecsig->privateuint4 = 0;
+        nsecsig->private5 = NULL;
+        nsec->private6 = NULL;
+
+        dns_name_clone(&noqname->name, name);
+
+        return (ISC_R_SUCCESS);
 }
 
 /*
@@ -5827,172 +6531,172 @@ rdataset_getnoqname(dns_rdataset_t *rdataset, dns_name_t *name,
 
 static void
 rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp) {
-       rbtdb_rdatasetiter_t *rbtiterator;
+        rbtdb_rdatasetiter_t *rbtiterator;
 
-       rbtiterator = (rbtdb_rdatasetiter_t *)(*iteratorp);
+        rbtiterator = (rbtdb_rdatasetiter_t *)(*iteratorp);
 
-       if (rbtiterator->common.version != NULL)
-               closeversion(rbtiterator->common.db,
-                            &rbtiterator->common.version, ISC_FALSE);
-       detachnode(rbtiterator->common.db, &rbtiterator->common.node);
-       isc_mem_put(rbtiterator->common.db->mctx, rbtiterator,
-                   sizeof(*rbtiterator));
+        if (rbtiterator->common.version != NULL)
+                closeversion(rbtiterator->common.db,
+                             &rbtiterator->common.version, ISC_FALSE);
+        detachnode(rbtiterator->common.db, &rbtiterator->common.node);
+        isc_mem_put(rbtiterator->common.db->mctx, rbtiterator,
+                    sizeof(*rbtiterator));
 
-       *iteratorp = NULL;
+        *iteratorp = NULL;
 }
 
 static isc_result_t
 rdatasetiter_first(dns_rdatasetiter_t *iterator) {
-       rbtdb_rdatasetiter_t *rbtiterator = (rbtdb_rdatasetiter_t *)iterator;
-       dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)(rbtiterator->common.db);
-       dns_rbtnode_t *rbtnode = rbtiterator->common.node;
-       rbtdb_version_t *rbtversion = rbtiterator->common.version;
-       rdatasetheader_t *header, *top_next;
-       rbtdb_serial_t serial;
-       isc_stdtime_t now;
-
-       if (IS_CACHE(rbtdb)) {
-               serial = 1;
-               now = rbtiterator->common.now;
-       } else {
-               serial = rbtversion->serial;
-               now = 0;
-       }
-
-       NODE_LOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
-                 isc_rwlocktype_read);
-
-       for (header = rbtnode->data; header != NULL; header = top_next) {
-               top_next = header->next;
-               do {
-                       if (header->serial <= serial && !IGNORE(header)) {
-                               /*
-                                * Is this a "this rdataset doesn't exist"
-                                * record?  Or is it too old in the cache?
-                                *
-                                * Note: unlike everywhere else, we
-                                * check for now > header->ttl instead
-                                * of now >= header->ttl.  This allows
-                                * ANY and RRSIG queries for 0 TTL
-                                * rdatasets to work.
-                                */
-                               if (NONEXISTENT(header) ||
-                                   (now != 0 && now > header->ttl))
-                                       header = NULL;
-                               break;
-                       } else
-                               header = header->down;
-               } while (header != NULL);
-               if (header != NULL)
-                       break;
-       }
-
-       NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
-                   isc_rwlocktype_read);
-
-       rbtiterator->current = header;
-
-       if (header == NULL)
-               return (ISC_R_NOMORE);
-
-       return (ISC_R_SUCCESS);
+        rbtdb_rdatasetiter_t *rbtiterator = (rbtdb_rdatasetiter_t *)iterator;
+        dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)(rbtiterator->common.db);
+        dns_rbtnode_t *rbtnode = rbtiterator->common.node;
+        rbtdb_version_t *rbtversion = rbtiterator->common.version;
+        rdatasetheader_t *header, *top_next;
+        rbtdb_serial_t serial;
+        isc_stdtime_t now;
+
+        if (IS_CACHE(rbtdb)) {
+                serial = 1;
+                now = rbtiterator->common.now;
+        } else {
+                serial = rbtversion->serial;
+                now = 0;
+        }
+
+        NODE_LOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
+                  isc_rwlocktype_read);
+
+        for (header = rbtnode->data; header != NULL; header = top_next) {
+                top_next = header->next;
+                do {
+                        if (header->serial <= serial && !IGNORE(header)) {
+                                /*
+                                 * Is this a "this rdataset doesn't exist"
+                                 * record?  Or is it too old in the cache?
+                                 *
+                                 * Note: unlike everywhere else, we
+                                 * check for now > header->ttl instead
+                                 * of now >= header->ttl.  This allows
+                                 * ANY and RRSIG queries for 0 TTL
+                                 * rdatasets to work.
+                                 */
+                                if (NONEXISTENT(header) ||
+                                    (now != 0 && now > header->rdh_ttl))
+                                        header = NULL;
+                                break;
+                        } else
+                                header = header->down;
+                } while (header != NULL);
+                if (header != NULL)
+                        break;
+        }
+
+        NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
+                    isc_rwlocktype_read);
+
+        rbtiterator->current = header;
+
+        if (header == NULL)
+                return (ISC_R_NOMORE);
+
+        return (ISC_R_SUCCESS);
 }
 
 static isc_result_t
 rdatasetiter_next(dns_rdatasetiter_t *iterator) {
-       rbtdb_rdatasetiter_t *rbtiterator = (rbtdb_rdatasetiter_t *)iterator;
-       dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)(rbtiterator->common.db);
-       dns_rbtnode_t *rbtnode = rbtiterator->common.node;
-       rbtdb_version_t *rbtversion = rbtiterator->common.version;
-       rdatasetheader_t *header, *top_next;
-       rbtdb_serial_t serial;
-       isc_stdtime_t now;
-       rbtdb_rdatatype_t type, negtype;
-       dns_rdatatype_t rdtype, covers;
-
-       header = rbtiterator->current;
-       if (header == NULL)
-               return (ISC_R_NOMORE);
-
-       if (IS_CACHE(rbtdb)) {
-               serial = 1;
-               now = rbtiterator->common.now;
-       } else {
-               serial = rbtversion->serial;
-               now = 0;
-       }
-
-       NODE_LOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
-                 isc_rwlocktype_read);
-
-       type = header->type;
-       rdtype = RBTDB_RDATATYPE_BASE(header->type);
-       if (rdtype == 0) {
-               covers = RBTDB_RDATATYPE_EXT(header->type);
-               negtype = RBTDB_RDATATYPE_VALUE(covers, 0);
-       } else 
-               negtype = RBTDB_RDATATYPE_VALUE(0, rdtype);
-       for (header = header->next; header != NULL; header = top_next) {
-               top_next = header->next;
-               /*
-                * If not walking back up the down list.
-                */
-               if (header->type != type && header->type != negtype) {
-                       do {
-                               if (header->serial <= serial &&
-                                   !IGNORE(header)) {
-                                       /*
-                                        * Is this a "this rdataset doesn't
-                                        * exist" record?
-                                        *
-                                        * Note: unlike everywhere else, we
-                                        * check for now > header->ttl instead
-                                        * of now >= header->ttl.  This allows
-                                        * ANY and RRSIG queries for 0 TTL
-                                        * rdatasets to work.
-                                        */
-                                       if ((header->attributes &
-                                            RDATASET_ATTR_NONEXISTENT) != 0 ||
-                                           (now != 0 && now > header->ttl))
-                                               header = NULL;
-                                       break;
-                               } else
-                                       header = header->down;
-                       } while (header != NULL);
-                       if (header != NULL)
-                               break;
-               }
-       }
-
-       NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
-                   isc_rwlocktype_read);
-
-       rbtiterator->current = header;
-
-       if (header == NULL)
-               return (ISC_R_NOMORE);
-
-       return (ISC_R_SUCCESS);
+        rbtdb_rdatasetiter_t *rbtiterator = (rbtdb_rdatasetiter_t *)iterator;
+        dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)(rbtiterator->common.db);
+        dns_rbtnode_t *rbtnode = rbtiterator->common.node;
+        rbtdb_version_t *rbtversion = rbtiterator->common.version;
+        rdatasetheader_t *header, *top_next;
+        rbtdb_serial_t serial;
+        isc_stdtime_t now;
+        rbtdb_rdatatype_t type, negtype;
+        dns_rdatatype_t rdtype, covers;
+
+        header = rbtiterator->current;
+        if (header == NULL)
+                return (ISC_R_NOMORE);
+
+        if (IS_CACHE(rbtdb)) {
+                serial = 1;
+                now = rbtiterator->common.now;
+        } else {
+                serial = rbtversion->serial;
+                now = 0;
+        }
+
+        NODE_LOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
+                  isc_rwlocktype_read);
+
+        type = header->type;
+        rdtype = RBTDB_RDATATYPE_BASE(header->type);
+        if (rdtype == 0) {
+                covers = RBTDB_RDATATYPE_EXT(header->type);
+                negtype = RBTDB_RDATATYPE_VALUE(covers, 0);
+        } else
+                negtype = RBTDB_RDATATYPE_VALUE(0, rdtype);
+        for (header = header->next; header != NULL; header = top_next) {
+                top_next = header->next;
+                /*
+                 * If not walking back up the down list.
+                 */
+                if (header->type != type && header->type != negtype) {
+                        do {
+                                if (header->serial <= serial &&
+                                    !IGNORE(header)) {
+                                        /*
+                                         * Is this a "this rdataset doesn't
+                                         * exist" record?
+                                         *
+                                         * Note: unlike everywhere else, we
+                                         * check for now > header->ttl instead
+                                         * of now >= header->ttl.  This allows
+                                         * ANY and RRSIG queries for 0 TTL
+                                         * rdatasets to work.
+                                         */
+                                        if ((header->attributes &
+                                             RDATASET_ATTR_NONEXISTENT) != 0 ||
+                                            (now != 0 && now > header->rdh_ttl))
+                                                header = NULL;
+                                        break;
+                                } else
+                                        header = header->down;
+                        } while (header != NULL);
+                        if (header != NULL)
+                                break;
+                }
+        }
+
+        NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
+                    isc_rwlocktype_read);
+
+        rbtiterator->current = header;
+
+        if (header == NULL)
+                return (ISC_R_NOMORE);
+
+        return (ISC_R_SUCCESS);
 }
 
 static void
 rdatasetiter_current(dns_rdatasetiter_t *iterator, dns_rdataset_t *rdataset) {
-       rbtdb_rdatasetiter_t *rbtiterator = (rbtdb_rdatasetiter_t *)iterator;
-       dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)(rbtiterator->common.db);
-       dns_rbtnode_t *rbtnode = rbtiterator->common.node;
-       rdatasetheader_t *header;
+        rbtdb_rdatasetiter_t *rbtiterator = (rbtdb_rdatasetiter_t *)iterator;
+        dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)(rbtiterator->common.db);
+        dns_rbtnode_t *rbtnode = rbtiterator->common.node;
+        rdatasetheader_t *header;
 
-       header = rbtiterator->current;
-       REQUIRE(header != NULL);
+        header = rbtiterator->current;
+        REQUIRE(header != NULL);
 
-       NODE_LOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
-                 isc_rwlocktype_read);
+        NODE_LOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
+                  isc_rwlocktype_read);
 
-       bind_rdataset(rbtdb, rbtnode, header, rbtiterator->common.now,
-                     rdataset);
+        bind_rdataset(rbtdb, rbtnode, header, rbtiterator->common.now,
+                      rdataset);
 
-       NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
-                   isc_rwlocktype_read);
+        NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
+                    isc_rwlocktype_read);
 }
 
 
@@ -6002,410 +6706,410 @@ rdatasetiter_current(dns_rdatasetiter_t *iterator, dns_rdataset_t *rdataset) {
 
 static inline void
 reference_iter_node(rbtdb_dbiterator_t *rbtdbiter) {
-       dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)rbtdbiter->common.db;
-       dns_rbtnode_t *node = rbtdbiter->node;
+        dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)rbtdbiter->common.db;
+        dns_rbtnode_t *node = rbtdbiter->node;
 
-       if (node == NULL)
-               return;
+        if (node == NULL)
+                return;
 
-       INSIST(rbtdbiter->tree_locked != isc_rwlocktype_none);
-       NODE_STRONGLOCK(&rbtdb->node_locks[node->locknum].lock);
-       new_reference(rbtdb, node);
-       NODE_STRONGUNLOCK(&rbtdb->node_locks[node->locknum].lock);
+        INSIST(rbtdbiter->tree_locked != isc_rwlocktype_none);
+        NODE_STRONGLOCK(&rbtdb->node_locks[node->locknum].lock);
+        new_reference(rbtdb, node);
+        NODE_STRONGUNLOCK(&rbtdb->node_locks[node->locknum].lock);
 }
 
 static inline void
 dereference_iter_node(rbtdb_dbiterator_t *rbtdbiter) {
-       dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)rbtdbiter->common.db;
-       dns_rbtnode_t *node = rbtdbiter->node;
-       nodelock_t *lock;
+        dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)rbtdbiter->common.db;
+        dns_rbtnode_t *node = rbtdbiter->node;
+        nodelock_t *lock;
 
-       if (node == NULL)
-               return;
+        if (node == NULL)
+                return;
 
-       lock = &rbtdb->node_locks[node->locknum].lock;
-       NODE_LOCK(lock, isc_rwlocktype_read);
-       decrement_reference(rbtdb, node, 0, isc_rwlocktype_read,
-                           rbtdbiter->tree_locked);
-       NODE_UNLOCK(lock, isc_rwlocktype_read);
+        lock = &rbtdb->node_locks[node->locknum].lock;
+        NODE_LOCK(lock, isc_rwlocktype_read);
+        decrement_reference(rbtdb, node, 0, isc_rwlocktype_read,
+                            rbtdbiter->tree_locked);
+        NODE_UNLOCK(lock, isc_rwlocktype_read);
 
-       rbtdbiter->node = NULL;
+        rbtdbiter->node = NULL;
 }
 
 static void
 flush_deletions(rbtdb_dbiterator_t *rbtdbiter) {
-       dns_rbtnode_t *node;
-       dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)rbtdbiter->common.db;
-       isc_boolean_t was_read_locked = ISC_FALSE;
-       nodelock_t *lock;
-       int i;
-
-       if (rbtdbiter->delete != 0) {
-               /*
-                * Note that "%d node of %d in tree" can report things like
-                * "flush_deletions: 59 nodes of 41 in tree".  This means
-                * That some nodes appear on the deletions list more than
-                * once.  Only the last occurence will actually be deleted.
-                */
-               isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
-                             DNS_LOGMODULE_CACHE, ISC_LOG_DEBUG(1),
-                             "flush_deletions: %d nodes of %d in tree",
-                             rbtdbiter->delete,
-                             dns_rbt_nodecount(rbtdb->tree));
-
-               if (rbtdbiter->tree_locked == isc_rwlocktype_read) {
-                       RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
-                       was_read_locked = ISC_TRUE;
-               }
-               RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_write);
-               rbtdbiter->tree_locked = isc_rwlocktype_write;
-
-               for (i = 0; i < rbtdbiter->delete; i++) {
-                       node = rbtdbiter->deletions[i];
-                       lock = &rbtdb->node_locks[node->locknum].lock;
-
-                       NODE_LOCK(lock, isc_rwlocktype_read);
-                       decrement_reference(rbtdb, node, 0,
-                                           isc_rwlocktype_read,
-                                           rbtdbiter->tree_locked);
-                       NODE_UNLOCK(lock, isc_rwlocktype_read);
-               }
-
-               rbtdbiter->delete = 0;
-
-               RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_write);
-               if (was_read_locked) {
-                       RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
-                       rbtdbiter->tree_locked = isc_rwlocktype_read;
-
-               } else {
-                       rbtdbiter->tree_locked = isc_rwlocktype_none;
-               }
-       }
+        dns_rbtnode_t *node;
+        dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)rbtdbiter->common.db;
+        isc_boolean_t was_read_locked = ISC_FALSE;
+        nodelock_t *lock;
+        int i;
+
+        if (rbtdbiter->delete != 0) {
+                /*
+                 * Note that "%d node of %d in tree" can report things like
+                 * "flush_deletions: 59 nodes of 41 in tree".  This means
+                 * That some nodes appear on the deletions list more than
+                 * once.  Only the last occurence will actually be deleted.
+                 */
+                isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+                              DNS_LOGMODULE_CACHE, ISC_LOG_DEBUG(1),
+                              "flush_deletions: %d nodes of %d in tree",
+                              rbtdbiter->delete,
+                              dns_rbt_nodecount(rbtdb->tree));
+
+                if (rbtdbiter->tree_locked == isc_rwlocktype_read) {
+                        RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
+                        was_read_locked = ISC_TRUE;
+                }
+                RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_write);
+                rbtdbiter->tree_locked = isc_rwlocktype_write;
+
+                for (i = 0; i < rbtdbiter->delete; i++) {
+                        node = rbtdbiter->deletions[i];
+                        lock = &rbtdb->node_locks[node->locknum].lock;
+
+                        NODE_LOCK(lock, isc_rwlocktype_read);
+                        decrement_reference(rbtdb, node, 0,
+                                            isc_rwlocktype_read,
+                                            rbtdbiter->tree_locked);
+                        NODE_UNLOCK(lock, isc_rwlocktype_read);
+                }
+
+                rbtdbiter->delete = 0;
+
+                RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_write);
+                if (was_read_locked) {
+                        RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
+                        rbtdbiter->tree_locked = isc_rwlocktype_read;
+
+                } else {
+                        rbtdbiter->tree_locked = isc_rwlocktype_none;
+                }
+        }
 }
 
 static inline void
 resume_iteration(rbtdb_dbiterator_t *rbtdbiter) {
-       dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)rbtdbiter->common.db;
+        dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)rbtdbiter->common.db;
 
-       REQUIRE(rbtdbiter->paused);
-       REQUIRE(rbtdbiter->tree_locked == isc_rwlocktype_none);
+        REQUIRE(rbtdbiter->paused);
+        REQUIRE(rbtdbiter->tree_locked == isc_rwlocktype_none);
 
-       RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
-       rbtdbiter->tree_locked = isc_rwlocktype_read;
+        RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
+        rbtdbiter->tree_locked = isc_rwlocktype_read;
 
-       rbtdbiter->paused = ISC_FALSE;
+        rbtdbiter->paused = ISC_FALSE;
 }
 
 static void
 dbiterator_destroy(dns_dbiterator_t **iteratorp) {
-       rbtdb_dbiterator_t *rbtdbiter = (rbtdb_dbiterator_t *)(*iteratorp);
-       dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)rbtdbiter->common.db;
-       dns_db_t *db = NULL;
+        rbtdb_dbiterator_t *rbtdbiter = (rbtdb_dbiterator_t *)(*iteratorp);
+        dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)rbtdbiter->common.db;
+        dns_db_t *db = NULL;
 
-       if (rbtdbiter->tree_locked == isc_rwlocktype_read) {
-               RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
-               rbtdbiter->tree_locked = isc_rwlocktype_none;
-       } else
-               INSIST(rbtdbiter->tree_locked == isc_rwlocktype_none);
+        if (rbtdbiter->tree_locked == isc_rwlocktype_read) {
+                RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
+                rbtdbiter->tree_locked = isc_rwlocktype_none;
+        } else
+                INSIST(rbtdbiter->tree_locked == isc_rwlocktype_none);
 
-       dereference_iter_node(rbtdbiter);
+        dereference_iter_node(rbtdbiter);
 
-       flush_deletions(rbtdbiter);
+        flush_deletions(rbtdbiter);
 
-       dns_db_attach(rbtdbiter->common.db, &db);
-       dns_db_detach(&rbtdbiter->common.db);
+        dns_db_attach(rbtdbiter->common.db, &db);
+        dns_db_detach(&rbtdbiter->common.db);
 
-       dns_rbtnodechain_reset(&rbtdbiter->chain);
-       isc_mem_put(db->mctx, rbtdbiter, sizeof(*rbtdbiter));
-       dns_db_detach(&db);
+        dns_rbtnodechain_reset(&rbtdbiter->chain);
+        isc_mem_put(db->mctx, rbtdbiter, sizeof(*rbtdbiter));
+        dns_db_detach(&db);
 
-       *iteratorp = NULL;
+        *iteratorp = NULL;
 }
 
 static isc_result_t
 dbiterator_first(dns_dbiterator_t *iterator) {
-       isc_result_t result;
-       rbtdb_dbiterator_t *rbtdbiter = (rbtdb_dbiterator_t *)iterator;
-       dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)iterator->db;
-       dns_name_t *name, *origin;
-
-       if (rbtdbiter->result != ISC_R_SUCCESS &&
-           rbtdbiter->result != ISC_R_NOMORE)
-               return (rbtdbiter->result);
-
-       if (rbtdbiter->paused)
-               resume_iteration(rbtdbiter);
-
-       dereference_iter_node(rbtdbiter);
-
-       name = dns_fixedname_name(&rbtdbiter->name);
-       origin = dns_fixedname_name(&rbtdbiter->origin);
-       dns_rbtnodechain_reset(&rbtdbiter->chain);
-
-       result = dns_rbtnodechain_first(&rbtdbiter->chain, rbtdb->tree, name,
-                                       origin);
-
-       if (result == ISC_R_SUCCESS || result == DNS_R_NEWORIGIN) {
-               result = dns_rbtnodechain_current(&rbtdbiter->chain, NULL,
-                                                 NULL, &rbtdbiter->node);
-               if (result == ISC_R_SUCCESS) {
-                       rbtdbiter->new_origin = ISC_TRUE;
-                       reference_iter_node(rbtdbiter);
-               }
-       } else {
-               INSIST(result == ISC_R_NOTFOUND);
-               result = ISC_R_NOMORE; /* The tree is empty. */
-       }
-
-       rbtdbiter->result = result;
-
-       return (result);
+        isc_result_t result;
+        rbtdb_dbiterator_t *rbtdbiter = (rbtdb_dbiterator_t *)iterator;
+        dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)iterator->db;
+        dns_name_t *name, *origin;
+
+        if (rbtdbiter->result != ISC_R_SUCCESS &&
+            rbtdbiter->result != ISC_R_NOMORE)
+                return (rbtdbiter->result);
+
+        if (rbtdbiter->paused)
+                resume_iteration(rbtdbiter);
+
+        dereference_iter_node(rbtdbiter);
+
+        name = dns_fixedname_name(&rbtdbiter->name);
+        origin = dns_fixedname_name(&rbtdbiter->origin);
+        dns_rbtnodechain_reset(&rbtdbiter->chain);
+
+        result = dns_rbtnodechain_first(&rbtdbiter->chain, rbtdb->tree, name,
+                                        origin);
+
+        if (result == ISC_R_SUCCESS || result == DNS_R_NEWORIGIN) {
+                result = dns_rbtnodechain_current(&rbtdbiter->chain, NULL,
+                                                  NULL, &rbtdbiter->node);
+                if (result == ISC_R_SUCCESS) {
+                        rbtdbiter->new_origin = ISC_TRUE;
+                        reference_iter_node(rbtdbiter);
+                }
+        } else {
+                INSIST(result == ISC_R_NOTFOUND);
+                result = ISC_R_NOMORE; /* The tree is empty. */
+        }
+
+        rbtdbiter->result = result;
+
+        return (result);
 }
 
 static isc_result_t
 dbiterator_last(dns_dbiterator_t *iterator) {
-       isc_result_t result;
-       rbtdb_dbiterator_t *rbtdbiter = (rbtdb_dbiterator_t *)iterator;
-       dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)iterator->db;
-       dns_name_t *name, *origin;
-
-       if (rbtdbiter->result != ISC_R_SUCCESS &&
-           rbtdbiter->result != ISC_R_NOMORE)
-               return (rbtdbiter->result);
-
-       if (rbtdbiter->paused)
-               resume_iteration(rbtdbiter);
-
-       dereference_iter_node(rbtdbiter);
-
-       name = dns_fixedname_name(&rbtdbiter->name);
-       origin = dns_fixedname_name(&rbtdbiter->origin);
-       dns_rbtnodechain_reset(&rbtdbiter->chain);
-
-       result = dns_rbtnodechain_last(&rbtdbiter->chain, rbtdb->tree, name,
-                                      origin);
-       if (result == ISC_R_SUCCESS || result == DNS_R_NEWORIGIN) {
-               result = dns_rbtnodechain_current(&rbtdbiter->chain, NULL,
-                                                 NULL, &rbtdbiter->node);
-               if (result == ISC_R_SUCCESS) {
-                       rbtdbiter->new_origin = ISC_TRUE;
-                       reference_iter_node(rbtdbiter);
-               }
-       } else {
-               INSIST(result == ISC_R_NOTFOUND);
-               result = ISC_R_NOMORE; /* The tree is empty. */
-       }
-
-       rbtdbiter->result = result;
-
-       return (result);
+        isc_result_t result;
+        rbtdb_dbiterator_t *rbtdbiter = (rbtdb_dbiterator_t *)iterator;
+        dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)iterator->db;
+        dns_name_t *name, *origin;
+
+        if (rbtdbiter->result != ISC_R_SUCCESS &&
+            rbtdbiter->result != ISC_R_NOMORE)
+                return (rbtdbiter->result);
+
+        if (rbtdbiter->paused)
+                resume_iteration(rbtdbiter);
+
+        dereference_iter_node(rbtdbiter);
+
+        name = dns_fixedname_name(&rbtdbiter->name);
+        origin = dns_fixedname_name(&rbtdbiter->origin);
+        dns_rbtnodechain_reset(&rbtdbiter->chain);
+
+        result = dns_rbtnodechain_last(&rbtdbiter->chain, rbtdb->tree, name,
+                                       origin);
+        if (result == ISC_R_SUCCESS || result == DNS_R_NEWORIGIN) {
+                result = dns_rbtnodechain_current(&rbtdbiter->chain, NULL,
+                                                  NULL, &rbtdbiter->node);
+                if (result == ISC_R_SUCCESS) {
+                        rbtdbiter->new_origin = ISC_TRUE;
+                        reference_iter_node(rbtdbiter);
+                }
+        } else {
+                INSIST(result == ISC_R_NOTFOUND);
+                result = ISC_R_NOMORE; /* The tree is empty. */
+        }
+
+        rbtdbiter->result = result;
+
+        return (result);
 }
 
 static isc_result_t
 dbiterator_seek(dns_dbiterator_t *iterator, dns_name_t *name) {
-       isc_result_t result;
-       rbtdb_dbiterator_t *rbtdbiter = (rbtdb_dbiterator_t *)iterator;
-       dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)iterator->db;
-       dns_name_t *iname, *origin;
+        isc_result_t result;
+        rbtdb_dbiterator_t *rbtdbiter = (rbtdb_dbiterator_t *)iterator;
+        dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)iterator->db;
+        dns_name_t *iname, *origin;
 
-       if (rbtdbiter->result != ISC_R_SUCCESS &&
-           rbtdbiter->result != ISC_R_NOMORE)
-               return (rbtdbiter->result);
+        if (rbtdbiter->result != ISC_R_SUCCESS &&
+            rbtdbiter->result != ISC_R_NOMORE)
+                return (rbtdbiter->result);
 
-       if (rbtdbiter->paused)
-               resume_iteration(rbtdbiter);
+        if (rbtdbiter->paused)
+                resume_iteration(rbtdbiter);
 
-       dereference_iter_node(rbtdbiter);
+        dereference_iter_node(rbtdbiter);
 
-       iname = dns_fixedname_name(&rbtdbiter->name);
-       origin = dns_fixedname_name(&rbtdbiter->origin);
-       dns_rbtnodechain_reset(&rbtdbiter->chain);
+        iname = dns_fixedname_name(&rbtdbiter->name);
+        origin = dns_fixedname_name(&rbtdbiter->origin);
+        dns_rbtnodechain_reset(&rbtdbiter->chain);
 
-       result = dns_rbt_findnode(rbtdb->tree, name, NULL, &rbtdbiter->node,
-                                 &rbtdbiter->chain, DNS_RBTFIND_EMPTYDATA,
-                                 NULL, NULL);
-       if (result == ISC_R_SUCCESS) {
-               result = dns_rbtnodechain_current(&rbtdbiter->chain, iname,
-                                                 origin, NULL);
-               if (result == ISC_R_SUCCESS) {
-                       rbtdbiter->new_origin = ISC_TRUE;
-                       reference_iter_node(rbtdbiter);
-               }
+        result = dns_rbt_findnode(rbtdb->tree, name, NULL, &rbtdbiter->node,
+                                  &rbtdbiter->chain, DNS_RBTFIND_EMPTYDATA,
+                                  NULL, NULL);
+        if (result == ISC_R_SUCCESS) {
+                result = dns_rbtnodechain_current(&rbtdbiter->chain, iname,
+                                                  origin, NULL);
+                if (result == ISC_R_SUCCESS) {
+                        rbtdbiter->new_origin = ISC_TRUE;
+                        reference_iter_node(rbtdbiter);
+                }
 
-       } else if (result == DNS_R_PARTIALMATCH)
-               result = ISC_R_NOTFOUND;
+        } else if (result == DNS_R_PARTIALMATCH)
+                result = ISC_R_NOTFOUND;
 
-       rbtdbiter->result = result;
+        rbtdbiter->result = result;
 
-       return (result);
+        return (result);
 }
 
 static isc_result_t
 dbiterator_prev(dns_dbiterator_t *iterator) {
-       isc_result_t result;
-       rbtdb_dbiterator_t *rbtdbiter = (rbtdb_dbiterator_t *)iterator;
-       dns_name_t *name, *origin;
+        isc_result_t result;
+        rbtdb_dbiterator_t *rbtdbiter = (rbtdb_dbiterator_t *)iterator;
+        dns_name_t *name, *origin;
 
-       REQUIRE(rbtdbiter->node != NULL);
+        REQUIRE(rbtdbiter->node != NULL);
 
-       if (rbtdbiter->result != ISC_R_SUCCESS)
-               return (rbtdbiter->result);
+        if (rbtdbiter->result != ISC_R_SUCCESS)
+                return (rbtdbiter->result);
 
-       if (rbtdbiter->paused)
-               resume_iteration(rbtdbiter);
+        if (rbtdbiter->paused)
+                resume_iteration(rbtdbiter);
 
-       name = dns_fixedname_name(&rbtdbiter->name);
-       origin = dns_fixedname_name(&rbtdbiter->origin);
-       result = dns_rbtnodechain_prev(&rbtdbiter->chain, name, origin);
+        name = dns_fixedname_name(&rbtdbiter->name);
+        origin = dns_fixedname_name(&rbtdbiter->origin);
+        result = dns_rbtnodechain_prev(&rbtdbiter->chain, name, origin);
 
-       dereference_iter_node(rbtdbiter);
+        dereference_iter_node(rbtdbiter);
 
-       if (result == DNS_R_NEWORIGIN || result == ISC_R_SUCCESS) {
-               rbtdbiter->new_origin = ISC_TF(result == DNS_R_NEWORIGIN);
-               result = dns_rbtnodechain_current(&rbtdbiter->chain, NULL,
-                                                 NULL, &rbtdbiter->node);
-       }
+        if (result == DNS_R_NEWORIGIN || result == ISC_R_SUCCESS) {
+                rbtdbiter->new_origin = ISC_TF(result == DNS_R_NEWORIGIN);
+                result = dns_rbtnodechain_current(&rbtdbiter->chain, NULL,
+                                                  NULL, &rbtdbiter->node);
+        }
 
-       if (result == ISC_R_SUCCESS)
-               reference_iter_node(rbtdbiter);
+        if (result == ISC_R_SUCCESS)
+                reference_iter_node(rbtdbiter);
 
-       rbtdbiter->result = result;
+        rbtdbiter->result = result;
 
-       return (result);
+        return (result);
 }
 
 static isc_result_t
 dbiterator_next(dns_dbiterator_t *iterator) {
-       isc_result_t result;
-       rbtdb_dbiterator_t *rbtdbiter = (rbtdb_dbiterator_t *)iterator;
-       dns_name_t *name, *origin;
+        isc_result_t result;
+        rbtdb_dbiterator_t *rbtdbiter = (rbtdb_dbiterator_t *)iterator;
+        dns_name_t *name, *origin;
 
-       REQUIRE(rbtdbiter->node != NULL);
+        REQUIRE(rbtdbiter->node != NULL);
 
-       if (rbtdbiter->result != ISC_R_SUCCESS)
-               return (rbtdbiter->result);
+        if (rbtdbiter->result != ISC_R_SUCCESS)
+                return (rbtdbiter->result);
 
-       if (rbtdbiter->paused)
-               resume_iteration(rbtdbiter);
+        if (rbtdbiter->paused)
+                resume_iteration(rbtdbiter);
 
-       name = dns_fixedname_name(&rbtdbiter->name);
-       origin = dns_fixedname_name(&rbtdbiter->origin);
-       result = dns_rbtnodechain_next(&rbtdbiter->chain, name, origin);
+        name = dns_fixedname_name(&rbtdbiter->name);
+        origin = dns_fixedname_name(&rbtdbiter->origin);
+        result = dns_rbtnodechain_next(&rbtdbiter->chain, name, origin);
 
-       dereference_iter_node(rbtdbiter);
+        dereference_iter_node(rbtdbiter);
 
-       if (result == DNS_R_NEWORIGIN || result == ISC_R_SUCCESS) {
-               rbtdbiter->new_origin = ISC_TF(result == DNS_R_NEWORIGIN);
-               result = dns_rbtnodechain_current(&rbtdbiter->chain, NULL,
-                                                 NULL, &rbtdbiter->node);
-       }
-       if (result == ISC_R_SUCCESS)
-               reference_iter_node(rbtdbiter);
+        if (result == DNS_R_NEWORIGIN || result == ISC_R_SUCCESS) {
+                rbtdbiter->new_origin = ISC_TF(result == DNS_R_NEWORIGIN);
+                result = dns_rbtnodechain_current(&rbtdbiter->chain, NULL,
+                                                  NULL, &rbtdbiter->node);
+        }
+        if (result == ISC_R_SUCCESS)
+                reference_iter_node(rbtdbiter);
 
-       rbtdbiter->result = result;
+        rbtdbiter->result = result;
 
-       return (result);
+        return (result);
 }
 
 static isc_result_t
 dbiterator_current(dns_dbiterator_t *iterator, dns_dbnode_t **nodep,
-                  dns_name_t *name)
+                   dns_name_t *name)
 {
-       dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)iterator->db;
-       rbtdb_dbiterator_t *rbtdbiter = (rbtdb_dbiterator_t *)iterator;
-       dns_rbtnode_t *node = rbtdbiter->node;
-       isc_result_t result;
-       dns_name_t *nodename = dns_fixedname_name(&rbtdbiter->name);
-       dns_name_t *origin = dns_fixedname_name(&rbtdbiter->origin);
-
-       REQUIRE(rbtdbiter->result == ISC_R_SUCCESS);
-       REQUIRE(rbtdbiter->node != NULL);
-
-       if (rbtdbiter->paused)
-               resume_iteration(rbtdbiter);
-
-       if (name != NULL) {
-               if (rbtdbiter->common.relative_names)
-                       origin = NULL;
-               result = dns_name_concatenate(nodename, origin, name, NULL);
-               if (result != ISC_R_SUCCESS)
-                       return (result);
-               if (rbtdbiter->common.relative_names && rbtdbiter->new_origin)
-                       result = DNS_R_NEWORIGIN;
-       } else
-               result = ISC_R_SUCCESS;
-
-       NODE_STRONGLOCK(&rbtdb->node_locks[node->locknum].lock);
-       new_reference(rbtdb, node);
-       NODE_STRONGUNLOCK(&rbtdb->node_locks[node->locknum].lock);
-
-       *nodep = rbtdbiter->node;
-
-       if (iterator->cleaning && result == ISC_R_SUCCESS) {
-               isc_result_t expire_result;
-
-               /*
-                * If the deletion array is full, flush it before trying
-                * to expire the current node.  The current node can't
-                * fully deleted while the iteration cursor is still on it.
-                */
-               if (rbtdbiter->delete == DELETION_BATCH_MAX)
-                       flush_deletions(rbtdbiter);
-
-               expire_result = expirenode(iterator->db, *nodep, 0);
-
-               /*
-                * expirenode() currently always returns success.
-                */
-               if (expire_result == ISC_R_SUCCESS && node->down == NULL) {
-                       unsigned int refs;
-
-                       rbtdbiter->deletions[rbtdbiter->delete++] = node;
-                       NODE_STRONGLOCK(&rbtdb->node_locks[node->locknum].lock);
-                       dns_rbtnode_refincrement(node, &refs);
-                       INSIST(refs != 0);
-                       NODE_STRONGUNLOCK(&rbtdb->node_locks[node->locknum].lock);
-               }
-       }
-
-       return (result);
+        dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)iterator->db;
+        rbtdb_dbiterator_t *rbtdbiter = (rbtdb_dbiterator_t *)iterator;
+        dns_rbtnode_t *node = rbtdbiter->node;
+        isc_result_t result;
+        dns_name_t *nodename = dns_fixedname_name(&rbtdbiter->name);
+        dns_name_t *origin = dns_fixedname_name(&rbtdbiter->origin);
+
+        REQUIRE(rbtdbiter->result == ISC_R_SUCCESS);
+        REQUIRE(rbtdbiter->node != NULL);
+
+        if (rbtdbiter->paused)
+                resume_iteration(rbtdbiter);
+
+        if (name != NULL) {
+                if (rbtdbiter->common.relative_names)
+                        origin = NULL;
+                result = dns_name_concatenate(nodename, origin, name, NULL);
+                if (result != ISC_R_SUCCESS)
+                        return (result);
+                if (rbtdbiter->common.relative_names && rbtdbiter->new_origin)
+                        result = DNS_R_NEWORIGIN;
+        } else
+                result = ISC_R_SUCCESS;
+
+        NODE_STRONGLOCK(&rbtdb->node_locks[node->locknum].lock);
+        new_reference(rbtdb, node);
+        NODE_STRONGUNLOCK(&rbtdb->node_locks[node->locknum].lock);
+
+        *nodep = rbtdbiter->node;
+
+        if (iterator->cleaning && result == ISC_R_SUCCESS) {
+                isc_result_t expire_result;
+
+                /*
+                 * If the deletion array is full, flush it before trying
+                 * to expire the current node.  The current node can't
+                 * fully deleted while the iteration cursor is still on it.
+                 */
+                if (rbtdbiter->delete == DELETION_BATCH_MAX)
+                        flush_deletions(rbtdbiter);
+
+                expire_result = expirenode(iterator->db, *nodep, 0);
+
+                /*
+                 * expirenode() currently always returns success.
+                 */
+                if (expire_result == ISC_R_SUCCESS && node->down == NULL) {
+                        unsigned int refs;
+
+                        rbtdbiter->deletions[rbtdbiter->delete++] = node;
+                        NODE_STRONGLOCK(&rbtdb->node_locks[node->locknum].lock);
+                        dns_rbtnode_refincrement(node, &refs);
+                        INSIST(refs != 0);
+                        NODE_STRONGUNLOCK(&rbtdb->node_locks[node->locknum].lock);
+                }
+        }
+
+        return (result);
 }
 
 static isc_result_t
 dbiterator_pause(dns_dbiterator_t *iterator) {
-       dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)iterator->db;
-       rbtdb_dbiterator_t *rbtdbiter = (rbtdb_dbiterator_t *)iterator;
+        dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)iterator->db;
+        rbtdb_dbiterator_t *rbtdbiter = (rbtdb_dbiterator_t *)iterator;
 
-       if (rbtdbiter->result != ISC_R_SUCCESS &&
-           rbtdbiter->result != ISC_R_NOMORE)
-               return (rbtdbiter->result);
+        if (rbtdbiter->result != ISC_R_SUCCESS &&
+            rbtdbiter->result != ISC_R_NOMORE)
+                return (rbtdbiter->result);
 
-       if (rbtdbiter->paused)
-               return (ISC_R_SUCCESS);
+        if (rbtdbiter->paused)
+                return (ISC_R_SUCCESS);
 
-       rbtdbiter->paused = ISC_TRUE;
+        rbtdbiter->paused = ISC_TRUE;
 
-       if (rbtdbiter->tree_locked != isc_rwlocktype_none) {
-               INSIST(rbtdbiter->tree_locked == isc_rwlocktype_read);
-               RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
-               rbtdbiter->tree_locked = isc_rwlocktype_none;
-       }
+        if (rbtdbiter->tree_locked != isc_rwlocktype_none) {
+                INSIST(rbtdbiter->tree_locked == isc_rwlocktype_read);
+                RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
+                rbtdbiter->tree_locked = isc_rwlocktype_none;
+        }
 
-       flush_deletions(rbtdbiter);
+        flush_deletions(rbtdbiter);
 
-       return (ISC_R_SUCCESS);
+        return (ISC_R_SUCCESS);
 }
 
 static isc_result_t
 dbiterator_origin(dns_dbiterator_t *iterator, dns_name_t *name) {
-       rbtdb_dbiterator_t *rbtdbiter = (rbtdb_dbiterator_t *)iterator;
-       dns_name_t *origin = dns_fixedname_name(&rbtdbiter->origin);
+        rbtdb_dbiterator_t *rbtdbiter = (rbtdb_dbiterator_t *)iterator;
+        dns_name_t *origin = dns_fixedname_name(&rbtdbiter->origin);
 
-       if (rbtdbiter->result != ISC_R_SUCCESS)
-               return (rbtdbiter->result);
+        if (rbtdbiter->result != ISC_R_SUCCESS)
+                return (rbtdbiter->result);
 
-       return (dns_name_copy(origin, name, NULL));
+        return (dns_name_copy(origin, name, NULL));
 }
 
 /*%
@@ -6413,350 +7117,513 @@ dbiterator_origin(dns_dbiterator_t *iterator, dns_name_t *name) {
  */
 static isc_result_t
 rdataset_getadditional(dns_rdataset_t *rdataset, dns_rdatasetadditional_t type,
-                      dns_rdatatype_t qtype, dns_acache_t *acache,
-                      dns_zone_t **zonep, dns_db_t **dbp,
-                      dns_dbversion_t **versionp, dns_dbnode_t **nodep,
-                      dns_name_t *fname, dns_message_t *msg,
-                      isc_stdtime_t now)
+                       dns_rdatatype_t qtype, dns_acache_t *acache,
+                       dns_zone_t **zonep, dns_db_t **dbp,
+                       dns_dbversion_t **versionp, dns_dbnode_t **nodep,
+                       dns_name_t *fname, dns_message_t *msg,
+                       isc_stdtime_t now)
 {
-       dns_rbtdb_t *rbtdb = rdataset->private1;
-       dns_rbtnode_t *rbtnode = rdataset->private2;
-       unsigned char *raw = rdataset->private3;        /* RDATASLAB */
-       unsigned int current_count = rdataset->privateuint4;
-       unsigned int count;
-       rdatasetheader_t *header;
-       nodelock_t *nodelock;
-       unsigned int total_count;
-       acachectl_t *acarray;
-       dns_acacheentry_t *entry;
-       isc_result_t result;
-
-       UNUSED(qtype); /* we do not use this value at least for now */
-       UNUSED(acache);
-
-       header = (struct rdatasetheader *)(raw - sizeof(*header));
-
-       total_count = raw[0] * 256 + raw[1];
-       INSIST(total_count > current_count);
-       count = total_count - current_count - 1;
-
-       acarray = NULL;
-
-       nodelock = &rbtdb->node_locks[rbtnode->locknum].lock;
-       NODE_LOCK(nodelock, isc_rwlocktype_read);
-
-       switch (type) {
-       case dns_rdatasetadditional_fromauth:
-               acarray = header->additional_auth;
-               break;
-       case dns_rdatasetadditional_fromcache:
-               acarray = NULL;
-               break;
-       case dns_rdatasetadditional_fromglue:
-               acarray = header->additional_glue;
-               break;
-       default:
-               INSIST(0);
-       }
-
-       if (acarray == NULL) {
-               if (type != dns_rdatasetadditional_fromcache)
-                       dns_acache_countquerymiss(acache);
-               NODE_UNLOCK(nodelock, isc_rwlocktype_read);
-               return (ISC_R_NOTFOUND);
-       }
-
-       if (acarray[count].entry == NULL) {
-               dns_acache_countquerymiss(acache);
-               NODE_UNLOCK(nodelock, isc_rwlocktype_read);
-               return (ISC_R_NOTFOUND);
-       }
-
-       entry = NULL;
-       dns_acache_attachentry(acarray[count].entry, &entry);
-
-       NODE_UNLOCK(nodelock, isc_rwlocktype_read);
-
-       result = dns_acache_getentry(entry, zonep, dbp, versionp,
-                                    nodep, fname, msg, now);
-
-       dns_acache_detachentry(&entry);
-
-       return (result);
+        dns_rbtdb_t *rbtdb = rdataset->private1;
+        dns_rbtnode_t *rbtnode = rdataset->private2;
+        unsigned char *raw = rdataset->private3;        /* RDATASLAB */
+        unsigned int current_count = rdataset->privateuint4;
+        unsigned int count;
+        rdatasetheader_t *header;
+        nodelock_t *nodelock;
+        unsigned int total_count;
+        acachectl_t *acarray;
+        dns_acacheentry_t *entry;
+        isc_result_t result;
+
+        UNUSED(qtype); /* we do not use this value at least for now */
+        UNUSED(acache);
+
+        header = (struct rdatasetheader *)(raw - sizeof(*header));
+
+        total_count = raw[0] * 256 + raw[1];
+        INSIST(total_count > current_count);
+        count = total_count - current_count - 1;
+
+        acarray = NULL;
+
+        nodelock = &rbtdb->node_locks[rbtnode->locknum].lock;
+        NODE_LOCK(nodelock, isc_rwlocktype_read);
+
+        switch (type) {
+        case dns_rdatasetadditional_fromauth:
+                acarray = header->additional_auth;
+                break;
+        case dns_rdatasetadditional_fromcache:
+                acarray = NULL;
+                break;
+        case dns_rdatasetadditional_fromglue:
+                acarray = header->additional_glue;
+                break;
+        default:
+                INSIST(0);
+        }
+
+        if (acarray == NULL) {
+                if (type != dns_rdatasetadditional_fromcache)
+                        dns_acache_countquerymiss(acache);
+                NODE_UNLOCK(nodelock, isc_rwlocktype_read);
+                return (ISC_R_NOTFOUND);
+        }
+
+        if (acarray[count].entry == NULL) {
+                dns_acache_countquerymiss(acache);
+                NODE_UNLOCK(nodelock, isc_rwlocktype_read);
+                return (ISC_R_NOTFOUND);
+        }
+
+        entry = NULL;
+        dns_acache_attachentry(acarray[count].entry, &entry);
+
+        NODE_UNLOCK(nodelock, isc_rwlocktype_read);
+
+        result = dns_acache_getentry(entry, zonep, dbp, versionp,
+                                     nodep, fname, msg, now);
+
+        dns_acache_detachentry(&entry);
+
+        return (result);
 }
 
 static void
 acache_callback(dns_acacheentry_t *entry, void **arg) {
-       dns_rbtdb_t *rbtdb;
-       dns_rbtnode_t *rbtnode;
-       nodelock_t *nodelock;
-       acachectl_t *acarray = NULL;
-       acache_cbarg_t *cbarg;
-       unsigned int count;
-
-       REQUIRE(arg != NULL);
-       cbarg = *arg;
-
-       /*
-        * The caller must hold the entry lock.
-        */
-
-       rbtdb = (dns_rbtdb_t *)cbarg->db;
-       rbtnode = (dns_rbtnode_t *)cbarg->node;
-
-       nodelock = &rbtdb->node_locks[rbtnode->locknum].lock;
-       NODE_LOCK(nodelock, isc_rwlocktype_write);
-
-       switch (cbarg->type) {
-       case dns_rdatasetadditional_fromauth:
-               acarray = cbarg->header->additional_auth;
-               break;
-       case dns_rdatasetadditional_fromglue:
-               acarray = cbarg->header->additional_glue;
-               break;
-       default:
-               INSIST(0);
-       }
-
-       count = cbarg->count;
-       if (acarray[count].entry == entry)
-               acarray[count].entry = NULL;
-       INSIST(acarray[count].cbarg != NULL);
-       isc_mem_put(rbtdb->common.mctx, acarray[count].cbarg,
-                   sizeof(acache_cbarg_t));
-       acarray[count].cbarg = NULL;
-
-       dns_acache_detachentry(&entry);
-
-       NODE_UNLOCK(nodelock, isc_rwlocktype_write);
-
-       dns_db_detachnode((dns_db_t *)rbtdb, (dns_dbnode_t **)(void*)&rbtnode);
-       dns_db_detach((dns_db_t **)(void*)&rbtdb);
-
-       *arg = NULL;
+        dns_rbtdb_t *rbtdb;
+        dns_rbtnode_t *rbtnode;
+        nodelock_t *nodelock;
+        acachectl_t *acarray = NULL;
+        acache_cbarg_t *cbarg;
+        unsigned int count;
+
+        REQUIRE(arg != NULL);
+        cbarg = *arg;
+
+        /*
+         * The caller must hold the entry lock.
+         */
+
+        rbtdb = (dns_rbtdb_t *)cbarg->db;
+        rbtnode = (dns_rbtnode_t *)cbarg->node;
+
+        nodelock = &rbtdb->node_locks[rbtnode->locknum].lock;
+        NODE_LOCK(nodelock, isc_rwlocktype_write);
+
+        switch (cbarg->type) {
+        case dns_rdatasetadditional_fromauth:
+                acarray = cbarg->header->additional_auth;
+                break;
+        case dns_rdatasetadditional_fromglue:
+                acarray = cbarg->header->additional_glue;
+                break;
+        default:
+                INSIST(0);
+        }
+
+        count = cbarg->count;
+        if (acarray[count].entry == entry)
+                acarray[count].entry = NULL;
+        INSIST(acarray[count].cbarg != NULL);
+        isc_mem_put(rbtdb->common.mctx, acarray[count].cbarg,
+                    sizeof(acache_cbarg_t));
+        acarray[count].cbarg = NULL;
+
+        dns_acache_detachentry(&entry);
+
+        NODE_UNLOCK(nodelock, isc_rwlocktype_write);
+
+        dns_db_detachnode((dns_db_t *)rbtdb, (dns_dbnode_t **)(void*)&rbtnode);
+        dns_db_detach((dns_db_t **)(void*)&rbtdb);
+
+        *arg = NULL;
 }
 
 static void
 acache_cancelentry(isc_mem_t *mctx, dns_acacheentry_t *entry,
-                     acache_cbarg_t **cbargp)
+                      acache_cbarg_t **cbargp)
 {
-       acache_cbarg_t *cbarg;
+        acache_cbarg_t *cbarg;
 
-       REQUIRE(mctx != NULL);
-       REQUIRE(entry != NULL);
-       REQUIRE(cbargp != NULL && *cbargp != NULL);
+        REQUIRE(mctx != NULL);
+        REQUIRE(entry != NULL);
+        REQUIRE(cbargp != NULL && *cbargp != NULL);
 
-       cbarg = *cbargp;
+        cbarg = *cbargp;
 
-       dns_acache_cancelentry(entry);
-       dns_db_detachnode(cbarg->db, &cbarg->node);
-       dns_db_detach(&cbarg->db);
+        dns_acache_cancelentry(entry);
+        dns_db_detachnode(cbarg->db, &cbarg->node);
+        dns_db_detach(&cbarg->db);
 
-       isc_mem_put(mctx, cbarg, sizeof(acache_cbarg_t));
+        isc_mem_put(mctx, cbarg, sizeof(acache_cbarg_t));
 
-       *cbargp = NULL;
+        *cbargp = NULL;
 }
 
 static isc_result_t
 rdataset_setadditional(dns_rdataset_t *rdataset, dns_rdatasetadditional_t type,
-                      dns_rdatatype_t qtype, dns_acache_t *acache,
-                      dns_zone_t *zone, dns_db_t *db,
-                      dns_dbversion_t *version, dns_dbnode_t *node,
-                      dns_name_t *fname)
+                       dns_rdatatype_t qtype, dns_acache_t *acache,
+                       dns_zone_t *zone, dns_db_t *db,
+                       dns_dbversion_t *version, dns_dbnode_t *node,
+                       dns_name_t *fname)
 {
-       dns_rbtdb_t *rbtdb = rdataset->private1;
-       dns_rbtnode_t *rbtnode = rdataset->private2;
-       unsigned char *raw = rdataset->private3;        /* RDATASLAB */
-       unsigned int current_count = rdataset->privateuint4;
-       rdatasetheader_t *header;
-       unsigned int total_count, count;
-       nodelock_t *nodelock;
-       isc_result_t result;
-       acachectl_t *acarray;
-       dns_acacheentry_t *newentry, *oldentry = NULL;
-       acache_cbarg_t *newcbarg, *oldcbarg = NULL;
-
-       UNUSED(qtype);
-
-       if (type == dns_rdatasetadditional_fromcache)
-               return (ISC_R_SUCCESS);
-
-       header = (struct rdatasetheader *)(raw - sizeof(*header));
-
-       total_count = raw[0] * 256 + raw[1];
-       INSIST(total_count > current_count);
-       count = total_count - current_count - 1; /* should be private data */
-
-       newcbarg = isc_mem_get(rbtdb->common.mctx, sizeof(*newcbarg));
-       if (newcbarg == NULL)
-               return (ISC_R_NOMEMORY);
-       newcbarg->type = type;
-       newcbarg->count = count;
-       newcbarg->header = header;
-       newcbarg->db = NULL;
-       dns_db_attach((dns_db_t *)rbtdb, &newcbarg->db);
-       newcbarg->node = NULL;
-       dns_db_attachnode((dns_db_t *)rbtdb, (dns_dbnode_t *)rbtnode,
-                         &newcbarg->node);
-       newentry = NULL;
-       result = dns_acache_createentry(acache, (dns_db_t *)rbtdb,
-                                       acache_callback, newcbarg, &newentry);
-       if (result != ISC_R_SUCCESS)
-               goto fail;
-       /* Set cache data in the new entry. */
-       result = dns_acache_setentry(acache, newentry, zone, db,
-                                    version, node, fname);
-       if (result != ISC_R_SUCCESS)
-               goto fail;
-
-       nodelock = &rbtdb->node_locks[rbtnode->locknum].lock;
-       NODE_LOCK(nodelock, isc_rwlocktype_write);
-
-       acarray = NULL;
-       switch (type) {
-       case dns_rdatasetadditional_fromauth:
-               acarray = header->additional_auth;
-               break;
-       case dns_rdatasetadditional_fromglue:
-               acarray = header->additional_glue;
-               break;
-       default:
-               INSIST(0);
-       }
-
-       if (acarray == NULL) {
-               unsigned int i;
-
-               acarray = isc_mem_get(rbtdb->common.mctx, total_count *
-                                     sizeof(acachectl_t));
-
-               if (acarray == NULL) {
-                       NODE_UNLOCK(nodelock, isc_rwlocktype_write);
-                       goto fail;
-               }
-
-               for (i = 0; i < total_count; i++) {
-                       acarray[i].entry = NULL;
-                       acarray[i].cbarg = NULL;
-               }
-       }
-       switch (type) {
-       case dns_rdatasetadditional_fromauth:
-               header->additional_auth = acarray;
-               break;
-       case dns_rdatasetadditional_fromglue:
-               header->additional_glue = acarray;
-               break;
-       default:
-               INSIST(0);
-       }
-
-       if (acarray[count].entry != NULL) {
-               /*
-                * Swap the entry.  Delay cleaning-up the old entry since
-                * it would require a node lock.
-                */
-               oldentry = acarray[count].entry;
-               INSIST(acarray[count].cbarg != NULL);
-               oldcbarg = acarray[count].cbarg;
-       }
-       acarray[count].entry = newentry;
-       acarray[count].cbarg = newcbarg;
-
-       NODE_UNLOCK(nodelock, isc_rwlocktype_write);
-
-       if (oldentry != NULL) {
-               if (oldcbarg != NULL)
-                       acache_cancelentry(rbtdb->common.mctx, oldentry,
-                                          &oldcbarg); 
-               dns_acache_detachentry(&oldentry);
-       }
-
-       return (ISC_R_SUCCESS);
+        dns_rbtdb_t *rbtdb = rdataset->private1;
+        dns_rbtnode_t *rbtnode = rdataset->private2;
+        unsigned char *raw = rdataset->private3;        /* RDATASLAB */
+        unsigned int current_count = rdataset->privateuint4;
+        rdatasetheader_t *header;
+        unsigned int total_count, count;
+        nodelock_t *nodelock;
+        isc_result_t result;
+        acachectl_t *acarray;
+        dns_acacheentry_t *newentry, *oldentry = NULL;
+        acache_cbarg_t *newcbarg, *oldcbarg = NULL;
+
+        UNUSED(qtype);
+
+        if (type == dns_rdatasetadditional_fromcache)
+                return (ISC_R_SUCCESS);
+
+        header = (struct rdatasetheader *)(raw - sizeof(*header));
+
+        total_count = raw[0] * 256 + raw[1];
+        INSIST(total_count > current_count);
+        count = total_count - current_count - 1; /* should be private data */
+
+        newcbarg = isc_mem_get(rbtdb->common.mctx, sizeof(*newcbarg));
+        if (newcbarg == NULL)
+                return (ISC_R_NOMEMORY);
+        newcbarg->type = type;
+        newcbarg->count = count;
+        newcbarg->header = header;
+        newcbarg->db = NULL;
+        dns_db_attach((dns_db_t *)rbtdb, &newcbarg->db);
+        newcbarg->node = NULL;
+        dns_db_attachnode((dns_db_t *)rbtdb, (dns_dbnode_t *)rbtnode,
+                          &newcbarg->node);
+        newentry = NULL;
+        result = dns_acache_createentry(acache, (dns_db_t *)rbtdb,
+                                        acache_callback, newcbarg, &newentry);
+        if (result != ISC_R_SUCCESS)
+                goto fail;
+        /* Set cache data in the new entry. */
+        result = dns_acache_setentry(acache, newentry, zone, db,
+                                     version, node, fname);
+        if (result != ISC_R_SUCCESS)
+                goto fail;
+
+        nodelock = &rbtdb->node_locks[rbtnode->locknum].lock;
+        NODE_LOCK(nodelock, isc_rwlocktype_write);
+
+        acarray = NULL;
+        switch (type) {
+        case dns_rdatasetadditional_fromauth:
+                acarray = header->additional_auth;
+                break;
+        case dns_rdatasetadditional_fromglue:
+                acarray = header->additional_glue;
+                break;
+        default:
+                INSIST(0);
+        }
+
+        if (acarray == NULL) {
+                unsigned int i;
+
+                acarray = isc_mem_get(rbtdb->common.mctx, total_count *
+                                      sizeof(acachectl_t));
+
+                if (acarray == NULL) {
+                        NODE_UNLOCK(nodelock, isc_rwlocktype_write);
+                        goto fail;
+                }
+
+                for (i = 0; i < total_count; i++) {
+                        acarray[i].entry = NULL;
+                        acarray[i].cbarg = NULL;
+                }
+        }
+        switch (type) {
+        case dns_rdatasetadditional_fromauth:
+                header->additional_auth = acarray;
+                break;
+        case dns_rdatasetadditional_fromglue:
+                header->additional_glue = acarray;
+                break;
+        default:
+                INSIST(0);
+        }
+
+        if (acarray[count].entry != NULL) {
+                /*
+                 * Swap the entry.  Delay cleaning-up the old entry since
+                 * it would require a node lock.
+                 */
+                oldentry = acarray[count].entry;
+                INSIST(acarray[count].cbarg != NULL);
+                oldcbarg = acarray[count].cbarg;
+        }
+        acarray[count].entry = newentry;
+        acarray[count].cbarg = newcbarg;
+
+        NODE_UNLOCK(nodelock, isc_rwlocktype_write);
+
+        if (oldentry != NULL) {
+                if (oldcbarg != NULL)
+                        acache_cancelentry(rbtdb->common.mctx, oldentry,
+                                           &oldcbarg);
+                dns_acache_detachentry(&oldentry);
+        }
+
+        return (ISC_R_SUCCESS);
 
   fail:
-       if (newcbarg != NULL) {
-               if (newentry != NULL) {
-                       acache_cancelentry(rbtdb->common.mctx, newentry,
-                                          &newcbarg);
-                       dns_acache_detachentry(&newentry);
-               } else {
-                       dns_db_detachnode((dns_db_t *)rbtdb, &newcbarg->node);
-                       dns_db_detach(&newcbarg->db);
-                       isc_mem_put(rbtdb->common.mctx, newcbarg,
-                           sizeof(*newcbarg));
-               }
-       }
-
-       return (result);
+        if (newcbarg != NULL) {
+                if (newentry != NULL) {
+                        acache_cancelentry(rbtdb->common.mctx, newentry,
+                                           &newcbarg);
+                        dns_acache_detachentry(&newentry);
+                } else {
+                        dns_db_detachnode((dns_db_t *)rbtdb, &newcbarg->node);
+                        dns_db_detach(&newcbarg->db);
+                        isc_mem_put(rbtdb->common.mctx, newcbarg,
+                            sizeof(*newcbarg));
+                }
+        }
+
+        return (result);
 }
 
 static isc_result_t
 rdataset_putadditional(dns_acache_t *acache, dns_rdataset_t *rdataset,
-                      dns_rdatasetadditional_t type, dns_rdatatype_t qtype)
-{ 
-       dns_rbtdb_t *rbtdb = rdataset->private1;
-       dns_rbtnode_t *rbtnode = rdataset->private2;
-       unsigned char *raw = rdataset->private3;        /* RDATASLAB */
-       unsigned int current_count = rdataset->privateuint4;
-       rdatasetheader_t *header;
-       nodelock_t *nodelock;
-       unsigned int total_count, count;
-       acachectl_t *acarray;
-       dns_acacheentry_t *entry;
-       acache_cbarg_t *cbarg;
-
-       UNUSED(qtype);          /* we do not use this value at least for now */
-       UNUSED(acache);
-
-       if (type == dns_rdatasetadditional_fromcache)
-               return (ISC_R_SUCCESS);
-
-       header = (struct rdatasetheader *)(raw - sizeof(*header));
-
-       total_count = raw[0] * 256 + raw[1];
-       INSIST(total_count > current_count);
-       count = total_count - current_count - 1;
-
-       acarray = NULL;
-       entry = NULL;
-
-       nodelock = &rbtdb->node_locks[rbtnode->locknum].lock;
-       NODE_LOCK(nodelock, isc_rwlocktype_write);
-
-       switch (type) {
-       case dns_rdatasetadditional_fromauth:
-               acarray = header->additional_auth;
-               break;
-       case dns_rdatasetadditional_fromglue:
-               acarray = header->additional_glue;
-               break;
-       default:
-               INSIST(0);
-       }
-
-       if (acarray == NULL) {
-               NODE_UNLOCK(nodelock, isc_rwlocktype_write);
-               return (ISC_R_NOTFOUND);
-       }
-
-       entry = acarray[count].entry;
-       if (entry == NULL) {
-               NODE_UNLOCK(nodelock, isc_rwlocktype_write);
-               return (ISC_R_NOTFOUND);
-       }
-
-       acarray[count].entry = NULL;
-       cbarg = acarray[count].cbarg;
-       acarray[count].cbarg = NULL;
-
-       NODE_UNLOCK(nodelock, isc_rwlocktype_write);
-
-       if (entry != NULL) {
-               if (cbarg != NULL)
-                       acache_cancelentry(rbtdb->common.mctx, entry, &cbarg);
-               dns_acache_detachentry(&entry);
-       }
-
-       return (ISC_R_SUCCESS);
+                       dns_rdatasetadditional_t type, dns_rdatatype_t qtype)
+{
+        dns_rbtdb_t *rbtdb = rdataset->private1;
+        dns_rbtnode_t *rbtnode = rdataset->private2;
+        unsigned char *raw = rdataset->private3;        /* RDATASLAB */
+        unsigned int current_count = rdataset->privateuint4;
+        rdatasetheader_t *header;
+        nodelock_t *nodelock;
+        unsigned int total_count, count;
+        acachectl_t *acarray;
+        dns_acacheentry_t *entry;
+        acache_cbarg_t *cbarg;
+
+        UNUSED(qtype);          /* we do not use this value at least for now */
+        UNUSED(acache);
+
+        if (type == dns_rdatasetadditional_fromcache)
+                return (ISC_R_SUCCESS);
+
+        header = (struct rdatasetheader *)(raw - sizeof(*header));
+
+        total_count = raw[0] * 256 + raw[1];
+        INSIST(total_count > current_count);
+        count = total_count - current_count - 1;
+
+        acarray = NULL;
+        entry = NULL;
+
+        nodelock = &rbtdb->node_locks[rbtnode->locknum].lock;
+        NODE_LOCK(nodelock, isc_rwlocktype_write);
+
+        switch (type) {
+        case dns_rdatasetadditional_fromauth:
+                acarray = header->additional_auth;
+                break;
+        case dns_rdatasetadditional_fromglue:
+                acarray = header->additional_glue;
+                break;
+        default:
+                INSIST(0);
+        }
+
+        if (acarray == NULL) {
+                NODE_UNLOCK(nodelock, isc_rwlocktype_write);
+                return (ISC_R_NOTFOUND);
+        }
+
+        entry = acarray[count].entry;
+        if (entry == NULL) {
+                NODE_UNLOCK(nodelock, isc_rwlocktype_write);
+                return (ISC_R_NOTFOUND);
+        }
+
+        acarray[count].entry = NULL;
+        cbarg = acarray[count].cbarg;
+        acarray[count].cbarg = NULL;
+
+        NODE_UNLOCK(nodelock, isc_rwlocktype_write);
+
+        if (entry != NULL) {
+                if (cbarg != NULL)
+                        acache_cancelentry(rbtdb->common.mctx, entry, &cbarg);
+                dns_acache_detachentry(&entry);
+        }
+
+        return (ISC_R_SUCCESS);
+}
+
+/*%
+ * Routines for LRU-based cache management.
+ */
+
+/*%
+ * See if a given cache entry that is being reused needs to be updated
+ * in the LRU-list.  For the non-threaded case this is always true unless the
+ * entry has already been marked as stale; for the threaded case, updating
+ * the entry every time it is referenced might be expensive because it requires
+ * a node write lock.  Thus this function returns true if the entry has not been
+ * updated for some period of time.  We differentiate the NS or glue address
+ * case and the others since experiments have shown that the former tends to be
+ * accessed relatively infrequently and the cost of cache miss is higher
+ * (e.g., a missing NS records may cause external queries at a higher level
+ * zone, involving more transactions).
+ *
+ * Caller must hold the node (read or write) lock.
+ */
+static inline isc_boolean_t
+need_headerupdate(rdatasetheader_t *header, isc_stdtime_t now) {
+        if ((header->attributes &
+             (RDATASET_ATTR_NONEXISTENT|RDATASET_ATTR_STALE)) != 0)
+                return (ISC_FALSE);
+
+#ifdef ISC_PLATFORM_USETHREADS
+        if (header->type == dns_rdatatype_ns ||
+            (header->trust == dns_trust_glue &&
+             (header->type == dns_rdatatype_a ||
+              header->type == dns_rdatatype_aaaa))) {
+                /*
+                 * Glue records are updated if at least 60 seconds have passed
+                 * since the previous update time.
+                 */
+                return (header->last_used + 60 <= now);
+        }
+
+        /* Other records are updated if 5 minutes have passed. */
+        return (header->last_used + 300 <= now);
+#else
+        UNUSED(now);
+
+        return (ISC_TRUE);
+#endif
+}
+
+/*%
+ * Update the timestamp of a given cache entry and move it to the head
+ * of the corresponding LRU list.
+ *
+ * Caller must hold the node (write) lock.
+ *
+ * Note that the we do NOT touch the heap here, as the TTL has not changed.
+ */
+static void
+update_header(dns_rbtdb_t *rbtdb, rdatasetheader_t *header,
+              isc_stdtime_t now)
+{
+        /* To be checked: can we really assume this? XXXMLG */
+        INSIST(ISC_LINK_LINKED(header, lru_link));
+
+        ISC_LIST_UNLINK(rbtdb->rdatasets[header->node->locknum],
+                        header, lru_link);
+        header->last_used = now;
+        ISC_LIST_PREPEND(rbtdb->rdatasets[header->node->locknum],
+                         header, lru_link);
+}
+
+/*%
+ * Examine the tail entry of the LRU list to see if it expires or is stale
+ * (unused for some period).  If so, it's marked as stale and possibly freed.
+ * If the DB is in the overmem condition, the tail and the next to tail entries
+ * will be unconditionally marked.  We don't care about a race on 'overmem'
+ * at the risk of causing some collateral damage or a small delay in starting
+ * cleanup, so we don't bother to lock rbtdb.
+ *
+ * Caller must hold the node (write) lock.
+ *
+ * We can get away with locking only one node here, since it will lock all
+ * other nodes in that lock pool bucket.
+ */
+static void
+check_stale_cache(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode,
+                  isc_stdtime_t now, isc_boolean_t tree_locked)
+{
+        rdatasetheader_t *victim;
+        isc_boolean_t overmem = rbtdb->overmem;
+        int scans = 0;          /* for debug */
+        int victims = 0;
+
+        /*
+         * Check for TTL-based expiry.
+         */
+        victim = isc_heap_element(rbtdb->heaps[rbtnode->locknum], 1);
+        if (victim != NULL && victim->rdh_ttl <= now - RBTDB_VIRTUAL) {
+                INSIST(victim->node->locknum == rbtnode->locknum);
+
+#ifdef LRU_DEBUG
+                /* for debug */
+                rbtdb->cachestat.stale_expire++;
+#endif
+                victims++;
+
+                set_ttl(rbtdb, victim, 0);
+                victim->attributes |= RDATASET_ATTR_STALE;
+                victim->node->dirty = 1;
+
+                if (dns_rbtnode_refcurrent(victim->node) == 0) {
+                        INSIST(rbtnode != victim->node);
+                        /*
+                         * If no one else is using the node, we can
+                         * clean it up now.  We first need to gain
+                         * a new reference to the node to meet a
+                         * requirement of decrement_reference().
+                         */
+                        new_reference(rbtdb, victim->node);
+                        decrement_reference(rbtdb, victim->node, 0,
+                                            isc_rwlocktype_write,
+                                            tree_locked ? isc_rwlocktype_write :
+                                            isc_rwlocktype_none);
+                }
+        }
+
+        /*
+         * If we are over memory, delete the end entry from the LRU.
+         */
+        victim = ISC_LIST_TAIL(rbtdb->rdatasets[rbtnode->locknum]);
+        if (victim != NULL && overmem) {
+                INSIST(victim->node->locknum == rbtnode->locknum);
+
+#ifdef LRU_DEBUG
+                /* for debug */
+                rbtdb->cachestat.stale_lru++;
+#endif
+                victims++;
+                scans++;
+
+                set_ttl(rbtdb, victim, 0);
+                victim->attributes |= RDATASET_ATTR_STALE;
+                victim->node->dirty = 1;
+
+                if (dns_rbtnode_refcurrent(victim->node) == 0) {
+                        INSIST(rbtnode != victim->node);
+                        /*
+                         * If no one else is using the node, we can
+                         * clean it up now.  We first need to gain
+                         * a new reference to the node to meet a
+                         * requirement of decrement_reference().
+                         */
+                        new_reference(rbtdb, victim->node);
+                        decrement_reference(rbtdb, victim->node, 0,
+                                            isc_rwlocktype_write,
+                                            tree_locked ? isc_rwlocktype_write :
+                                            isc_rwlocktype_none);
+                }
+        }
+
+#ifdef LRU_DEBUG
+        /* update statistics for debug (no lock for brevity) */
+        rbtdb->cachestat.stale_scan += scans;
+        rbtdb->cachestat.stale_purge += victims;
+#endif
 }
index 1cebd5bdb54311dc44d8ec447e429a2dbb0f01ee..8c6a0ea4cfed070c7af422d414800307eea0a1cf 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: resolver.c,v 1.352 2007/09/14 05:43:05 marka Exp $ */
+/* $Id: resolver.c,v 1.353 2007/10/19 17:15:53 explorer Exp $ */
 
 /*! \file */
 
 
 #define DNS_RESOLVER_TRACE
 #ifdef DNS_RESOLVER_TRACE
-#define RTRACE(m)      isc_log_write(dns_lctx, \
-                                     DNS_LOGCATEGORY_RESOLVER, \
-                                     DNS_LOGMODULE_RESOLVER, \
-                                     ISC_LOG_DEBUG(3), \
-                                     "res %p: %s", res, (m))
-#define RRTRACE(r, m)  isc_log_write(dns_lctx, \
-                                     DNS_LOGCATEGORY_RESOLVER, \
-                                     DNS_LOGMODULE_RESOLVER, \
-                                     ISC_LOG_DEBUG(3), \
-                                     "res %p: %s", (r), (m))
-#define FCTXTRACE(m)   isc_log_write(dns_lctx, \
-                                     DNS_LOGCATEGORY_RESOLVER, \
-                                     DNS_LOGMODULE_RESOLVER, \
-                                     ISC_LOG_DEBUG(3), \
-                                     "fctx %p(%s'): %s", fctx, fctx->info, (m))
+#define RTRACE(m)       isc_log_write(dns_lctx, \
+                                      DNS_LOGCATEGORY_RESOLVER, \
+                                      DNS_LOGMODULE_RESOLVER, \
+                                      ISC_LOG_DEBUG(3), \
+                                      "res %p: %s", res, (m))
+#define RRTRACE(r, m)   isc_log_write(dns_lctx, \
+                                      DNS_LOGCATEGORY_RESOLVER, \
+                                      DNS_LOGMODULE_RESOLVER, \
+                                      ISC_LOG_DEBUG(3), \
+                                      "res %p: %s", (r), (m))
+#define FCTXTRACE(m)    isc_log_write(dns_lctx, \
+                                      DNS_LOGCATEGORY_RESOLVER, \
+                                      DNS_LOGMODULE_RESOLVER, \
+                                      ISC_LOG_DEBUG(3), \
+                                      "fctx %p(%s'): %s", fctx, fctx->info, (m))
 #define FCTXTRACE2(m1, m2) \
-                       isc_log_write(dns_lctx, \
-                                     DNS_LOGCATEGORY_RESOLVER, \
-                                     DNS_LOGMODULE_RESOLVER, \
-                                     ISC_LOG_DEBUG(3), \
-                                     "fctx %p(%s): %s %s", \
-                                     fctx, fctx->info, (m1), (m2))
-#define FTRACE(m)      isc_log_write(dns_lctx, \
-                                     DNS_LOGCATEGORY_RESOLVER, \
-                                     DNS_LOGMODULE_RESOLVER, \
-                                     ISC_LOG_DEBUG(3), \
-                                     "fetch %p (fctx %p(%s)): %s", \
-                                     fetch, fetch->private, \
-                                     fetch->private->info, (m))
-#define QTRACE(m)      isc_log_write(dns_lctx, \
-                                     DNS_LOGCATEGORY_RESOLVER, \
-                                     DNS_LOGMODULE_RESOLVER, \
-                                     ISC_LOG_DEBUG(3), \
-                                     "resquery %p (fctx %p(%s)): %s", \
-                                     query, query->fctx, \
-                                     query->fctx->info, (m))
+                        isc_log_write(dns_lctx, \
+                                      DNS_LOGCATEGORY_RESOLVER, \
+                                      DNS_LOGMODULE_RESOLVER, \
+                                      ISC_LOG_DEBUG(3), \
+                                      "fctx %p(%s): %s %s", \
+                                      fctx, fctx->info, (m1), (m2))
+#define FTRACE(m)       isc_log_write(dns_lctx, \
+                                      DNS_LOGCATEGORY_RESOLVER, \
+                                      DNS_LOGMODULE_RESOLVER, \
+                                      ISC_LOG_DEBUG(3), \
+                                      "fetch %p (fctx %p(%s)): %s", \
+                                      fetch, fetch->private, \
+                                      fetch->private->info, (m))
+#define QTRACE(m)       isc_log_write(dns_lctx, \
+                                      DNS_LOGCATEGORY_RESOLVER, \
+                                      DNS_LOGMODULE_RESOLVER, \
+                                      ISC_LOG_DEBUG(3), \
+                                      "resquery %p (fctx %p(%s)): %s", \
+                                      query, query->fctx, \
+                                      query->fctx->info, (m))
 #else
 #define RTRACE(m)
 #define RRTRACE(r, m)
 /*%
  * Maximum EDNS0 input packet size.
  */
-#define RECV_BUFFER_SIZE               4096            /* XXXRTH  Constant. */
+#define RECV_BUFFER_SIZE                4096            /* XXXRTH  Constant. */
 
 /*%
  * This defines the maximum number of timeouts we will permit before we
  * disable EDNS0 on the query.
  */
-#define MAX_EDNS0_TIMEOUTS     3
+#define MAX_EDNS0_TIMEOUTS      3
 
 typedef struct fetchctx fetchctx_t;
 
 typedef struct query {
-       /* Locked by task event serialization. */
-       unsigned int                    magic;
-       fetchctx_t *                    fctx;
-       isc_mem_t *                     mctx;
-       dns_dispatchmgr_t *             dispatchmgr;
-       dns_dispatch_t *                dispatch;
-       dns_adbaddrinfo_t *             addrinfo;
-       isc_socket_t *                  tcpsocket;
-       isc_time_t                      start;
-       dns_messageid_t                 id;
-       dns_dispentry_t *               dispentry;
-       ISC_LINK(struct query)          link;
-       isc_buffer_t                    buffer;
-       isc_buffer_t                    *tsig;
-       dns_tsigkey_t                   *tsigkey;
-       unsigned int                    options;
-       unsigned int                    attributes;
-       unsigned int                    sends;
-       unsigned int                    connects;
-       unsigned char                   data[512];
+        /* Locked by task event serialization. */
+        unsigned int                    magic;
+        fetchctx_t *                    fctx;
+        isc_mem_t *                     mctx;
+        dns_dispatchmgr_t *             dispatchmgr;
+        dns_dispatch_t *                dispatch;
+        dns_adbaddrinfo_t *             addrinfo;
+        isc_socket_t *                  tcpsocket;
+        isc_time_t                      start;
+        dns_messageid_t                 id;
+        dns_dispentry_t *               dispentry;
+        ISC_LINK(struct query)          link;
+        isc_buffer_t                    buffer;
+        isc_buffer_t                    *tsig;
+        dns_tsigkey_t                   *tsigkey;
+        unsigned int                    options;
+        unsigned int                    attributes;
+        unsigned int                    sends;
+        unsigned int                    connects;
+        unsigned char                   data[512];
 } resquery_t;
 
-#define QUERY_MAGIC                    ISC_MAGIC('Q', '!', '!', '!')
-#define VALID_QUERY(query)             ISC_MAGIC_VALID(query, QUERY_MAGIC)
+#define QUERY_MAGIC                     ISC_MAGIC('Q', '!', '!', '!')
+#define VALID_QUERY(query)              ISC_MAGIC_VALID(query, QUERY_MAGIC)
 
-#define RESQUERY_ATTR_CANCELED         0x02
+#define RESQUERY_ATTR_CANCELED          0x02
 
-#define RESQUERY_CONNECTING(q)         ((q)->connects > 0)
-#define RESQUERY_CANCELED(q)           (((q)->attributes & \
-                                         RESQUERY_ATTR_CANCELED) != 0)
-#define RESQUERY_SENDING(q)            ((q)->sends > 0)
+#define RESQUERY_CONNECTING(q)          ((q)->connects > 0)
+#define RESQUERY_CANCELED(q)            (((q)->attributes & \
+                                          RESQUERY_ATTR_CANCELED) != 0)
+#define RESQUERY_SENDING(q)             ((q)->sends > 0)
 
 typedef enum {
-       fetchstate_init = 0,            /*%< Start event has not run yet. */
-       fetchstate_active,
-       fetchstate_done                 /*%< FETCHDONE events posted. */
+        fetchstate_init = 0,            /*%< Start event has not run yet. */
+        fetchstate_active,
+        fetchstate_done                 /*%< FETCHDONE events posted. */
 } fetchstate;
 
 struct fetchctx {
-       /*% Not locked. */
-       unsigned int                    magic;
-       dns_resolver_t *                res;
-       dns_name_t                      name;
-       dns_rdatatype_t                 type;
-       unsigned int                    options;
-       unsigned int                    bucketnum;
-       char *                          info;
-       /*% Locked by appropriate bucket lock. */
-       fetchstate                      state;
-       isc_boolean_t                   want_shutdown;
-       isc_boolean_t                   cloned;
-       isc_boolean_t                   spilled;
-       unsigned int                    references;
-       isc_event_t                     control_event;
-       ISC_LINK(struct fetchctx)       link;
-       ISC_LIST(dns_fetchevent_t)      events;
-       /*% Locked by task event serialization. */
-       dns_name_t                      domain;
-       dns_rdataset_t                  nameservers;
-       unsigned int                    attributes;
-       isc_timer_t *                   timer;
-       isc_time_t                      expires;
-       isc_interval_t                  interval;
-       dns_message_t *                 qmessage;
-       dns_message_t *                 rmessage;
-       ISC_LIST(resquery_t)            queries;
-       dns_adbfindlist_t               finds;
-       dns_adbfind_t *                 find;
-       dns_adbfindlist_t               altfinds;
-       dns_adbfind_t *                 altfind;
-       dns_adbaddrinfolist_t           forwaddrs;
-       dns_adbaddrinfolist_t           altaddrs;
-       isc_sockaddrlist_t              forwarders;
-       dns_fwdpolicy_t                 fwdpolicy;
-       isc_sockaddrlist_t              bad;
-       isc_sockaddrlist_t              edns;
-       isc_sockaddrlist_t              edns512;
-       dns_validator_t                 *validator;
-       ISC_LIST(dns_validator_t)       validators;
-       dns_db_t *                      cache;
-       dns_adb_t *                     adb;
-
-       /*%
-        * The number of events we're waiting for.
-        */
-       unsigned int                    pending;
-
-       /*%
-        * The number of times we've "restarted" the current
-        * nameserver set.  This acts as a failsafe to prevent
-        * us from pounding constantly on a particular set of
-        * servers that, for whatever reason, are not giving
-        * us useful responses, but are responding in such a
-        * way that they are not marked "bad".
-        */
-       unsigned int                    restarts;
-
-       /*%
-        * The number of timeouts that have occurred since we 
-        * last successfully received a response packet.  This
-        * is used for EDNS0 black hole detection.
-        */
-       unsigned int                    timeouts;
-       /*%
-        * Look aside state for DS lookups.
-        */
-       dns_name_t                      nsname; 
-       dns_fetch_t *                   nsfetch;
-       dns_rdataset_t                  nsrrset;
-
-       /*%
-        * Number of queries that reference this context.
-        */
-       unsigned int                    nqueries;
+        /*% Not locked. */
+        unsigned int                    magic;
+        dns_resolver_t *                res;
+        dns_name_t                      name;
+        dns_rdatatype_t                 type;
+        unsigned int                    options;
+        unsigned int                    bucketnum;
+        char *                          info;
+        /*% Locked by appropriate bucket lock. */
+        fetchstate                      state;
+        isc_boolean_t                   want_shutdown;
+        isc_boolean_t                   cloned;
+        isc_boolean_t                   spilled;
+        unsigned int                    references;
+        isc_event_t                     control_event;
+        ISC_LINK(struct fetchctx)       link;
+        ISC_LIST(dns_fetchevent_t)      events;
+        /*% Locked by task event serialization. */
+        dns_name_t                      domain;
+        dns_rdataset_t                  nameservers;
+        unsigned int                    attributes;
+        isc_timer_t *                   timer;
+        isc_time_t                      expires;
+        isc_interval_t                  interval;
+        dns_message_t *                 qmessage;
+        dns_message_t *                 rmessage;
+        ISC_LIST(resquery_t)            queries;
+        dns_adbfindlist_t               finds;
+        dns_adbfind_t *                 find;
+        dns_adbfindlist_t               altfinds;
+        dns_adbfind_t *                 altfind;
+        dns_adbaddrinfolist_t           forwaddrs;
+        dns_adbaddrinfolist_t           altaddrs;
+        isc_sockaddrlist_t              forwarders;
+        dns_fwdpolicy_t                 fwdpolicy;
+        isc_sockaddrlist_t              bad;
+        isc_sockaddrlist_t              edns;
+        isc_sockaddrlist_t              edns512;
+        dns_validator_t                 *validator;
+        ISC_LIST(dns_validator_t)       validators;
+        dns_db_t *                      cache;
+        dns_adb_t *                     adb;
+
+        /*%
+         * The number of events we're waiting for.
+         */
+        unsigned int                    pending;
+
+        /*%
+         * The number of times we've "restarted" the current
+         * nameserver set.  This acts as a failsafe to prevent
+         * us from pounding constantly on a particular set of
+         * servers that, for whatever reason, are not giving
+         * us useful responses, but are responding in such a
+         * way that they are not marked "bad".
+         */
+        unsigned int                    restarts;
+
+        /*%
+         * The number of timeouts that have occurred since we
+         * last successfully received a response packet.  This
+         * is used for EDNS0 black hole detection.
+         */
+        unsigned int                    timeouts;
+        /*%
+         * Look aside state for DS lookups.
+         */
+        dns_name_t                      nsname;
+        dns_fetch_t *                   nsfetch;
+        dns_rdataset_t                  nsrrset;
+
+        /*%
+         * Number of queries that reference this context.
+         */
+        unsigned int                    nqueries;
 };
 
-#define FCTX_MAGIC                     ISC_MAGIC('F', '!', '!', '!')
-#define VALID_FCTX(fctx)               ISC_MAGIC_VALID(fctx, FCTX_MAGIC)
-
-#define FCTX_ATTR_HAVEANSWER           0x0001
-#define FCTX_ATTR_GLUING               0x0002
-#define FCTX_ATTR_ADDRWAIT             0x0004
-#define FCTX_ATTR_SHUTTINGDOWN         0x0008
-#define FCTX_ATTR_WANTCACHE            0x0010
-#define FCTX_ATTR_WANTNCACHE           0x0020
-#define FCTX_ATTR_NEEDEDNS0            0x0040
-#define FCTX_ATTR_TRIEDFIND            0x0080
-#define FCTX_ATTR_TRIEDALT             0x0100
-
-#define HAVE_ANSWER(f)         (((f)->attributes & FCTX_ATTR_HAVEANSWER) != \
-                                0)
-#define GLUING(f)              (((f)->attributes & FCTX_ATTR_GLUING) != \
-                                0)
-#define ADDRWAIT(f)            (((f)->attributes & FCTX_ATTR_ADDRWAIT) != \
-                                0)
-#define SHUTTINGDOWN(f)                (((f)->attributes & FCTX_ATTR_SHUTTINGDOWN) \
-                                != 0)
-#define WANTCACHE(f)           (((f)->attributes & FCTX_ATTR_WANTCACHE) != 0)
-#define WANTNCACHE(f)          (((f)->attributes & FCTX_ATTR_WANTNCACHE) != 0)
-#define NEEDEDNS0(f)           (((f)->attributes & FCTX_ATTR_NEEDEDNS0) != 0)
-#define TRIEDFIND(f)           (((f)->attributes & FCTX_ATTR_TRIEDFIND) != 0)
-#define TRIEDALT(f)            (((f)->attributes & FCTX_ATTR_TRIEDALT) != 0)
+#define FCTX_MAGIC                      ISC_MAGIC('F', '!', '!', '!')
+#define VALID_FCTX(fctx)                ISC_MAGIC_VALID(fctx, FCTX_MAGIC)
+
+#define FCTX_ATTR_HAVEANSWER            0x0001
+#define FCTX_ATTR_GLUING                0x0002
+#define FCTX_ATTR_ADDRWAIT              0x0004
+#define FCTX_ATTR_SHUTTINGDOWN          0x0008
+#define FCTX_ATTR_WANTCACHE             0x0010
+#define FCTX_ATTR_WANTNCACHE            0x0020
+#define FCTX_ATTR_NEEDEDNS0             0x0040
+#define FCTX_ATTR_TRIEDFIND             0x0080
+#define FCTX_ATTR_TRIEDALT              0x0100
+
+#define HAVE_ANSWER(f)          (((f)->attributes & FCTX_ATTR_HAVEANSWER) != \
+                                 0)
+#define GLUING(f)               (((f)->attributes & FCTX_ATTR_GLUING) != \
+                                 0)
+#define ADDRWAIT(f)             (((f)->attributes & FCTX_ATTR_ADDRWAIT) != \
+                                 0)
+#define SHUTTINGDOWN(f)         (((f)->attributes & FCTX_ATTR_SHUTTINGDOWN) \
+                                 != 0)
+#define WANTCACHE(f)            (((f)->attributes & FCTX_ATTR_WANTCACHE) != 0)
+#define WANTNCACHE(f)           (((f)->attributes & FCTX_ATTR_WANTNCACHE) != 0)
+#define NEEDEDNS0(f)            (((f)->attributes & FCTX_ATTR_NEEDEDNS0) != 0)
+#define TRIEDFIND(f)            (((f)->attributes & FCTX_ATTR_TRIEDFIND) != 0)
+#define TRIEDALT(f)             (((f)->attributes & FCTX_ATTR_TRIEDALT) != 0)
 
 typedef struct {
-       dns_adbaddrinfo_t *             addrinfo;
-       fetchctx_t *                    fctx;
+        dns_adbaddrinfo_t *             addrinfo;
+        fetchctx_t *                    fctx;
 } dns_valarg_t;
 
 struct dns_fetch {
-       unsigned int                    magic;
-       fetchctx_t *                    private;
+        unsigned int                    magic;
+        fetchctx_t *                    private;
 };
 
-#define DNS_FETCH_MAGIC                        ISC_MAGIC('F', 't', 'c', 'h')
-#define DNS_FETCH_VALID(fetch)         ISC_MAGIC_VALID(fetch, DNS_FETCH_MAGIC)
+#define DNS_FETCH_MAGIC                 ISC_MAGIC('F', 't', 'c', 'h')
+#define DNS_FETCH_VALID(fetch)          ISC_MAGIC_VALID(fetch, DNS_FETCH_MAGIC)
 
 typedef struct fctxbucket {
-       isc_task_t *                    task;
-       isc_mutex_t                     lock;
-       ISC_LIST(fetchctx_t)            fctxs;
-       isc_boolean_t                   exiting;
-       isc_mem_t *                     mctx;
+        isc_task_t *                    task;
+        isc_mutex_t                     lock;
+        ISC_LIST(fetchctx_t)            fctxs;
+        isc_boolean_t                   exiting;
+        isc_mem_t *                     mctx;
 } fctxbucket_t;
 
 typedef struct alternate {
-       isc_boolean_t                   isaddress;
-       union   {
-               isc_sockaddr_t          addr;
-               struct {
-                       dns_name_t      name;
-                       in_port_t       port;
-               } _n;
-       } _u;
-       ISC_LINK(struct alternate)      link;
+        isc_boolean_t                   isaddress;
+        union   {
+                isc_sockaddr_t          addr;
+                struct {
+                        dns_name_t      name;
+                        in_port_t       port;
+                } _n;
+        } _u;
+        ISC_LINK(struct alternate)      link;
 } alternate_t;
 
 #ifdef ISC_RWLOCK_USEATOMIC
@@ -301,88 +301,102 @@ typedef struct alternate {
 #endif
 
 #if DNS_RESOLVER_USERWLOCK
-#define RES_INITLOCK(l)                isc_rwlock_init((l), 0, 0)
-#define RES_DESTROYLOCK(l)     isc_rwlock_destroy(l)
-#define RES_LOCK(l, t)         RWLOCK((l), (t))
-#define RES_UNLOCK(l, t)       RWUNLOCK((l), (t))
+#define RES_INITLOCK(l)         isc_rwlock_init((l), 0, 0)
+#define RES_DESTROYLOCK(l)      isc_rwlock_destroy(l)
+#define RES_LOCK(l, t)          RWLOCK((l), (t))
+#define RES_UNLOCK(l, t)        RWUNLOCK((l), (t))
 #else
-#define RES_INITLOCK(l)                isc_mutex_init(l)
-#define RES_DESTROYLOCK(l)     DESTROYLOCK(l)
-#define RES_LOCK(l, t)         LOCK(l)
-#define RES_UNLOCK(l, t)       UNLOCK(l)
+#define RES_INITLOCK(l)         isc_mutex_init(l)
+#define RES_DESTROYLOCK(l)      DESTROYLOCK(l)
+#define RES_LOCK(l, t)          LOCK(l)
+#define RES_UNLOCK(l, t)        UNLOCK(l)
 #endif
 
 struct dns_resolver {
-       /* Unlocked. */
-       unsigned int                    magic;
-       isc_mem_t *                     mctx;
-       isc_mutex_t                     lock;
-       isc_mutex_t                     nlock;  
-       isc_mutex_t                     primelock;
+        /* Unlocked. */
+        unsigned int                    magic;
+        isc_mem_t *                     mctx;
+        isc_mutex_t                     lock;
+        isc_mutex_t                     nlock;
+        isc_mutex_t                     primelock;
 #if DNS_RESOLVER_USERWLOCK
-       isc_rwlock_t                    poollock;
+        isc_rwlock_t                    poollock;
 #else
-       isc_mutex_t                     poollock;
+        isc_mutex_t                     poollock;
 #endif
-       dns_rdataclass_t                rdclass;
-       isc_socketmgr_t *               socketmgr;
-       isc_timermgr_t *                timermgr;
-       isc_taskmgr_t *                 taskmgr;
-       dns_view_t *                    view;
-       isc_boolean_t                   frozen;
-       unsigned int                    options;
-       dns_dispatchmgr_t *             dispatchmgr;
-       dns_dispatch_t *                dispatchv4;
-       dns_dispatch_t *                dispatchv6;
-       unsigned int                    ndisps;
-       unsigned int                    nbuckets;
-       fctxbucket_t *                  buckets;
-       isc_uint32_t                    lame_ttl;
-       ISC_LIST(alternate_t)           alternates;
-       isc_uint16_t                    udpsize;
+        dns_rdataclass_t                rdclass;
+        isc_socketmgr_t *               socketmgr;
+        isc_timermgr_t *                timermgr;
+        isc_taskmgr_t *                 taskmgr;
+        dns_view_t *                    view;
+        isc_boolean_t                   frozen;
+        unsigned int                    options;
+        dns_dispatchmgr_t *             dispatchmgr;
+        dns_dispatch_t *                dispatchv4;
+        dns_dispatch_t *                dispatchv6;
+        unsigned int                    ndisps;
+        unsigned int                    nbuckets;
+        fctxbucket_t *                  buckets;
+        isc_uint32_t                    lame_ttl;
+        ISC_LIST(alternate_t)           alternates;
+        isc_uint16_t                    udpsize;
 #if USE_ALGLOCK
-       isc_rwlock_t                    alglock;
+        isc_rwlock_t                    alglock;
 #endif
-       dns_rbt_t *                     algorithms;
+        dns_rbt_t *                     algorithms;
 #if USE_MBSLOCK
-       isc_rwlock_t                    mbslock;
+        isc_rwlock_t                    mbslock;
+#endif
+        dns_rbt_t *                     mustbesecure;
+        unsigned int                    spillatmax;
+        unsigned int                    spillatmin;
+        isc_timer_t *                   spillattimer;
+        isc_boolean_t                   zero_no_soa_ttl;
+        isc_timer_t *                   disppooltimer;
+#ifdef LRU_DEBUG
+#define DUMP_INTERVAL 30        /* seconds */
+        isc_timer_t *                   dumptimer;
+        isc_time_t                      dump_time;
+#endif
+        /* Locked by lock. */
+        unsigned int                    references;
+        isc_boolean_t                   exiting;
+        isc_eventlist_t                 whenshutdown;
+        unsigned int                    activebuckets;
+        isc_boolean_t                   priming;
+        unsigned int                    spillat;
+        unsigned int                    nextdisp;
+        /* Locked by primelock. */
+        dns_fetch_t *                   primefetch;
+        /* Locked by nlock. */
+        unsigned int                    nfctx;
+        /* Locked by poollock. */
+        dns_dispatch_t **               dispatchv4pool;
+        dns_dispatch_t **               dispatchv6pool;
+
+#ifdef LRU_DEBUG
+        /* Unlocked: just for debug */
+        unsigned int                    extqueries;
+        unsigned int                    extqueries_ns;
+        unsigned int                    extqueries_soa;
+        unsigned int                    extqueries_a;
+        unsigned int                    extqueries_aaaa;
 #endif
-       dns_rbt_t *                     mustbesecure;
-       unsigned int                    spillatmax;
-       unsigned int                    spillatmin;
-       isc_timer_t *                   spillattimer;
-       isc_boolean_t                   zero_no_soa_ttl;
-       isc_timer_t *                   disppooltimer;
-       /* Locked by lock. */
-       unsigned int                    references;
-       isc_boolean_t                   exiting;
-       isc_eventlist_t                 whenshutdown;
-       unsigned int                    activebuckets;
-       isc_boolean_t                   priming;
-       unsigned int                    spillat;
-       unsigned int                    nextdisp;
-       /* Locked by primelock. */
-       dns_fetch_t *                   primefetch;
-       /* Locked by nlock. */
-       unsigned int                    nfctx;
-       /* Locked by poollock. */
-       dns_dispatch_t **               dispatchv4pool;
-       dns_dispatch_t **               dispatchv6pool;
 };
 
-#define RES_MAGIC                      ISC_MAGIC('R', 'e', 's', '!')
-#define VALID_RESOLVER(res)            ISC_MAGIC_VALID(res, RES_MAGIC)
+#define RES_MAGIC                       ISC_MAGIC('R', 'e', 's', '!')
+#define VALID_RESOLVER(res)             ISC_MAGIC_VALID(res, RES_MAGIC)
 
 /*%
  * Private addrinfo flags.  These must not conflict with DNS_FETCHOPT_NOEDNS0,
  * which we also use as an addrinfo flag.
  */
-#define FCTX_ADDRINFO_MARK             0x0001
-#define FCTX_ADDRINFO_FORWARDER                0x1000
-#define UNMARKED(a)                    (((a)->flags & FCTX_ADDRINFO_MARK) \
-                                        == 0)
-#define ISFORWARDER(a)                 (((a)->flags & \
-                                        FCTX_ADDRINFO_FORWARDER) != 0)
+#define FCTX_ADDRINFO_MARK              0x0001
+#define FCTX_ADDRINFO_FORWARDER         0x1000
+#define UNMARKED(a)                     (((a)->flags & FCTX_ADDRINFO_MARK) \
+                                         == 0)
+#define ISFORWARDER(a)                  (((a)->flags & \
+                                         FCTX_ADDRINFO_FORWARDER) != 0)
 
 #define NXDOMAIN(r) (((r)->attributes & DNS_RDATASETATTR_NXDOMAIN) != 0)
 
@@ -394,2324 +408,2347 @@ static void resquery_connected(isc_task_t *task, isc_event_t *event);
 static void fctx_try(fetchctx_t *fctx);
 static isc_boolean_t fctx_destroy(fetchctx_t *fctx);
 static isc_result_t ncache_adderesult(dns_message_t *message,
-                                     dns_db_t *cache, dns_dbnode_t *node,
-                                     dns_rdatatype_t covers,
-                                     isc_stdtime_t now, dns_ttl_t maxttl,
-                                     dns_rdataset_t *ardataset,
-                                     isc_result_t *eresultp);
-static void validated(isc_task_t *task, isc_event_t *event); 
+                                      dns_db_t *cache, dns_dbnode_t *node,
+                                      dns_rdatatype_t covers,
+                                      isc_stdtime_t now, dns_ttl_t maxttl,
+                                      dns_rdataset_t *ardataset,
+                                      isc_result_t *eresultp);
+static void validated(isc_task_t *task, isc_event_t *event);
 static void maybe_destroy(fetchctx_t *fctx);
 
+#ifdef LRU_DEBUG
+static void timer_dump(isc_task_t *task, isc_event_t *ev);
+#endif
+
 static isc_result_t
 valcreate(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, dns_name_t *name,
-         dns_rdatatype_t type, dns_rdataset_t *rdataset,
-         dns_rdataset_t *sigrdataset, unsigned int valoptions,
-         isc_task_t *task)
+          dns_rdatatype_t type, dns_rdataset_t *rdataset,
+          dns_rdataset_t *sigrdataset, unsigned int valoptions,
+          isc_task_t *task)
 {
-       dns_validator_t *validator = NULL;
-       dns_valarg_t *valarg;
-       isc_result_t result;
-
-       valarg = isc_mem_get(fctx->res->buckets[fctx->bucketnum].mctx,
-                            sizeof(*valarg));
-       if (valarg == NULL)
-               return (ISC_R_NOMEMORY);
-
-       valarg->fctx = fctx;
-       valarg->addrinfo = addrinfo;
-
-       if (!ISC_LIST_EMPTY(fctx->validators))
-               INSIST((valoptions & DNS_VALIDATOR_DEFER) != 0);
-
-       result = dns_validator_create(fctx->res->view, name, type, rdataset,
-                                     sigrdataset, fctx->rmessage,
-                                     valoptions, task, validated, valarg,
-                                     &validator);
-       if (result == ISC_R_SUCCESS) {
-               if ((valoptions & DNS_VALIDATOR_DEFER) == 0) {
-                       INSIST(fctx->validator == NULL);
-                       fctx->validator  = validator;
-               }
-               ISC_LIST_APPEND(fctx->validators, validator, link);
-       } else
-               isc_mem_put(fctx->res->buckets[fctx->bucketnum].mctx,
-                           valarg, sizeof(*valarg));
-       return (result);
+        dns_validator_t *validator = NULL;
+        dns_valarg_t *valarg;
+        isc_result_t result;
+
+        valarg = isc_mem_get(fctx->res->buckets[fctx->bucketnum].mctx,
+                             sizeof(*valarg));
+        if (valarg == NULL)
+                return (ISC_R_NOMEMORY);
+
+        valarg->fctx = fctx;
+        valarg->addrinfo = addrinfo;
+
+        if (!ISC_LIST_EMPTY(fctx->validators))
+                INSIST((valoptions & DNS_VALIDATOR_DEFER) != 0);
+
+        result = dns_validator_create(fctx->res->view, name, type, rdataset,
+                                      sigrdataset, fctx->rmessage,
+                                      valoptions, task, validated, valarg,
+                                      &validator);
+        if (result == ISC_R_SUCCESS) {
+                if ((valoptions & DNS_VALIDATOR_DEFER) == 0) {
+                        INSIST(fctx->validator == NULL);
+                        fctx->validator  = validator;
+                }
+                ISC_LIST_APPEND(fctx->validators, validator, link);
+        } else
+                isc_mem_put(fctx->res->buckets[fctx->bucketnum].mctx,
+                            valarg, sizeof(*valarg));
+        return (result);
 }
 
 static isc_boolean_t
 fix_mustbedelegationornxdomain(dns_message_t *message, fetchctx_t *fctx) {
-       dns_name_t *name;
-       dns_name_t *domain = &fctx->domain;
-       dns_rdataset_t *rdataset;
-       dns_rdatatype_t type;
-       isc_result_t result;
-       isc_boolean_t keep_auth = ISC_FALSE;
-
-       if (message->rcode == dns_rcode_nxdomain)
-               return (ISC_FALSE);
-
-       /*
-        * Look for BIND 8 style delegations.
-        * Also look for answers to ANY queries where the duplicate NS RRset
-        * may have been stripped from the authority section.
-        */
-       if (message->counts[DNS_SECTION_ANSWER] != 0 &&
-           (fctx->type == dns_rdatatype_ns ||
-            fctx->type == dns_rdatatype_any)) {
-               result = dns_message_firstname(message, DNS_SECTION_ANSWER);
-               while (result == ISC_R_SUCCESS) {
-                       name = NULL;
-                       dns_message_currentname(message, DNS_SECTION_ANSWER,
-                                               &name);
-                       for (rdataset = ISC_LIST_HEAD(name->list);
-                            rdataset != NULL;
-                            rdataset = ISC_LIST_NEXT(rdataset, link)) {
-                               type = rdataset->type;
-                               if (type != dns_rdatatype_ns)
-                                       continue;
-                               if (dns_name_issubdomain(name, domain))
-                                       return (ISC_FALSE);
-                       }
-                       result = dns_message_nextname(message,
-                                                     DNS_SECTION_ANSWER);
-               }
-       }
-
-       /* Look for referral. */
-       if (message->counts[DNS_SECTION_AUTHORITY] == 0)
-               goto munge;
-
-       result = dns_message_firstname(message, DNS_SECTION_AUTHORITY);
-       while (result == ISC_R_SUCCESS) {
-               name = NULL;
-               dns_message_currentname(message, DNS_SECTION_AUTHORITY, &name);
-               for (rdataset = ISC_LIST_HEAD(name->list);
-                    rdataset != NULL;
-                    rdataset = ISC_LIST_NEXT(rdataset, link)) {
-                       type = rdataset->type;
-                       if (type == dns_rdatatype_soa &&
-                           dns_name_equal(name, domain))
-                               keep_auth = ISC_TRUE;
-                       if (type != dns_rdatatype_ns &&
-                           type != dns_rdatatype_soa)
-                               continue;
-                       if (dns_name_equal(name, domain))
-                               goto munge;
-                       if (dns_name_issubdomain(name, domain))
-                               return (ISC_FALSE);
-               }
-               result = dns_message_nextname(message, DNS_SECTION_AUTHORITY);
-       }
+        dns_name_t *name;
+        dns_name_t *domain = &fctx->domain;
+        dns_rdataset_t *rdataset;
+        dns_rdatatype_t type;
+        isc_result_t result;
+        isc_boolean_t keep_auth = ISC_FALSE;
+
+        if (message->rcode == dns_rcode_nxdomain)
+                return (ISC_FALSE);
+
+        /*
+         * Look for BIND 8 style delegations.
+         * Also look for answers to ANY queries where the duplicate NS RRset
+         * may have been stripped from the authority section.
+         */
+        if (message->counts[DNS_SECTION_ANSWER] != 0 &&
+            (fctx->type == dns_rdatatype_ns ||
+             fctx->type == dns_rdatatype_any)) {
+                result = dns_message_firstname(message, DNS_SECTION_ANSWER);
+                while (result == ISC_R_SUCCESS) {
+                        name = NULL;
+                        dns_message_currentname(message, DNS_SECTION_ANSWER,
+                                                &name);
+                        for (rdataset = ISC_LIST_HEAD(name->list);
+                             rdataset != NULL;
+                             rdataset = ISC_LIST_NEXT(rdataset, link)) {
+                                type = rdataset->type;
+                                if (type != dns_rdatatype_ns)
+                                        continue;
+                                if (dns_name_issubdomain(name, domain))
+                                        return (ISC_FALSE);
+                        }
+                        result = dns_message_nextname(message,
+                                                      DNS_SECTION_ANSWER);
+                }
+        }
+
+        /* Look for referral. */
+        if (message->counts[DNS_SECTION_AUTHORITY] == 0)
+                goto munge;
+
+        result = dns_message_firstname(message, DNS_SECTION_AUTHORITY);
+        while (result == ISC_R_SUCCESS) {
+                name = NULL;
+                dns_message_currentname(message, DNS_SECTION_AUTHORITY, &name);
+                for (rdataset = ISC_LIST_HEAD(name->list);
+                     rdataset != NULL;
+                     rdataset = ISC_LIST_NEXT(rdataset, link)) {
+                        type = rdataset->type;
+                        if (type == dns_rdatatype_soa &&
+                            dns_name_equal(name, domain))
+                                keep_auth = ISC_TRUE;
+                        if (type != dns_rdatatype_ns &&
+                            type != dns_rdatatype_soa)
+                                continue;
+                        if (dns_name_equal(name, domain))
+                                goto munge;
+                        if (dns_name_issubdomain(name, domain))
+                                return (ISC_FALSE);
+                }
+                result = dns_message_nextname(message, DNS_SECTION_AUTHORITY);
+        }
 
  munge:
-       message->rcode = dns_rcode_nxdomain;
-       message->counts[DNS_SECTION_ANSWER] = 0;
-       if (!keep_auth)
-               message->counts[DNS_SECTION_AUTHORITY] = 0;
-       message->counts[DNS_SECTION_ADDITIONAL] = 0;
-       return (ISC_TRUE);
+        message->rcode = dns_rcode_nxdomain;
+        message->counts[DNS_SECTION_ANSWER] = 0;
+        if (!keep_auth)
+                message->counts[DNS_SECTION_AUTHORITY] = 0;
+        message->counts[DNS_SECTION_ADDITIONAL] = 0;
+        return (ISC_TRUE);
 }
 
 static inline isc_result_t
 fctx_starttimer(fetchctx_t *fctx) {
-       /*
-        * Start the lifetime timer for fctx.
-        *
-        * This is also used for stopping the idle timer; in that
-        * case we must purge events already posted to ensure that
-        * no further idle events are delivered.
-        */
-       return (isc_timer_reset(fctx->timer, isc_timertype_once,
-                               &fctx->expires, NULL, ISC_TRUE));
+        /*
+         * Start the lifetime timer for fctx.
+         *
+         * This is also used for stopping the idle timer; in that
+         * case we must purge events already posted to ensure that
+         * no further idle events are delivered.
+         */
+        return (isc_timer_reset(fctx->timer, isc_timertype_once,
+                                &fctx->expires, NULL, ISC_TRUE));
 }
 
 static inline void
 fctx_stoptimer(fetchctx_t *fctx) {
-       isc_result_t result;
-
-       /*
-        * We don't return a result if resetting the timer to inactive fails
-        * since there's nothing to be done about it.  Resetting to inactive
-        * should never fail anyway, since the code as currently written
-        * cannot fail in that case.
-        */
-       result = isc_timer_reset(fctx->timer, isc_timertype_inactive,
-                                 NULL, NULL, ISC_TRUE);
-       if (result != ISC_R_SUCCESS) {
-               UNEXPECTED_ERROR(__FILE__, __LINE__,
-                                "isc_timer_reset(): %s",
-                                isc_result_totext(result));
-       }
+        isc_result_t result;
+
+        /*
+         * We don't return a result if resetting the timer to inactive fails
+         * since there's nothing to be done about it.  Resetting to inactive
+         * should never fail anyway, since the code as currently written
+         * cannot fail in that case.
+         */
+        result = isc_timer_reset(fctx->timer, isc_timertype_inactive,
+                                  NULL, NULL, ISC_TRUE);
+        if (result != ISC_R_SUCCESS) {
+                UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                 "isc_timer_reset(): %s",
+                                 isc_result_totext(result));
+        }
 }
 
 
 static inline isc_result_t
 fctx_startidletimer(fetchctx_t *fctx) {
-       /*
-        * Start the idle timer for fctx.  The lifetime timer continues
-        * to be in effect.
-        */
-       return (isc_timer_reset(fctx->timer, isc_timertype_once,
-                               &fctx->expires, &fctx->interval,
-                               ISC_FALSE));
+        /*
+         * Start the idle timer for fctx.  The lifetime timer continues
+         * to be in effect.
+         */
+        return (isc_timer_reset(fctx->timer, isc_timertype_once,
+                                &fctx->expires, &fctx->interval,
+                                ISC_FALSE));
 }
 
 /*
  * Stopping the idle timer is equivalent to calling fctx_starttimer(), but
  * we use fctx_stopidletimer for readability in the code below.
  */
-#define fctx_stopidletimer     fctx_starttimer
+#define fctx_stopidletimer      fctx_starttimer
 
 
 static inline void
 resquery_destroy(resquery_t **queryp) {
-       resquery_t *query;
+        resquery_t *query;
 
-       REQUIRE(queryp != NULL);
-       query = *queryp;
-       REQUIRE(!ISC_LINK_LINKED(query, link));
+        REQUIRE(queryp != NULL);
+        query = *queryp;
+        REQUIRE(!ISC_LINK_LINKED(query, link));
 
-       INSIST(query->tcpsocket == NULL);
+        INSIST(query->tcpsocket == NULL);
 
-       query->fctx->nqueries--;
-       if (SHUTTINGDOWN(query->fctx))
-               maybe_destroy(query->fctx);     /* Locks bucket. */
-       query->magic = 0;
-       isc_mem_put(query->mctx, query, sizeof(*query));
-       *queryp = NULL;
+        query->fctx->nqueries--;
+        if (SHUTTINGDOWN(query->fctx))
+                maybe_destroy(query->fctx);     /* Locks bucket. */
+        query->magic = 0;
+        isc_mem_put(query->mctx, query, sizeof(*query));
+        *queryp = NULL;
 }
 
 static void
 fctx_cancelquery(resquery_t **queryp, dns_dispatchevent_t **deventp,
-                isc_time_t *finish, isc_boolean_t no_response)
+                 isc_time_t *finish, isc_boolean_t no_response)
 {
-       fetchctx_t *fctx;
-       resquery_t *query;
-       unsigned int rtt;
-       unsigned int factor;
-       dns_adbfind_t *find;
-       dns_adbaddrinfo_t *addrinfo;
-
-       query = *queryp;
-       fctx = query->fctx;
-
-       FCTXTRACE("cancelquery");
-
-       REQUIRE(!RESQUERY_CANCELED(query));
-
-       query->attributes |= RESQUERY_ATTR_CANCELED;
-
-       /*
-        * Should we update the RTT?
-        */
-       if (finish != NULL || no_response) {
-               if (finish != NULL) {
-                       /*
-                        * We have both the start and finish times for this
-                        * packet, so we can compute a real RTT.
-                        */
-                       rtt = (unsigned int)isc_time_microdiff(finish,
-                                                              &query->start);
-                       factor = DNS_ADB_RTTADJDEFAULT;
-               } else {
-                       /*
-                        * We don't have an RTT for this query.  Maybe the
-                        * packet was lost, or maybe this server is very
-                        * slow.  We don't know.  Increase the RTT.
-                        */
-                       INSIST(no_response);
-                       rtt = query->addrinfo->srtt + 200000;
-                       if (rtt > 10000000)
-                               rtt = 10000000;
-                       /*
-                        * Replace the current RTT with our value.
-                        */
-                       factor = DNS_ADB_RTTADJREPLACE;
-               }
-               dns_adb_adjustsrtt(fctx->adb, query->addrinfo, rtt, factor);
-       }
-
-       /*
-        * Age RTTs of servers not tried.
-        */
-       factor = DNS_ADB_RTTADJAGE;
-       if (finish != NULL)
-               for (addrinfo = ISC_LIST_HEAD(fctx->forwaddrs);
-                    addrinfo != NULL;
-                    addrinfo = ISC_LIST_NEXT(addrinfo, publink))
-                       if (UNMARKED(addrinfo))
-                               dns_adb_adjustsrtt(fctx->adb, addrinfo,
-                                                  0, factor);
-
-       if (finish != NULL && TRIEDFIND(fctx))
-               for (find = ISC_LIST_HEAD(fctx->finds);
-                    find != NULL;
-                    find = ISC_LIST_NEXT(find, publink))
-                       for (addrinfo = ISC_LIST_HEAD(find->list);
-                            addrinfo != NULL;
-                            addrinfo = ISC_LIST_NEXT(addrinfo, publink))
-                               if (UNMARKED(addrinfo))
-                                       dns_adb_adjustsrtt(fctx->adb, addrinfo,
-                                                          0, factor);
-
-       if (finish != NULL && TRIEDALT(fctx)) {
-               for (addrinfo = ISC_LIST_HEAD(fctx->altaddrs);
-                    addrinfo != NULL;
-                    addrinfo = ISC_LIST_NEXT(addrinfo, publink))
-                       if (UNMARKED(addrinfo))
-                               dns_adb_adjustsrtt(fctx->adb, addrinfo,
-                                                  0, factor);
-               for (find = ISC_LIST_HEAD(fctx->altfinds);
-                    find != NULL;
-                    find = ISC_LIST_NEXT(find, publink))
-                       for (addrinfo = ISC_LIST_HEAD(find->list);
-                            addrinfo != NULL;
-                            addrinfo = ISC_LIST_NEXT(addrinfo, publink))
-                               if (UNMARKED(addrinfo))
-                                       dns_adb_adjustsrtt(fctx->adb, addrinfo,
-                                                          0, factor);
-       }
-
-       if (query->dispentry != NULL)
-               dns_dispatch_removeresponse(&query->dispentry, deventp);
-
-       ISC_LIST_UNLINK(fctx->queries, query, link);
-
-       if (query->tsig != NULL)
-               isc_buffer_free(&query->tsig);
-
-       if (query->tsigkey != NULL)
-               dns_tsigkey_detach(&query->tsigkey);
-
-       /*
-        * Check for any outstanding socket events.  If they exist, cancel
-        * them and let the event handlers finish the cleanup.  The resolver
-        * only needs to worry about managing the connect and send events;
-        * the dispatcher manages the recv events.
-        */
-       if (RESQUERY_CONNECTING(query))
-               /*
-                * Cancel the connect.
-                */
-               isc_socket_cancel(query->tcpsocket, NULL,
-                                 ISC_SOCKCANCEL_CONNECT);
-       else if (RESQUERY_SENDING(query))
-               /*
-                * Cancel the pending send.
-                */
-               isc_socket_cancel(dns_dispatch_getsocket(query->dispatch),
-                                 NULL, ISC_SOCKCANCEL_SEND);
-
-       if (query->dispatch != NULL)
-               dns_dispatch_detach(&query->dispatch);
-
-       if (! (RESQUERY_CONNECTING(query) || RESQUERY_SENDING(query)))
-               /*
-                * It's safe to destroy the query now.
-                */
-               resquery_destroy(&query);
+        fetchctx_t *fctx;
+        resquery_t *query;
+        unsigned int rtt;
+        unsigned int factor;
+        dns_adbfind_t *find;
+        dns_adbaddrinfo_t *addrinfo;
+
+        query = *queryp;
+        fctx = query->fctx;
+
+        FCTXTRACE("cancelquery");
+
+        REQUIRE(!RESQUERY_CANCELED(query));
+
+        query->attributes |= RESQUERY_ATTR_CANCELED;
+
+        /*
+         * Should we update the RTT?
+         */
+        if (finish != NULL || no_response) {
+                if (finish != NULL) {
+                        /*
+                         * We have both the start and finish times for this
+                         * packet, so we can compute a real RTT.
+                         */
+                        rtt = (unsigned int)isc_time_microdiff(finish,
+                                                               &query->start);
+                        factor = DNS_ADB_RTTADJDEFAULT;
+                } else {
+                        /*
+                         * We don't have an RTT for this query.  Maybe the
+                         * packet was lost, or maybe this server is very
+                         * slow.  We don't know.  Increase the RTT.
+                         */
+                        INSIST(no_response);
+                        rtt = query->addrinfo->srtt + 200000;
+                        if (rtt > 10000000)
+                                rtt = 10000000;
+                        /*
+                         * Replace the current RTT with our value.
+                         */
+                        factor = DNS_ADB_RTTADJREPLACE;
+                }
+                dns_adb_adjustsrtt(fctx->adb, query->addrinfo, rtt, factor);
+        }
+
+        /*
+         * Age RTTs of servers not tried.
+         */
+        factor = DNS_ADB_RTTADJAGE;
+        if (finish != NULL)
+                for (addrinfo = ISC_LIST_HEAD(fctx->forwaddrs);
+                     addrinfo != NULL;
+                     addrinfo = ISC_LIST_NEXT(addrinfo, publink))
+                        if (UNMARKED(addrinfo))
+                                dns_adb_adjustsrtt(fctx->adb, addrinfo,
+                                                   0, factor);
+
+        if (finish != NULL && TRIEDFIND(fctx))
+                for (find = ISC_LIST_HEAD(fctx->finds);
+                     find != NULL;
+                     find = ISC_LIST_NEXT(find, publink))
+                        for (addrinfo = ISC_LIST_HEAD(find->list);
+                             addrinfo != NULL;
+                             addrinfo = ISC_LIST_NEXT(addrinfo, publink))
+                                if (UNMARKED(addrinfo))
+                                        dns_adb_adjustsrtt(fctx->adb, addrinfo,
+                                                           0, factor);
+
+        if (finish != NULL && TRIEDALT(fctx)) {
+                for (addrinfo = ISC_LIST_HEAD(fctx->altaddrs);
+                     addrinfo != NULL;
+                     addrinfo = ISC_LIST_NEXT(addrinfo, publink))
+                        if (UNMARKED(addrinfo))
+                                dns_adb_adjustsrtt(fctx->adb, addrinfo,
+                                                   0, factor);
+                for (find = ISC_LIST_HEAD(fctx->altfinds);
+                     find != NULL;
+                     find = ISC_LIST_NEXT(find, publink))
+                        for (addrinfo = ISC_LIST_HEAD(find->list);
+                             addrinfo != NULL;
+                             addrinfo = ISC_LIST_NEXT(addrinfo, publink))
+                                if (UNMARKED(addrinfo))
+                                        dns_adb_adjustsrtt(fctx->adb, addrinfo,
+                                                           0, factor);
+        }
+
+        if (query->dispentry != NULL)
+                dns_dispatch_removeresponse(&query->dispentry, deventp);
+
+        ISC_LIST_UNLINK(fctx->queries, query, link);
+
+        if (query->tsig != NULL)
+                isc_buffer_free(&query->tsig);
+
+        if (query->tsigkey != NULL)
+                dns_tsigkey_detach(&query->tsigkey);
+
+        /*
+         * Check for any outstanding socket events.  If they exist, cancel
+         * them and let the event handlers finish the cleanup.  The resolver
+         * only needs to worry about managing the connect and send events;
+         * the dispatcher manages the recv events.
+         */
+        if (RESQUERY_CONNECTING(query))
+                /*
+                 * Cancel the connect.
+                 */
+                isc_socket_cancel(query->tcpsocket, NULL,
+                                  ISC_SOCKCANCEL_CONNECT);
+        else if (RESQUERY_SENDING(query))
+                /*
+                 * Cancel the pending send.
+                 */
+                isc_socket_cancel(dns_dispatch_getsocket(query->dispatch),
+                                  NULL, ISC_SOCKCANCEL_SEND);
+
+        if (query->dispatch != NULL)
+                dns_dispatch_detach(&query->dispatch);
+
+        if (! (RESQUERY_CONNECTING(query) || RESQUERY_SENDING(query)))
+                /*
+                 * It's safe to destroy the query now.
+                 */
+                resquery_destroy(&query);
 }
 
 static void
 fctx_cancelqueries(fetchctx_t *fctx, isc_boolean_t no_response) {
-       resquery_t *query, *next_query;
+        resquery_t *query, *next_query;
 
-       FCTXTRACE("cancelqueries");
+        FCTXTRACE("cancelqueries");
 
-       for (query = ISC_LIST_HEAD(fctx->queries);
-            query != NULL;
-            query = next_query) {
-               next_query = ISC_LIST_NEXT(query, link);
-               fctx_cancelquery(&query, NULL, NULL, no_response);
-       }
+        for (query = ISC_LIST_HEAD(fctx->queries);
+             query != NULL;
+             query = next_query) {
+                next_query = ISC_LIST_NEXT(query, link);
+                fctx_cancelquery(&query, NULL, NULL, no_response);
+        }
 }
 
 static void
 fctx_cleanupfinds(fetchctx_t *fctx) {
-       dns_adbfind_t *find, *next_find;
-
-       REQUIRE(ISC_LIST_EMPTY(fctx->queries));
-
-       for (find = ISC_LIST_HEAD(fctx->finds);
-            find != NULL;
-            find = next_find) {
-               next_find = ISC_LIST_NEXT(find, publink);
-               ISC_LIST_UNLINK(fctx->finds, find, publink);
-               dns_adb_destroyfind(&find);
-       }
-       fctx->find = NULL;
+        dns_adbfind_t *find, *next_find;
+
+        REQUIRE(ISC_LIST_EMPTY(fctx->queries));
+
+        for (find = ISC_LIST_HEAD(fctx->finds);
+             find != NULL;
+             find = next_find) {
+                next_find = ISC_LIST_NEXT(find, publink);
+                ISC_LIST_UNLINK(fctx->finds, find, publink);
+                dns_adb_destroyfind(&find);
+        }
+        fctx->find = NULL;
 }
 
 static void
 fctx_cleanupaltfinds(fetchctx_t *fctx) {
-       dns_adbfind_t *find, *next_find;
-
-       REQUIRE(ISC_LIST_EMPTY(fctx->queries));
-
-       for (find = ISC_LIST_HEAD(fctx->altfinds);
-            find != NULL;
-            find = next_find) {
-               next_find = ISC_LIST_NEXT(find, publink);
-               ISC_LIST_UNLINK(fctx->altfinds, find, publink);
-               dns_adb_destroyfind(&find);
-       }
-       fctx->altfind = NULL;
+        dns_adbfind_t *find, *next_find;
+
+        REQUIRE(ISC_LIST_EMPTY(fctx->queries));
+
+        for (find = ISC_LIST_HEAD(fctx->altfinds);
+             find != NULL;
+             find = next_find) {
+                next_find = ISC_LIST_NEXT(find, publink);
+                ISC_LIST_UNLINK(fctx->altfinds, find, publink);
+                dns_adb_destroyfind(&find);
+        }
+        fctx->altfind = NULL;
 }
 
 static void
 fctx_cleanupforwaddrs(fetchctx_t *fctx) {
-       dns_adbaddrinfo_t *addr, *next_addr;
+        dns_adbaddrinfo_t *addr, *next_addr;
 
-       REQUIRE(ISC_LIST_EMPTY(fctx->queries));
+        REQUIRE(ISC_LIST_EMPTY(fctx->queries));
 
-       for (addr = ISC_LIST_HEAD(fctx->forwaddrs);
-            addr != NULL;
-            addr = next_addr) {
-               next_addr = ISC_LIST_NEXT(addr, publink);
-               ISC_LIST_UNLINK(fctx->forwaddrs, addr, publink);
-               dns_adb_freeaddrinfo(fctx->adb, &addr);
-       }
+        for (addr = ISC_LIST_HEAD(fctx->forwaddrs);
+             addr != NULL;
+             addr = next_addr) {
+                next_addr = ISC_LIST_NEXT(addr, publink);
+                ISC_LIST_UNLINK(fctx->forwaddrs, addr, publink);
+                dns_adb_freeaddrinfo(fctx->adb, &addr);
+        }
 }
 
 static void
 fctx_cleanupaltaddrs(fetchctx_t *fctx) {
-       dns_adbaddrinfo_t *addr, *next_addr;
+        dns_adbaddrinfo_t *addr, *next_addr;
 
-       REQUIRE(ISC_LIST_EMPTY(fctx->queries));
+        REQUIRE(ISC_LIST_EMPTY(fctx->queries));
 
-       for (addr = ISC_LIST_HEAD(fctx->altaddrs);
-            addr != NULL;
-            addr = next_addr) {
-               next_addr = ISC_LIST_NEXT(addr, publink);
-               ISC_LIST_UNLINK(fctx->altaddrs, addr, publink);
-               dns_adb_freeaddrinfo(fctx->adb, &addr);
-       }
+        for (addr = ISC_LIST_HEAD(fctx->altaddrs);
+             addr != NULL;
+             addr = next_addr) {
+                next_addr = ISC_LIST_NEXT(addr, publink);
+                ISC_LIST_UNLINK(fctx->altaddrs, addr, publink);
+                dns_adb_freeaddrinfo(fctx->adb, &addr);
+        }
 }
 
 static inline void
 fctx_stopeverything(fetchctx_t *fctx, isc_boolean_t no_response) {
-       FCTXTRACE("stopeverything");
-       fctx_cancelqueries(fctx, no_response);
-       fctx_cleanupfinds(fctx);
-       fctx_cleanupaltfinds(fctx);
-       fctx_cleanupforwaddrs(fctx);
-       fctx_cleanupaltaddrs(fctx);
-       fctx_stoptimer(fctx);
+        FCTXTRACE("stopeverything");
+        fctx_cancelqueries(fctx, no_response);
+        fctx_cleanupfinds(fctx);
+        fctx_cleanupaltfinds(fctx);
+        fctx_cleanupforwaddrs(fctx);
+        fctx_cleanupaltaddrs(fctx);
+        fctx_stoptimer(fctx);
 }
 
 static inline void
 fctx_sendevents(fetchctx_t *fctx, isc_result_t result) {
-       dns_fetchevent_t *event, *next_event;
-       isc_task_t *task;
-       unsigned int count = 0;
-       isc_interval_t i;
-       isc_boolean_t logit = ISC_FALSE;
-
-       /*
-        * Caller must be holding the appropriate bucket lock.
-        */
-       REQUIRE(fctx->state == fetchstate_done);
-
-       FCTXTRACE("sendevents");
-
-       for (event = ISC_LIST_HEAD(fctx->events);
-            event != NULL;
-            event = next_event) {
-               next_event = ISC_LIST_NEXT(event, ev_link);
-               ISC_LIST_UNLINK(fctx->events, event, ev_link);
-               task = event->ev_sender;
-               event->ev_sender = fctx;
-               if (!HAVE_ANSWER(fctx))
-                       event->result = result;
-
-               INSIST(result != ISC_R_SUCCESS ||
-                      dns_rdataset_isassociated(event->rdataset) ||
-                      fctx->type == dns_rdatatype_any ||
-                      fctx->type == dns_rdatatype_rrsig ||
-                      fctx->type == dns_rdatatype_sig);
-               
-               /*
-                * Negative results must be indicated in event->result.
-                */
-               if (dns_rdataset_isassociated(event->rdataset) &&
-                   event->rdataset->type == dns_rdatatype_none) {
-                       INSIST(event->result == DNS_R_NCACHENXDOMAIN ||
-                              event->result == DNS_R_NCACHENXRRSET);
-               }
-
-               isc_task_sendanddetach(&task, ISC_EVENT_PTR(&event));
-               count++;
-       }
-
-       if ((fctx->attributes & FCTX_ATTR_HAVEANSWER) != 0 &&
-           fctx->spilled &&
-           (count < fctx->res->spillatmax || fctx->res->spillatmax == 0)) {
-               LOCK(&fctx->res->lock);
-               if (count == fctx->res->spillat && !fctx->res->exiting) {
-                       fctx->res->spillat += 5;
-                       if (fctx->res->spillat > fctx->res->spillatmax &&
-                           fctx->res->spillatmax != 0)
-                               fctx->res->spillat = fctx->res->spillatmax;
-                       isc_interval_set(&i, 20 * 60, 0);
-                       result = isc_timer_reset(fctx->res->spillattimer,
-                                                isc_timertype_ticker, NULL,
-                                                &i, ISC_TRUE);
-                       RUNTIME_CHECK(result == ISC_R_SUCCESS);
-                       logit = ISC_TRUE;
-               }
-               UNLOCK(&fctx->res->lock);
-               if (logit)
-                       isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,
-                                     DNS_LOGMODULE_RESOLVER, ISC_LOG_NOTICE,
-                                     "clients-per-query increased to %u",
-                                     count + 1);
-       }
+        dns_fetchevent_t *event, *next_event;
+        isc_task_t *task;
+        unsigned int count = 0;
+        isc_interval_t i;
+        isc_boolean_t logit = ISC_FALSE;
+
+        /*
+         * Caller must be holding the appropriate bucket lock.
+         */
+        REQUIRE(fctx->state == fetchstate_done);
+
+        FCTXTRACE("sendevents");
+
+        for (event = ISC_LIST_HEAD(fctx->events);
+             event != NULL;
+             event = next_event) {
+                next_event = ISC_LIST_NEXT(event, ev_link);
+                ISC_LIST_UNLINK(fctx->events, event, ev_link);
+                task = event->ev_sender;
+                event->ev_sender = fctx;
+                if (!HAVE_ANSWER(fctx))
+                        event->result = result;
+
+                INSIST(result != ISC_R_SUCCESS ||
+                       dns_rdataset_isassociated(event->rdataset) ||
+                       fctx->type == dns_rdatatype_any ||
+                       fctx->type == dns_rdatatype_rrsig ||
+                       fctx->type == dns_rdatatype_sig);
+
+                /*
+                 * Negative results must be indicated in event->result.
+                 */
+                if (dns_rdataset_isassociated(event->rdataset) &&
+                    event->rdataset->type == dns_rdatatype_none) {
+                        INSIST(event->result == DNS_R_NCACHENXDOMAIN ||
+                               event->result == DNS_R_NCACHENXRRSET);
+                }
+
+                isc_task_sendanddetach(&task, ISC_EVENT_PTR(&event));
+                count++;
+        }
+
+        if ((fctx->attributes & FCTX_ATTR_HAVEANSWER) != 0 &&
+            fctx->spilled &&
+            (count < fctx->res->spillatmax || fctx->res->spillatmax == 0)) {
+                LOCK(&fctx->res->lock);
+                if (count == fctx->res->spillat && !fctx->res->exiting) {
+                        fctx->res->spillat += 5;
+                        if (fctx->res->spillat > fctx->res->spillatmax &&
+                            fctx->res->spillatmax != 0)
+                                fctx->res->spillat = fctx->res->spillatmax;
+                        isc_interval_set(&i, 20 * 60, 0);
+                        result = isc_timer_reset(fctx->res->spillattimer,
+                                                 isc_timertype_ticker, NULL,
+                                                 &i, ISC_TRUE);
+                        RUNTIME_CHECK(result == ISC_R_SUCCESS);
+                        logit = ISC_TRUE;
+                }
+                UNLOCK(&fctx->res->lock);
+                if (logit)
+                        isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,
+                                      DNS_LOGMODULE_RESOLVER, ISC_LOG_NOTICE,
+                                      "clients-per-query increased to %u",
+                                      count + 1);
+        }
 }
 
 static void
 fctx_done(fetchctx_t *fctx, isc_result_t result) {
-       dns_resolver_t *res;
-       isc_boolean_t no_response;
+        dns_resolver_t *res;
+        isc_boolean_t no_response;
 
-       FCTXTRACE("done");
+        FCTXTRACE("done");
 
-       res = fctx->res;
+        res = fctx->res;
 
-       if (result == ISC_R_SUCCESS)
-               no_response = ISC_TRUE;
-       else
-               no_response = ISC_FALSE;
-       fctx_stopeverything(fctx, no_response);
+        if (result == ISC_R_SUCCESS)
+                no_response = ISC_TRUE;
+        else
+                no_response = ISC_FALSE;
+        fctx_stopeverything(fctx, no_response);
 
-       LOCK(&res->buckets[fctx->bucketnum].lock);
+        LOCK(&res->buckets[fctx->bucketnum].lock);
 
-       fctx->state = fetchstate_done;
-       fctx->attributes &= ~FCTX_ATTR_ADDRWAIT;
-       fctx_sendevents(fctx, result);
+        fctx->state = fetchstate_done;
+        fctx->attributes &= ~FCTX_ATTR_ADDRWAIT;
+        fctx_sendevents(fctx, result);
 
-       UNLOCK(&res->buckets[fctx->bucketnum].lock);
+        UNLOCK(&res->buckets[fctx->bucketnum].lock);
 }
 
 static void
 resquery_senddone(isc_task_t *task, isc_event_t *event) {
-       isc_socketevent_t *sevent = (isc_socketevent_t *)event;
-       resquery_t *query = event->ev_arg;
-       isc_boolean_t retry = ISC_FALSE;
-       isc_result_t result;
-       fetchctx_t *fctx;
-
-       REQUIRE(event->ev_type == ISC_SOCKEVENT_SENDDONE);
-
-       QTRACE("senddone");
-
-       /*
-        * XXXRTH
-        *
-        * Currently we don't wait for the senddone event before retrying
-        * a query.  This means that if we get really behind, we may end
-        * up doing extra work!
-        */
-
-       UNUSED(task);
-
-       INSIST(RESQUERY_SENDING(query));
-
-       query->sends--;
-       fctx = query->fctx;
-
-       if (RESQUERY_CANCELED(query)) {
-               if (query->sends == 0) {
-                       /*
-                        * This query was canceled while the
-                        * isc_socket_sendto() was in progress.
-                        */
-                       if (query->tcpsocket != NULL)
-                               isc_socket_detach(&query->tcpsocket);
-                       resquery_destroy(&query);
-               }
-       } else 
-               switch (sevent->result) {
-               case ISC_R_SUCCESS:
-                       break;
-
-               case ISC_R_HOSTUNREACH:
-               case ISC_R_NETUNREACH:
-               case ISC_R_NOPERM:
-               case ISC_R_ADDRNOTAVAIL:
-               case ISC_R_CONNREFUSED:
-
-                       /*
-                        * No route to remote.
-                        */
-                       fctx_cancelquery(&query, NULL, NULL, ISC_TRUE);
-                       retry = ISC_TRUE;
-                       break;
-
-               default:
-                       fctx_cancelquery(&query, NULL, NULL, ISC_FALSE);
-                       break;
-               }
-
-       isc_event_free(&event);
-
-       if (retry) {
-               /*
-                * Behave as if the idle timer has expired.  For TCP
-                * this may not actually reflect the latest timer.
-                */
-               fctx->attributes &= ~FCTX_ATTR_ADDRWAIT;
-               result = fctx_stopidletimer(fctx);
-               if (result != ISC_R_SUCCESS)
-                       fctx_done(fctx, result);
-               else
-                       fctx_try(fctx);
-       }
+        isc_socketevent_t *sevent = (isc_socketevent_t *)event;
+        resquery_t *query = event->ev_arg;
+        isc_boolean_t retry = ISC_FALSE;
+        isc_result_t result;
+        fetchctx_t *fctx;
+
+        REQUIRE(event->ev_type == ISC_SOCKEVENT_SENDDONE);
+
+        QTRACE("senddone");
+
+        /*
+         * XXXRTH
+         *
+         * Currently we don't wait for the senddone event before retrying
+         * a query.  This means that if we get really behind, we may end
+         * up doing extra work!
+         */
+
+        UNUSED(task);
+
+        INSIST(RESQUERY_SENDING(query));
+
+        query->sends--;
+        fctx = query->fctx;
+
+        if (RESQUERY_CANCELED(query)) {
+                if (query->sends == 0) {
+                        /*
+                         * This query was canceled while the
+                         * isc_socket_sendto() was in progress.
+                         */
+                        if (query->tcpsocket != NULL)
+                                isc_socket_detach(&query->tcpsocket);
+                        resquery_destroy(&query);
+                }
+        } else
+                switch (sevent->result) {
+                case ISC_R_SUCCESS:
+                        break;
+
+                case ISC_R_HOSTUNREACH:
+                case ISC_R_NETUNREACH:
+                case ISC_R_NOPERM:
+                case ISC_R_ADDRNOTAVAIL:
+                case ISC_R_CONNREFUSED:
+
+                        /*
+                         * No route to remote.
+                         */
+                        fctx_cancelquery(&query, NULL, NULL, ISC_TRUE);
+                        retry = ISC_TRUE;
+                        break;
+
+                default:
+                        fctx_cancelquery(&query, NULL, NULL, ISC_FALSE);
+                        break;
+                }
+
+        isc_event_free(&event);
+
+        if (retry) {
+                /*
+                 * Behave as if the idle timer has expired.  For TCP
+                 * this may not actually reflect the latest timer.
+                 */
+                fctx->attributes &= ~FCTX_ATTR_ADDRWAIT;
+                result = fctx_stopidletimer(fctx);
+                if (result != ISC_R_SUCCESS)
+                        fctx_done(fctx, result);
+                else
+                        fctx_try(fctx);
+        }
 }
 
 static inline isc_result_t
 fctx_addopt(dns_message_t *message, unsigned int version, isc_uint16_t udpsize)
-{ 
-       dns_rdataset_t *rdataset;
-       dns_rdatalist_t *rdatalist;
-       dns_rdata_t *rdata;
-       isc_result_t result;
-
-       rdatalist = NULL;
-       result = dns_message_gettemprdatalist(message, &rdatalist);
-       if (result != ISC_R_SUCCESS)
-               return (result);
-       rdata = NULL;
-       result = dns_message_gettemprdata(message, &rdata);
-       if (result != ISC_R_SUCCESS)
-               return (result);
-       rdataset = NULL;
-       result = dns_message_gettemprdataset(message, &rdataset);
-       if (result != ISC_R_SUCCESS)
-               return (result);
-       dns_rdataset_init(rdataset);
-
-       rdatalist->type = dns_rdatatype_opt;
-       rdatalist->covers = 0;
-
-       /*
-        * Set Maximum UDP buffer size.
-        */
-       rdatalist->rdclass = udpsize;
-
-       /*
-        * Set EXTENDED-RCODE and Z to 0, DO to 1.
-        */
-       rdatalist->ttl = (version << 16);
-       rdatalist->ttl |= DNS_MESSAGEEXTFLAG_DO;
-
-       /*
-        * No EDNS options.
-        */
-       rdata->data = NULL;
-       rdata->length = 0;
-       rdata->rdclass = rdatalist->rdclass;
-       rdata->type = rdatalist->type;
-       rdata->flags = 0;
-
-       ISC_LIST_INIT(rdatalist->rdata);
-       ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
-       RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist, rdataset) == ISC_R_SUCCESS);
-
-       return (dns_message_setopt(message, rdataset));
+{
+        dns_rdataset_t *rdataset;
+        dns_rdatalist_t *rdatalist;
+        dns_rdata_t *rdata;
+        isc_result_t result;
+
+        rdatalist = NULL;
+        result = dns_message_gettemprdatalist(message, &rdatalist);
+        if (result != ISC_R_SUCCESS)
+                return (result);
+        rdata = NULL;
+        result = dns_message_gettemprdata(message, &rdata);
+        if (result != ISC_R_SUCCESS)
+                return (result);
+        rdataset = NULL;
+        result = dns_message_gettemprdataset(message, &rdataset);
+        if (result != ISC_R_SUCCESS)
+                return (result);
+        dns_rdataset_init(rdataset);
+
+        rdatalist->type = dns_rdatatype_opt;
+        rdatalist->covers = 0;
+
+        /*
+         * Set Maximum UDP buffer size.
+         */
+        rdatalist->rdclass = udpsize;
+
+        /*
+         * Set EXTENDED-RCODE and Z to 0, DO to 1.
+         */
+        rdatalist->ttl = (version << 16);
+        rdatalist->ttl |= DNS_MESSAGEEXTFLAG_DO;
+
+        /*
+         * No EDNS options.
+         */
+        rdata->data = NULL;
+        rdata->length = 0;
+        rdata->rdclass = rdatalist->rdclass;
+        rdata->type = rdatalist->type;
+        rdata->flags = 0;
+
+        ISC_LIST_INIT(rdatalist->rdata);
+        ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
+        RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist, rdataset) == ISC_R_SUCCESS);
+
+        return (dns_message_setopt(message, rdataset));
 }
 
 static inline void
 fctx_setretryinterval(fetchctx_t *fctx, unsigned int rtt) {
-       unsigned int seconds;
-       unsigned int us;
-
-       /*
-        * We retry every .5 seconds the first two times through the address
-        * list, and then we do exponential back-off.
-        */
-       if (fctx->restarts < 3)
-               us = 500000;
-       else
-               us = (500000 << (fctx->restarts - 2));
-
-       /*
-        * Double the round-trip time.
-        */
-       rtt *= 2;
-
-       /*
-        * Always wait for at least the doubled round-trip time.
-        */
-       if (us < rtt)
-               us = rtt;
-
-       /*
-        * But don't ever wait for more than 10 seconds.
-        */
-       if (us > 10000000)
-               us = 10000000;
-
-       seconds = us / 1000000;
-       us -= seconds * 1000000;
-       isc_interval_set(&fctx->interval, seconds, us * 1000);
+        unsigned int seconds;
+        unsigned int us;
+
+        /*
+         * We retry every .5 seconds the first two times through the address
+         * list, and then we do exponential back-off.
+         */
+        if (fctx->restarts < 3)
+                us = 500000;
+        else
+                us = (500000 << (fctx->restarts - 2));
+
+        /*
+         * Double the round-trip time.
+         */
+        rtt *= 2;
+
+        /*
+         * Always wait for at least the doubled round-trip time.
+         */
+        if (us < rtt)
+                us = rtt;
+
+        /*
+         * But don't ever wait for more than 10 seconds.
+         */
+        if (us > 10000000)
+                us = 10000000;
+
+        seconds = us / 1000000;
+        us -= seconds * 1000000;
+        isc_interval_set(&fctx->interval, seconds, us * 1000);
 }
 
 static isc_result_t
 fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo,
-          unsigned int options)
+           unsigned int options)
 {
-       dns_resolver_t *res;
-       isc_task_t *task;
-       isc_result_t result;
-       resquery_t *query;
-       isc_sockaddr_t addr;
-       isc_boolean_t have_addr = ISC_FALSE;
-
-       FCTXTRACE("query");
-
-       res = fctx->res;
-       task = res->buckets[fctx->bucketnum].task;
-
-       fctx_setretryinterval(fctx, addrinfo->srtt);
-       result = fctx_startidletimer(fctx);
-       if (result != ISC_R_SUCCESS)
-               return (result);
-
-       INSIST(ISC_LIST_EMPTY(fctx->validators));
-
-       dns_message_reset(fctx->rmessage, DNS_MESSAGE_INTENTPARSE);
-
-       query = isc_mem_get(res->buckets[fctx->bucketnum].mctx,
-                           sizeof(*query));
-       if (query == NULL) {
-               result = ISC_R_NOMEMORY;
-               goto stop_idle_timer;
-       }
-       query->mctx = res->buckets[fctx->bucketnum].mctx;
-       query->options = options;
-       query->attributes = 0;
-       query->sends = 0;
-       query->connects = 0;
-       /*
-        * Note that the caller MUST guarantee that 'addrinfo' will remain
-        * valid until this query is canceled.
-        */
-       query->addrinfo = addrinfo;
-       TIME_NOW(&query->start);
-
-       /*
-        * If this is a TCP query, then we need to make a socket and
-        * a dispatch for it here.  Otherwise we use the resolver's
-        * shared dispatch.
-        */
-       query->dispatchmgr = res->dispatchmgr;
-       query->dispatch = NULL;
-       query->tcpsocket = NULL;
-       if (res->view->peers != NULL) {
-               dns_peer_t *peer = NULL;
-               isc_netaddr_t dstip;
-               isc_netaddr_fromsockaddr(&dstip, &addrinfo->sockaddr);
-               result = dns_peerlist_peerbyaddr(res->view->peers,
-                                                &dstip, &peer);
-               if (result == ISC_R_SUCCESS) {
-                       result = dns_peer_getquerysource(peer, &addr);
-                       if (result == ISC_R_SUCCESS)
-                               have_addr = ISC_TRUE;
-               }
-       }
-
-       if ((query->options & DNS_FETCHOPT_TCP) != 0) {
-               int pf;
-
-               pf = isc_sockaddr_pf(&addrinfo->sockaddr);
-               if (!have_addr) {
-                       switch (pf) {
-                       case PF_INET:
-                               result =
-                                 dns_dispatch_getlocaladdress(res->dispatchv4,
-                                                              &addr);
-                               break;
-                       case PF_INET6:
-                               result =
-                                 dns_dispatch_getlocaladdress(res->dispatchv6,
-                                                              &addr);
-                               break;
-                       default:
-                               result = ISC_R_NOTIMPLEMENTED;
-                               break;
-                       }
-                       if (result != ISC_R_SUCCESS)
-                               goto cleanup_query;
-               }
-               isc_sockaddr_setport(&addr, 0);
-
-               result = isc_socket_create(res->socketmgr, pf,
-                                          isc_sockettype_tcp,
-                                          &query->tcpsocket);
-               if (result != ISC_R_SUCCESS)
-                       goto cleanup_query;
+        dns_resolver_t *res;
+        isc_task_t *task;
+        isc_result_t result;
+        resquery_t *query;
+        isc_sockaddr_t addr;
+        isc_boolean_t have_addr = ISC_FALSE;
+
+        FCTXTRACE("query");
+
+        res = fctx->res;
+        task = res->buckets[fctx->bucketnum].task;
+
+        fctx_setretryinterval(fctx, addrinfo->srtt);
+        result = fctx_startidletimer(fctx);
+        if (result != ISC_R_SUCCESS)
+                return (result);
+
+        INSIST(ISC_LIST_EMPTY(fctx->validators));
+
+        dns_message_reset(fctx->rmessage, DNS_MESSAGE_INTENTPARSE);
+
+        query = isc_mem_get(res->buckets[fctx->bucketnum].mctx,
+                            sizeof(*query));
+        if (query == NULL) {
+                result = ISC_R_NOMEMORY;
+                goto stop_idle_timer;
+        }
+        query->mctx = res->buckets[fctx->bucketnum].mctx;
+        query->options = options;
+        query->attributes = 0;
+        query->sends = 0;
+        query->connects = 0;
+        /*
+         * Note that the caller MUST guarantee that 'addrinfo' will remain
+         * valid until this query is canceled.
+         */
+        query->addrinfo = addrinfo;
+        TIME_NOW(&query->start);
+
+        /*
+         * If this is a TCP query, then we need to make a socket and
+         * a dispatch for it here.  Otherwise we use the resolver's
+         * shared dispatch.
+         */
+        query->dispatchmgr = res->dispatchmgr;
+        query->dispatch = NULL;
+        query->tcpsocket = NULL;
+        if (res->view->peers != NULL) {
+                dns_peer_t *peer = NULL;
+                isc_netaddr_t dstip;
+                isc_netaddr_fromsockaddr(&dstip, &addrinfo->sockaddr);
+                result = dns_peerlist_peerbyaddr(res->view->peers,
+                                                 &dstip, &peer);
+                if (result == ISC_R_SUCCESS) {
+                        result = dns_peer_getquerysource(peer, &addr);
+                        if (result == ISC_R_SUCCESS)
+                                have_addr = ISC_TRUE;
+                }
+        }
+
+        if ((query->options & DNS_FETCHOPT_TCP) != 0) {
+                int pf;
+
+                pf = isc_sockaddr_pf(&addrinfo->sockaddr);
+                if (!have_addr) {
+                        switch (pf) {
+                        case PF_INET:
+                                result =
+                                  dns_dispatch_getlocaladdress(res->dispatchv4,
+                                                               &addr);
+                                break;
+                        case PF_INET6:
+                                result =
+                                  dns_dispatch_getlocaladdress(res->dispatchv6,
+                                                               &addr);
+                                break;
+                        default:
+                                result = ISC_R_NOTIMPLEMENTED;
+                                break;
+                        }
+                        if (result != ISC_R_SUCCESS)
+                                goto cleanup_query;
+                }
+                isc_sockaddr_setport(&addr, 0);
+
+                result = isc_socket_create(res->socketmgr, pf,
+                                           isc_sockettype_tcp,
+                                           &query->tcpsocket);
+                if (result != ISC_R_SUCCESS)
+                        goto cleanup_query;
 
 #ifndef BROKEN_TCP_BIND_BEFORE_CONNECT
-               result = isc_socket_bind(query->tcpsocket, &addr);
-               if (result != ISC_R_SUCCESS)
-                       goto cleanup_socket;
+                result = isc_socket_bind(query->tcpsocket, &addr);
+                if (result != ISC_R_SUCCESS)
+                        goto cleanup_socket;
 #endif
 
-               /*
-                * A dispatch will be created once the connect succeeds.
-                */
-       } else {
-               if (have_addr) {
-                       unsigned int attrs, attrmask;
-                       attrs = DNS_DISPATCHATTR_UDP;
-                       switch (isc_sockaddr_pf(&addr)) {
-                       case AF_INET:
-                               attrs |= DNS_DISPATCHATTR_IPV4;
-                               break;
-                       case AF_INET6:
-                               attrs |= DNS_DISPATCHATTR_IPV6;
-                               break;
-                       default:
-                               result = ISC_R_NOTIMPLEMENTED;
-                               goto cleanup_query;
-                       }
-                       attrmask = DNS_DISPATCHATTR_UDP;
-                       attrmask |= DNS_DISPATCHATTR_TCP;
-                       attrmask |= DNS_DISPATCHATTR_IPV4;
-                       attrmask |= DNS_DISPATCHATTR_IPV6;
-                       result = dns_dispatch_getudp(res->dispatchmgr,
-                                                    res->socketmgr,
-                                                    res->taskmgr, &addr,
-                                                    4096, 1000, 32768, 16411,
-                                                    16433, attrs, attrmask,
-                                                    &query->dispatch);
-                       if (result != ISC_R_SUCCESS)
-                               goto cleanup_query;
-               } else {
-                       int did = 0;
-                       isc_uint32_t val;
-
-                       if (res->ndisps > 0) {
-                               isc_random_get(&val);
-                               did = val % res->ndisps;
-                       }
-                       switch (isc_sockaddr_pf(&addrinfo->sockaddr)) {
-                       case PF_INET:
-                               if (res->dispatchv4pool != NULL) {
-                                       RES_LOCK(&res->poollock,
-                                                isc_rwlocktype_read);
-                                       dns_dispatch_attach(res->dispatchv4pool[did],
-                                                           &query->dispatch);
-                                       RES_UNLOCK(&res->poollock,
-                                                  isc_rwlocktype_read);
-                               } else {
-                                       dns_dispatch_attach(res->dispatchv4,
-                                                           &query->dispatch);
-                               }
-                               break;
-                       case PF_INET6:
-                               if (res->dispatchv6pool != NULL) {
-                                       RES_LOCK(&res->poollock,
-                                                isc_rwlocktype_read);
-                                       dns_dispatch_attach(res->dispatchv6pool[did],
-                                                           &query->dispatch);
-                                       RES_UNLOCK(&res->poollock,
-                                                  isc_rwlocktype_read);
-                               } else {
-                                       dns_dispatch_attach(res->dispatchv6,
-                                                           &query->dispatch);
-                               }
-                               break;
-                       default:
-                               result = ISC_R_NOTIMPLEMENTED;
-                               goto cleanup_query;
-                       }
-               }
-               /*
-                * We should always have a valid dispatcher here.  If we
-                * don't support a protocol family, then its dispatcher
-                * will be NULL, but we shouldn't be finding addresses for
-                * protocol types we don't support, so the dispatcher
-                * we found should never be NULL.
-                */
-               INSIST(query->dispatch != NULL);
-       }
-
-       query->dispentry = NULL;
-       query->fctx = fctx;
-       query->tsig = NULL;
-       query->tsigkey = NULL;
-       ISC_LINK_INIT(query, link);
-       query->magic = QUERY_MAGIC;
-
-       if ((query->options & DNS_FETCHOPT_TCP) != 0) {
-               /*
-                * Connect to the remote server.
-                *
-                * XXXRTH  Should we attach to the socket?
-                */
-               result = isc_socket_connect(query->tcpsocket,
-                                           &addrinfo->sockaddr, task,
-                                           resquery_connected, query);
-               if (result != ISC_R_SUCCESS)
-                       goto cleanup_socket;
-               query->connects++;
-               QTRACE("connecting via TCP");
-       } else {
-               result = resquery_send(query);
-               if (result != ISC_R_SUCCESS)
-                       goto cleanup_dispatch;
-       }
-
-       ISC_LIST_APPEND(fctx->queries, query, link);
-       query->fctx->nqueries++;
-
-       return (ISC_R_SUCCESS);
+                /*
+                 * A dispatch will be created once the connect succeeds.
+                 */
+        } else {
+                if (have_addr) {
+                        unsigned int attrs, attrmask;
+                        attrs = DNS_DISPATCHATTR_UDP;
+                        switch (isc_sockaddr_pf(&addr)) {
+                        case AF_INET:
+                                attrs |= DNS_DISPATCHATTR_IPV4;
+                                break;
+                        case AF_INET6:
+                                attrs |= DNS_DISPATCHATTR_IPV6;
+                                break;
+                        default:
+                                result = ISC_R_NOTIMPLEMENTED;
+                                goto cleanup_query;
+                        }
+                        attrmask = DNS_DISPATCHATTR_UDP;
+                        attrmask |= DNS_DISPATCHATTR_TCP;
+                        attrmask |= DNS_DISPATCHATTR_IPV4;
+                        attrmask |= DNS_DISPATCHATTR_IPV6;
+                        result = dns_dispatch_getudp(res->dispatchmgr,
+                                                     res->socketmgr,
+                                                     res->taskmgr, &addr,
+                                                     4096, 1000, 32768, 16411,
+                                                     16433, attrs, attrmask,
+                                                     &query->dispatch);
+                        if (result != ISC_R_SUCCESS)
+                                goto cleanup_query;
+                } else {
+                        int did = 0;
+                        isc_uint32_t val;
+
+                        if (res->ndisps > 0) {
+                                isc_random_get(&val);
+                                did = val % res->ndisps;
+                        }
+                        switch (isc_sockaddr_pf(&addrinfo->sockaddr)) {
+                        case PF_INET:
+                                if (res->dispatchv4pool != NULL) {
+                                        RES_LOCK(&res->poollock,
+                                                 isc_rwlocktype_read);
+                                        dns_dispatch_attach(res->dispatchv4pool[did],
+                                                            &query->dispatch);
+                                        RES_UNLOCK(&res->poollock,
+                                                   isc_rwlocktype_read);
+                                } else {
+                                        dns_dispatch_attach(res->dispatchv4,
+                                                            &query->dispatch);
+                                }
+                                break;
+                        case PF_INET6:
+                                if (res->dispatchv6pool != NULL) {
+                                        RES_LOCK(&res->poollock,
+                                                 isc_rwlocktype_read);
+                                        dns_dispatch_attach(res->dispatchv6pool[did],
+                                                            &query->dispatch);
+                                        RES_UNLOCK(&res->poollock,
+                                                   isc_rwlocktype_read);
+                                } else {
+                                        dns_dispatch_attach(res->dispatchv6,
+                                                            &query->dispatch);
+                                }
+                                break;
+                        default:
+                                result = ISC_R_NOTIMPLEMENTED;
+                                goto cleanup_query;
+                        }
+                }
+                /*
+                 * We should always have a valid dispatcher here.  If we
+                 * don't support a protocol family, then its dispatcher
+                 * will be NULL, but we shouldn't be finding addresses for
+                 * protocol types we don't support, so the dispatcher
+                 * we found should never be NULL.
+                 */
+                INSIST(query->dispatch != NULL);
+        }
+
+        query->dispentry = NULL;
+        query->fctx = fctx;
+        query->tsig = NULL;
+        query->tsigkey = NULL;
+        ISC_LINK_INIT(query, link);
+        query->magic = QUERY_MAGIC;
+
+        if ((query->options & DNS_FETCHOPT_TCP) != 0) {
+                /*
+                 * Connect to the remote server.
+                 *
+                 * XXXRTH  Should we attach to the socket?
+                 */
+                result = isc_socket_connect(query->tcpsocket,
+                                            &addrinfo->sockaddr, task,
+                                            resquery_connected, query);
+                if (result != ISC_R_SUCCESS)
+                        goto cleanup_socket;
+                query->connects++;
+                QTRACE("connecting via TCP");
+        } else {
+                result = resquery_send(query);
+                if (result != ISC_R_SUCCESS)
+                        goto cleanup_dispatch;
+        }
+
+        ISC_LIST_APPEND(fctx->queries, query, link);
+        query->fctx->nqueries++;
+
+        return (ISC_R_SUCCESS);
 
  cleanup_socket:
-       isc_socket_detach(&query->tcpsocket);
+        isc_socket_detach(&query->tcpsocket);
 
  cleanup_dispatch:
-       if (query->dispatch != NULL)
-               dns_dispatch_detach(&query->dispatch);
+        if (query->dispatch != NULL)
+                dns_dispatch_detach(&query->dispatch);
 
  cleanup_query:
-       query->magic = 0;
-       isc_mem_put(res->buckets[fctx->bucketnum].mctx,
-                   query, sizeof(*query));
+        query->magic = 0;
+        isc_mem_put(res->buckets[fctx->bucketnum].mctx,
+                    query, sizeof(*query));
 
  stop_idle_timer:
-       RUNTIME_CHECK(fctx_stopidletimer(fctx) == ISC_R_SUCCESS);
+        RUNTIME_CHECK(fctx_stopidletimer(fctx) == ISC_R_SUCCESS);
 
-       return (result);
+        return (result);
 }
 
 static isc_boolean_t
 triededns(fetchctx_t *fctx, isc_sockaddr_t *address) {
-       isc_sockaddr_t *sa;
+        isc_sockaddr_t *sa;
 
-       for (sa = ISC_LIST_HEAD(fctx->edns);
-            sa != NULL;
-            sa = ISC_LIST_NEXT(sa, link)) {
-               if (isc_sockaddr_equal(sa, address))
-                       return (ISC_TRUE);
-       }
+        for (sa = ISC_LIST_HEAD(fctx->edns);
+             sa != NULL;
+             sa = ISC_LIST_NEXT(sa, link)) {
+                if (isc_sockaddr_equal(sa, address))
+                        return (ISC_TRUE);
+        }
 
-       return (ISC_FALSE);
+        return (ISC_FALSE);
 }
 
 static void
 add_triededns(fetchctx_t *fctx, isc_sockaddr_t *address) {
-       isc_sockaddr_t *sa;
+        isc_sockaddr_t *sa;
 
-       if (triededns(fctx, address))
-               return;
+        if (triededns(fctx, address))
+                return;
 
-       sa = isc_mem_get(fctx->res->buckets[fctx->bucketnum].mctx,
-                        sizeof(*sa));
-       if (sa == NULL)
-               return;
+        sa = isc_mem_get(fctx->res->buckets[fctx->bucketnum].mctx,
+                         sizeof(*sa));
+        if (sa == NULL)
+                return;
 
-       *sa = *address;
-       ISC_LIST_INITANDAPPEND(fctx->edns, sa, link);
+        *sa = *address;
+        ISC_LIST_INITANDAPPEND(fctx->edns, sa, link);
 }
 
 static isc_boolean_t
 triededns512(fetchctx_t *fctx, isc_sockaddr_t *address) {
-       isc_sockaddr_t *sa;
+        isc_sockaddr_t *sa;
 
-       for (sa = ISC_LIST_HEAD(fctx->edns512);
-            sa != NULL;
-            sa = ISC_LIST_NEXT(sa, link)) {
-               if (isc_sockaddr_equal(sa, address))
-                       return (ISC_TRUE);
-       }
+        for (sa = ISC_LIST_HEAD(fctx->edns512);
+             sa != NULL;
+             sa = ISC_LIST_NEXT(sa, link)) {
+                if (isc_sockaddr_equal(sa, address))
+                        return (ISC_TRUE);
+        }
 
-       return (ISC_FALSE);
+        return (ISC_FALSE);
 }
 
 static void
 add_triededns512(fetchctx_t *fctx, isc_sockaddr_t *address) {
-       isc_sockaddr_t *sa;
+        isc_sockaddr_t *sa;
 
-       if (triededns512(fctx, address))
-               return;
+        if (triededns512(fctx, address))
+                return;
 
-       sa = isc_mem_get(fctx->res->buckets[fctx->bucketnum].mctx,
-                        sizeof(*sa));
-       if (sa == NULL)
-               return;
+        sa = isc_mem_get(fctx->res->buckets[fctx->bucketnum].mctx,
+                         sizeof(*sa));
+        if (sa == NULL)
+                return;
 
-       *sa = *address;
-       ISC_LIST_INITANDAPPEND(fctx->edns512, sa, link);
+        *sa = *address;
+        ISC_LIST_INITANDAPPEND(fctx->edns512, sa, link);
 }
 
 static inline void
 log_edns(fetchctx_t *fctx) {
-       char domainbuf[DNS_NAME_FORMATSIZE];    
-       
-       dns_name_format(&fctx->domain, domainbuf, sizeof(domainbuf));
-       isc_log_write(dns_lctx, DNS_LOGCATEGORY_EDNS_DISABLED,
-                     DNS_LOGMODULE_RESOLVER, ISC_LOG_INFO,
-                     "too many timeouts resolving '%s' (in '%s'?): "
-                     "disabling EDNS", fctx->info, domainbuf);
+        char domainbuf[DNS_NAME_FORMATSIZE];
+
+        dns_name_format(&fctx->domain, domainbuf, sizeof(domainbuf));
+        isc_log_write(dns_lctx, DNS_LOGCATEGORY_EDNS_DISABLED,
+                      DNS_LOGMODULE_RESOLVER, ISC_LOG_INFO,
+                      "too many timeouts resolving '%s' (in '%s'?): "
+                      "disabling EDNS", fctx->info, domainbuf);
 }
 
 static isc_result_t
 resquery_send(resquery_t *query) {
-       fetchctx_t *fctx;
-       isc_result_t result;
-       dns_name_t *qname = NULL;
-       dns_rdataset_t *qrdataset = NULL;
-       isc_region_t r;
-       dns_resolver_t *res;
-       isc_task_t *task;
-       isc_socket_t *socket;
-       isc_buffer_t tcpbuffer;
-       isc_sockaddr_t *address;
-       isc_buffer_t *buffer;
-       isc_netaddr_t ipaddr;
-       dns_tsigkey_t *tsigkey = NULL;
-       dns_peer_t *peer = NULL;
-       isc_boolean_t useedns;
-       dns_compress_t cctx;
-       isc_boolean_t cleanup_cctx = ISC_FALSE;
-       isc_boolean_t secure_domain;
-
-       fctx = query->fctx;
-       QTRACE("send");
-
-       res = fctx->res;
-       task = res->buckets[fctx->bucketnum].task;
-       address = NULL;
-
-       if ((query->options & DNS_FETCHOPT_TCP) != 0) {
-               /*
-                * Reserve space for the TCP message length.
-                */
-               isc_buffer_init(&tcpbuffer, query->data, sizeof(query->data));
-               isc_buffer_init(&query->buffer, query->data + 2,
-                               sizeof(query->data) - 2);
-               buffer = &tcpbuffer;
-       } else {
-               isc_buffer_init(&query->buffer, query->data,
-                               sizeof(query->data));
-               buffer = &query->buffer;
-       }
-
-       result = dns_message_gettempname(fctx->qmessage, &qname);
-       if (result != ISC_R_SUCCESS)
-               goto cleanup_temps;
-       result = dns_message_gettemprdataset(fctx->qmessage, &qrdataset);
-       if (result != ISC_R_SUCCESS)
-               goto cleanup_temps;
-
-       /*
-        * Get a query id from the dispatch.
-        */
-       result = dns_dispatch_addresponse(query->dispatch,
-                                         &query->addrinfo->sockaddr,
-                                         task,
-                                         resquery_response,
-                                         query,
-                                         &query->id,
-                                         &query->dispentry);
-       if (result != ISC_R_SUCCESS)
-               goto cleanup_temps;
-
-       fctx->qmessage->opcode = dns_opcode_query;
-
-       /*
-        * Set up question.
-        */
-       dns_name_init(qname, NULL);
-       dns_name_clone(&fctx->name, qname);
-       dns_rdataset_init(qrdataset);
-       dns_rdataset_makequestion(qrdataset, res->rdclass, fctx->type);
-       ISC_LIST_APPEND(qname->list, qrdataset, link);
-       dns_message_addname(fctx->qmessage, qname, DNS_SECTION_QUESTION);
-       qname = NULL;
-       qrdataset = NULL;
-
-       /*
-        * Set RD if the client has requested that we do a recursive query,
-        * or if we're sending to a forwarder.
-        */
-       if ((query->options & DNS_FETCHOPT_RECURSIVE) != 0 ||
-           ISFORWARDER(query->addrinfo))
-               fctx->qmessage->flags |= DNS_MESSAGEFLAG_RD;
-
-       /*
-        * Set CD if the client says don't validate or the question is
-        * under a secure entry point.
-        */
-       if ((query->options & DNS_FETCHOPT_NOVALIDATE) != 0) {
-               fctx->qmessage->flags |= DNS_MESSAGEFLAG_CD;
-       } else if (res->view->enablevalidation) {
-               result = dns_keytable_issecuredomain(res->view->secroots,
-                                                    &fctx->name,
-                                                    &secure_domain);
-               if (result != ISC_R_SUCCESS)
-                       secure_domain = ISC_FALSE;
-               if (res->view->dlv != NULL)
-                       secure_domain = ISC_TRUE;
-               if (secure_domain)
-                       fctx->qmessage->flags |= DNS_MESSAGEFLAG_CD;
-       }
-
-       /*
-        * We don't have to set opcode because it defaults to query.
-        */
-       fctx->qmessage->id = query->id;
-
-       /*
-        * Convert the question to wire format.
-        */
-       result = dns_compress_init(&cctx, -1, fctx->res->mctx);
-       if (result != ISC_R_SUCCESS)
-               goto cleanup_message;
-       cleanup_cctx = ISC_TRUE;
-
-       result = dns_message_renderbegin(fctx->qmessage, &cctx,
-                                        &query->buffer);
-       if (result != ISC_R_SUCCESS)
-               goto cleanup_message;
-
-       result = dns_message_rendersection(fctx->qmessage,
-                                          DNS_SECTION_QUESTION, 0);
-       if (result != ISC_R_SUCCESS)
-               goto cleanup_message;
-
-       peer = NULL;
-       isc_netaddr_fromsockaddr(&ipaddr, &query->addrinfo->sockaddr);
-       (void) dns_peerlist_peerbyaddr(fctx->res->view->peers, &ipaddr, &peer);
-
-       /*
-        * The ADB does not know about servers with "edns no".  Check this,
-        * and then inform the ADB for future use.
-        */
-       if ((query->addrinfo->flags & DNS_FETCHOPT_NOEDNS0) == 0 &&
-           peer != NULL &&
-           dns_peer_getsupportedns(peer, &useedns) == ISC_R_SUCCESS &&
-           !useedns)
-       {
-               query->options |= DNS_FETCHOPT_NOEDNS0;
-               dns_adb_changeflags(fctx->adb,
-                                   query->addrinfo,
-                                   DNS_FETCHOPT_NOEDNS0,
-                                   DNS_FETCHOPT_NOEDNS0);
-       }
-
-       /*
-        * Use EDNS0, unless the caller doesn't want it, or we know that
-        * the remote server doesn't like it.
-        */
-
-       if ((triededns512(fctx, &query->addrinfo->sockaddr) ||
-            fctx->timeouts >= (MAX_EDNS0_TIMEOUTS * 2)) &&
-           (query->options & DNS_FETCHOPT_NOEDNS0) == 0) {
-               query->options |= DNS_FETCHOPT_NOEDNS0;
-               log_edns(fctx);
-       } else if ((triededns(fctx, &query->addrinfo->sockaddr) ||
-                   fctx->timeouts >= MAX_EDNS0_TIMEOUTS) &&
-                  (query->options & DNS_FETCHOPT_NOEDNS0) == 0) {
-               query->options |= DNS_FETCHOPT_EDNS512;
-               FCTXTRACE("too many timeouts, setting EDNS size to 512");
-       }
-
-       if ((query->options & DNS_FETCHOPT_NOEDNS0) == 0) {
-               if ((query->addrinfo->flags & DNS_FETCHOPT_NOEDNS0) == 0) {
-                       unsigned int version = 0;       /* Default version. */
-                       unsigned int flags;
-                       isc_uint16_t udpsize = res->udpsize;
-
-                       flags = query->addrinfo->flags;
-                       if ((flags & DNS_FETCHOPT_EDNSVERSIONSET) != 0) {
-                               version = flags & DNS_FETCHOPT_EDNSVERSIONMASK;
-                               version >>= DNS_FETCHOPT_EDNSVERSIONSHIFT;
-                       }
-                       if ((query->options & DNS_FETCHOPT_EDNS512) != 0)
-                               udpsize = 512;
-                       else if (peer != NULL)
-                               (void)dns_peer_getudpsize(peer, &udpsize);
-                       result = fctx_addopt(fctx->qmessage, version, udpsize);
-                       if (result != ISC_R_SUCCESS) {
-                               /*
-                                * We couldn't add the OPT, but we'll press on.
-                                * We're not using EDNS0, so set the NOEDNS0
-                                * bit.
-                                */
-                               query->options |= DNS_FETCHOPT_NOEDNS0;
-                       }
-               } else {
-                       /*
-                        * We know this server doesn't like EDNS0, so we
-                        * won't use it.  Set the NOEDNS0 bit since we're
-                        * not using EDNS0.
-                        */
-                       query->options |= DNS_FETCHOPT_NOEDNS0;
-               }
-       }
-
-       /*
-        * If we need EDNS0 to do this query and aren't using it, we lose.
-        */
-       if (NEEDEDNS0(fctx) && (query->options & DNS_FETCHOPT_NOEDNS0) != 0) {
-               result = DNS_R_SERVFAIL;
-               goto cleanup_message;
-       }
-
-       if ((query->options & DNS_FETCHOPT_NOEDNS0) == 0)
-               add_triededns(fctx, &query->addrinfo->sockaddr);
-
-       if ((query->options & DNS_FETCHOPT_EDNS512) != 0)
-               add_triededns512(fctx, &query->addrinfo->sockaddr);
-
-       /*
-        * Clear CD if EDNS is not in use.
-        */
-       if ((query->options & DNS_FETCHOPT_NOEDNS0) != 0)
-               fctx->qmessage->flags &= ~DNS_MESSAGEFLAG_CD;
-
-       /*
-        * Add TSIG record tailored to the current recipient.
-        */
-       result = dns_view_getpeertsig(fctx->res->view, &ipaddr, &tsigkey);
-       if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND)
-               goto cleanup_message;
-
-       if (tsigkey != NULL) {
-               result = dns_message_settsigkey(fctx->qmessage, tsigkey);
-               dns_tsigkey_detach(&tsigkey);
-               if (result != ISC_R_SUCCESS)
-                       goto cleanup_message;
-       }
-
-       result = dns_message_rendersection(fctx->qmessage,
-                                          DNS_SECTION_ADDITIONAL, 0);
-       if (result != ISC_R_SUCCESS)
-               goto cleanup_message;
-
-       result = dns_message_renderend(fctx->qmessage);
-       if (result != ISC_R_SUCCESS)
-               goto cleanup_message;
-
-       dns_compress_invalidate(&cctx);
-       cleanup_cctx = ISC_FALSE;
-
-       if (dns_message_gettsigkey(fctx->qmessage) != NULL) {
-               dns_tsigkey_attach(dns_message_gettsigkey(fctx->qmessage),
-                                  &query->tsigkey);
-               result = dns_message_getquerytsig(fctx->qmessage,
-                                                 fctx->res->mctx,
-                                                 &query->tsig);
-               if (result != ISC_R_SUCCESS)
-                       goto cleanup_message;
-       }
-
-       /*
-        * If using TCP, write the length of the message at the beginning
-        * of the buffer.
-        */
-       if ((query->options & DNS_FETCHOPT_TCP) != 0) {
-               isc_buffer_usedregion(&query->buffer, &r);
-               isc_buffer_putuint16(&tcpbuffer, (isc_uint16_t)r.length);
-               isc_buffer_add(&tcpbuffer, r.length);
-       }
-
-       /*
-        * We're now done with the query message.
-        */
-       dns_message_reset(fctx->qmessage, DNS_MESSAGE_INTENTRENDER);
-
-       socket = dns_dispatch_getsocket(query->dispatch);
-       /*
-        * Send the query!
-        */
-       if ((query->options & DNS_FETCHOPT_TCP) == 0)
-               address = &query->addrinfo->sockaddr;
-       isc_buffer_usedregion(buffer, &r);
-
-       /*
-        * XXXRTH  Make sure we don't send to ourselves!  We should probably
-        *         prune out these addresses when we get them from the ADB.
-        */
-       result = isc_socket_sendto(socket, &r, task, resquery_senddone,
-                                  query, address, NULL);
-       if (result != ISC_R_SUCCESS)
-               goto cleanup_message;
-       query->sends++;
-       QTRACE("sent");
-
-       return (ISC_R_SUCCESS);
+        fetchctx_t *fctx;
+        isc_result_t result;
+        dns_name_t *qname = NULL;
+        dns_rdataset_t *qrdataset = NULL;
+        isc_region_t r;
+        dns_resolver_t *res;
+        isc_task_t *task;
+        isc_socket_t *socket;
+        isc_buffer_t tcpbuffer;
+        isc_sockaddr_t *address;
+        isc_buffer_t *buffer;
+        isc_netaddr_t ipaddr;
+        dns_tsigkey_t *tsigkey = NULL;
+        dns_peer_t *peer = NULL;
+        isc_boolean_t useedns;
+        dns_compress_t cctx;
+        isc_boolean_t cleanup_cctx = ISC_FALSE;
+        isc_boolean_t secure_domain;
+
+        fctx = query->fctx;
+        QTRACE("send");
+
+        res = fctx->res;
+        task = res->buckets[fctx->bucketnum].task;
+        address = NULL;
+
+        if ((query->options & DNS_FETCHOPT_TCP) != 0) {
+                /*
+                 * Reserve space for the TCP message length.
+                 */
+                isc_buffer_init(&tcpbuffer, query->data, sizeof(query->data));
+                isc_buffer_init(&query->buffer, query->data + 2,
+                                sizeof(query->data) - 2);
+                buffer = &tcpbuffer;
+        } else {
+                isc_buffer_init(&query->buffer, query->data,
+                                sizeof(query->data));
+                buffer = &query->buffer;
+        }
+
+        result = dns_message_gettempname(fctx->qmessage, &qname);
+        if (result != ISC_R_SUCCESS)
+                goto cleanup_temps;
+        result = dns_message_gettemprdataset(fctx->qmessage, &qrdataset);
+        if (result != ISC_R_SUCCESS)
+                goto cleanup_temps;
+
+        /*
+         * Get a query id from the dispatch.
+         */
+        result = dns_dispatch_addresponse(query->dispatch,
+                                          &query->addrinfo->sockaddr,
+                                          task,
+                                          resquery_response,
+                                          query,
+                                          &query->id,
+                                          &query->dispentry);
+        if (result != ISC_R_SUCCESS)
+                goto cleanup_temps;
+
+        fctx->qmessage->opcode = dns_opcode_query;
+
+        /*
+         * Set up question.
+         */
+        dns_name_init(qname, NULL);
+        dns_name_clone(&fctx->name, qname);
+        dns_rdataset_init(qrdataset);
+        dns_rdataset_makequestion(qrdataset, res->rdclass, fctx->type);
+        ISC_LIST_APPEND(qname->list, qrdataset, link);
+        dns_message_addname(fctx->qmessage, qname, DNS_SECTION_QUESTION);
+        qname = NULL;
+        qrdataset = NULL;
+
+        /*
+         * Set RD if the client has requested that we do a recursive query,
+         * or if we're sending to a forwarder.
+         */
+        if ((query->options & DNS_FETCHOPT_RECURSIVE) != 0 ||
+            ISFORWARDER(query->addrinfo))
+                fctx->qmessage->flags |= DNS_MESSAGEFLAG_RD;
+
+        /*
+         * Set CD if the client says don't validate or the question is
+         * under a secure entry point.
+         */
+        if ((query->options & DNS_FETCHOPT_NOVALIDATE) != 0) {
+                fctx->qmessage->flags |= DNS_MESSAGEFLAG_CD;
+        } else if (res->view->enablevalidation) {
+                result = dns_keytable_issecuredomain(res->view->secroots,
+                                                     &fctx->name,
+                                                     &secure_domain);
+                if (result != ISC_R_SUCCESS)
+                        secure_domain = ISC_FALSE;
+                if (res->view->dlv != NULL)
+                        secure_domain = ISC_TRUE;
+                if (secure_domain)
+                        fctx->qmessage->flags |= DNS_MESSAGEFLAG_CD;
+        }
+
+        /*
+         * We don't have to set opcode because it defaults to query.
+         */
+        fctx->qmessage->id = query->id;
+
+        /*
+         * Convert the question to wire format.
+         */
+        result = dns_compress_init(&cctx, -1, fctx->res->mctx);
+        if (result != ISC_R_SUCCESS)
+                goto cleanup_message;
+        cleanup_cctx = ISC_TRUE;
+
+        result = dns_message_renderbegin(fctx->qmessage, &cctx,
+                                         &query->buffer);
+        if (result != ISC_R_SUCCESS)
+                goto cleanup_message;
+
+        result = dns_message_rendersection(fctx->qmessage,
+                                           DNS_SECTION_QUESTION, 0);
+        if (result != ISC_R_SUCCESS)
+                goto cleanup_message;
+
+        peer = NULL;
+        isc_netaddr_fromsockaddr(&ipaddr, &query->addrinfo->sockaddr);
+        (void) dns_peerlist_peerbyaddr(fctx->res->view->peers, &ipaddr, &peer);
+
+        /*
+         * The ADB does not know about servers with "edns no".  Check this,
+         * and then inform the ADB for future use.
+         */
+        if ((query->addrinfo->flags & DNS_FETCHOPT_NOEDNS0) == 0 &&
+            peer != NULL &&
+            dns_peer_getsupportedns(peer, &useedns) == ISC_R_SUCCESS &&
+            !useedns)
+        {
+                query->options |= DNS_FETCHOPT_NOEDNS0;
+                dns_adb_changeflags(fctx->adb,
+                                    query->addrinfo,
+                                    DNS_FETCHOPT_NOEDNS0,
+                                    DNS_FETCHOPT_NOEDNS0);
+        }
+
+        /*
+         * Use EDNS0, unless the caller doesn't want it, or we know that
+         * the remote server doesn't like it.
+         */
+
+        if ((triededns512(fctx, &query->addrinfo->sockaddr) ||
+             fctx->timeouts >= (MAX_EDNS0_TIMEOUTS * 2)) &&
+            (query->options & DNS_FETCHOPT_NOEDNS0) == 0) {
+                query->options |= DNS_FETCHOPT_NOEDNS0;
+                log_edns(fctx);
+        } else if ((triededns(fctx, &query->addrinfo->sockaddr) ||
+                    fctx->timeouts >= MAX_EDNS0_TIMEOUTS) &&
+                   (query->options & DNS_FETCHOPT_NOEDNS0) == 0) {
+                query->options |= DNS_FETCHOPT_EDNS512;
+                FCTXTRACE("too many timeouts, setting EDNS size to 512");
+        }
+
+        if ((query->options & DNS_FETCHOPT_NOEDNS0) == 0) {
+                if ((query->addrinfo->flags & DNS_FETCHOPT_NOEDNS0) == 0) {
+                        unsigned int version = 0;       /* Default version. */
+                        unsigned int flags;
+                        isc_uint16_t udpsize = res->udpsize;
+
+                        flags = query->addrinfo->flags;
+                        if ((flags & DNS_FETCHOPT_EDNSVERSIONSET) != 0) {
+                                version = flags & DNS_FETCHOPT_EDNSVERSIONMASK;
+                                version >>= DNS_FETCHOPT_EDNSVERSIONSHIFT;
+                        }
+                        if ((query->options & DNS_FETCHOPT_EDNS512) != 0)
+                                udpsize = 512;
+                        else if (peer != NULL)
+                                (void)dns_peer_getudpsize(peer, &udpsize);
+                        result = fctx_addopt(fctx->qmessage, version, udpsize);
+                        if (result != ISC_R_SUCCESS) {
+                                /*
+                                 * We couldn't add the OPT, but we'll press on.
+                                 * We're not using EDNS0, so set the NOEDNS0
+                                 * bit.
+                                 */
+                                query->options |= DNS_FETCHOPT_NOEDNS0;
+                        }
+                } else {
+                        /*
+                         * We know this server doesn't like EDNS0, so we
+                         * won't use it.  Set the NOEDNS0 bit since we're
+                         * not using EDNS0.
+                         */
+                        query->options |= DNS_FETCHOPT_NOEDNS0;
+                }
+        }
+
+        /*
+         * If we need EDNS0 to do this query and aren't using it, we lose.
+         */
+        if (NEEDEDNS0(fctx) && (query->options & DNS_FETCHOPT_NOEDNS0) != 0) {
+                result = DNS_R_SERVFAIL;
+                goto cleanup_message;
+        }
+
+        if ((query->options & DNS_FETCHOPT_NOEDNS0) == 0)
+                add_triededns(fctx, &query->addrinfo->sockaddr);
+
+        if ((query->options & DNS_FETCHOPT_EDNS512) != 0)
+                add_triededns512(fctx, &query->addrinfo->sockaddr);
+
+        /*
+         * Clear CD if EDNS is not in use.
+         */
+        if ((query->options & DNS_FETCHOPT_NOEDNS0) != 0)
+                fctx->qmessage->flags &= ~DNS_MESSAGEFLAG_CD;
+
+        /*
+         * Add TSIG record tailored to the current recipient.
+         */
+        result = dns_view_getpeertsig(fctx->res->view, &ipaddr, &tsigkey);
+        if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND)
+                goto cleanup_message;
+
+        if (tsigkey != NULL) {
+                result = dns_message_settsigkey(fctx->qmessage, tsigkey);
+                dns_tsigkey_detach(&tsigkey);
+                if (result != ISC_R_SUCCESS)
+                        goto cleanup_message;
+        }
+
+        result = dns_message_rendersection(fctx->qmessage,
+                                           DNS_SECTION_ADDITIONAL, 0);
+        if (result != ISC_R_SUCCESS)
+                goto cleanup_message;
+
+        result = dns_message_renderend(fctx->qmessage);
+        if (result != ISC_R_SUCCESS)
+                goto cleanup_message;
+
+        dns_compress_invalidate(&cctx);
+        cleanup_cctx = ISC_FALSE;
+
+        if (dns_message_gettsigkey(fctx->qmessage) != NULL) {
+                dns_tsigkey_attach(dns_message_gettsigkey(fctx->qmessage),
+                                   &query->tsigkey);
+                result = dns_message_getquerytsig(fctx->qmessage,
+                                                  fctx->res->mctx,
+                                                  &query->tsig);
+                if (result != ISC_R_SUCCESS)
+                        goto cleanup_message;
+        }
+
+        /*
+         * If using TCP, write the length of the message at the beginning
+         * of the buffer.
+         */
+        if ((query->options & DNS_FETCHOPT_TCP) != 0) {
+                isc_buffer_usedregion(&query->buffer, &r);
+                isc_buffer_putuint16(&tcpbuffer, (isc_uint16_t)r.length);
+                isc_buffer_add(&tcpbuffer, r.length);
+        }
+
+        /*
+         * We're now done with the query message.
+         */
+        dns_message_reset(fctx->qmessage, DNS_MESSAGE_INTENTRENDER);
+
+        socket = dns_dispatch_getsocket(query->dispatch);
+        /*
+         * Send the query!
+         */
+        if ((query->options & DNS_FETCHOPT_TCP) == 0)
+                address = &query->addrinfo->sockaddr;
+        isc_buffer_usedregion(buffer, &r);
+
+        /*
+         * XXXRTH  Make sure we don't send to ourselves!  We should probably
+         *         prune out these addresses when we get them from the ADB.
+         */
+        result = isc_socket_sendto(socket, &r, task, resquery_senddone,
+                                   query, address, NULL);
+        if (result != ISC_R_SUCCESS)
+                goto cleanup_message;
+
+#ifdef LRU_DEBUG
+        res->extqueries++;
+        switch (fctx->type) {
+        case dns_rdatatype_ns:
+                res->extqueries_ns++;
+                break;
+        case dns_rdatatype_soa:
+                res->extqueries_soa++;
+                break;
+        case dns_rdatatype_a:
+                res->extqueries_a++;
+                break;
+        case dns_rdatatype_aaaa:
+                res->extqueries_aaaa++;
+                break;
+        }
+#endif
+        query->sends++;
+
+        QTRACE("sent");
+
+        return (ISC_R_SUCCESS);
 
  cleanup_message:
-       if (cleanup_cctx)
-               dns_compress_invalidate(&cctx);
+        if (cleanup_cctx)
+                dns_compress_invalidate(&cctx);
 
-       dns_message_reset(fctx->qmessage, DNS_MESSAGE_INTENTRENDER);
+        dns_message_reset(fctx->qmessage, DNS_MESSAGE_INTENTRENDER);
 
-       /*
-        * Stop the dispatcher from listening.
-        */
-       dns_dispatch_removeresponse(&query->dispentry, NULL);
+        /*
+         * Stop the dispatcher from listening.
+         */
+        dns_dispatch_removeresponse(&query->dispentry, NULL);
 
  cleanup_temps:
-       if (qname != NULL)
-               dns_message_puttempname(fctx->qmessage, &qname);
-       if (qrdataset != NULL)
-               dns_message_puttemprdataset(fctx->qmessage, &qrdataset);
+        if (qname != NULL)
+                dns_message_puttempname(fctx->qmessage, &qname);
+        if (qrdataset != NULL)
+                dns_message_puttemprdataset(fctx->qmessage, &qrdataset);
 
-       return (result);
+        return (result);
 }
 
 static void
 resquery_connected(isc_task_t *task, isc_event_t *event) {
-       isc_socketevent_t *sevent = (isc_socketevent_t *)event;
-       resquery_t *query = event->ev_arg;
-       isc_boolean_t retry = ISC_FALSE;
-       isc_result_t result;
-       unsigned int attrs;
-       fetchctx_t *fctx;
-
-       REQUIRE(event->ev_type == ISC_SOCKEVENT_CONNECT);
-       REQUIRE(VALID_QUERY(query));
-
-       QTRACE("connected");
-
-       UNUSED(task);
-
-       /*
-        * XXXRTH
-        *
-        * Currently we don't wait for the connect event before retrying
-        * a query.  This means that if we get really behind, we may end
-        * up doing extra work!
-        */
-
-       query->connects--;
-       fctx = query->fctx;
-
-       if (RESQUERY_CANCELED(query)) {
-               /*
-                * This query was canceled while the connect() was in
-                * progress.
-                */
-               isc_socket_detach(&query->tcpsocket);
-               resquery_destroy(&query);
-       } else {
-               switch (sevent->result) {
-               case ISC_R_SUCCESS:
-                       /*
-                        * We are connected.  Create a dispatcher and
-                        * send the query.
-                        */
-                       attrs = 0;
-                       attrs |= DNS_DISPATCHATTR_TCP;
-                       attrs |= DNS_DISPATCHATTR_PRIVATE;
-                       attrs |= DNS_DISPATCHATTR_CONNECTED;
-                       if (isc_sockaddr_pf(&query->addrinfo->sockaddr) ==
-                           AF_INET)
-                               attrs |= DNS_DISPATCHATTR_IPV4;
-                       else
-                               attrs |= DNS_DISPATCHATTR_IPV6;
-                       attrs |= DNS_DISPATCHATTR_MAKEQUERY;
-
-                       result = dns_dispatch_createtcp(query->dispatchmgr,
-                                                    query->tcpsocket,
-                                                    query->fctx->res->taskmgr,
-                                                    4096, 2, 1, 1, 3, attrs,
-                                                    &query->dispatch);
-
-                       /*
-                        * Regardless of whether dns_dispatch_create()
-                        * succeeded or not, we don't need our reference
-                        * to the socket anymore.
-                        */
-                       isc_socket_detach(&query->tcpsocket);
-
-                       if (result == ISC_R_SUCCESS)
-                               result = resquery_send(query);
-
-                       if (result != ISC_R_SUCCESS) {
-                               fctx_cancelquery(&query, NULL, NULL,
-                                                ISC_FALSE);
-                               fctx_done(fctx, result);
-                       }
-                       break;
-
-               case ISC_R_NETUNREACH:
-               case ISC_R_HOSTUNREACH:
-               case ISC_R_CONNREFUSED:
-               case ISC_R_NOPERM:
-               case ISC_R_ADDRNOTAVAIL:
-               case ISC_R_CONNECTIONRESET:
-                       /*
-                        * No route to remote.
-                        */
-                       isc_socket_detach(&query->tcpsocket);
-                       fctx_cancelquery(&query, NULL, NULL, ISC_TRUE);
-                       retry = ISC_TRUE;
-                       break;
-
-               default:
-                       isc_socket_detach(&query->tcpsocket);
-                       fctx_cancelquery(&query, NULL, NULL, ISC_FALSE);
-                       break;
-               }
-       }
-
-       isc_event_free(&event);
-       
-       if (retry) {
-               /*
-                * Behave as if the idle timer has expired.  For TCP
-                * connections this may not actually reflect the latest timer.
-                */
-               fctx->attributes &= ~FCTX_ATTR_ADDRWAIT;
-               result = fctx_stopidletimer(fctx);
-               if (result != ISC_R_SUCCESS)
-                       fctx_done(fctx, result);
-               else
-                       fctx_try(fctx);
-       }
+        isc_socketevent_t *sevent = (isc_socketevent_t *)event;
+        resquery_t *query = event->ev_arg;
+        isc_boolean_t retry = ISC_FALSE;
+        isc_result_t result;
+        unsigned int attrs;
+        fetchctx_t *fctx;
+
+        REQUIRE(event->ev_type == ISC_SOCKEVENT_CONNECT);
+        REQUIRE(VALID_QUERY(query));
+
+        QTRACE("connected");
+
+        UNUSED(task);
+
+        /*
+         * XXXRTH
+         *
+         * Currently we don't wait for the connect event before retrying
+         * a query.  This means that if we get really behind, we may end
+         * up doing extra work!
+         */
+
+        query->connects--;
+        fctx = query->fctx;
+
+        if (RESQUERY_CANCELED(query)) {
+                /*
+                 * This query was canceled while the connect() was in
+                 * progress.
+                 */
+                isc_socket_detach(&query->tcpsocket);
+                resquery_destroy(&query);
+        } else {
+                switch (sevent->result) {
+                case ISC_R_SUCCESS:
+                        /*
+                         * We are connected.  Create a dispatcher and
+                         * send the query.
+                         */
+                        attrs = 0;
+                        attrs |= DNS_DISPATCHATTR_TCP;
+                        attrs |= DNS_DISPATCHATTR_PRIVATE;
+                        attrs |= DNS_DISPATCHATTR_CONNECTED;
+                        if (isc_sockaddr_pf(&query->addrinfo->sockaddr) ==
+                            AF_INET)
+                                attrs |= DNS_DISPATCHATTR_IPV4;
+                        else
+                                attrs |= DNS_DISPATCHATTR_IPV6;
+                        attrs |= DNS_DISPATCHATTR_MAKEQUERY;
+
+                        result = dns_dispatch_createtcp(query->dispatchmgr,
+                                                     query->tcpsocket,
+                                                     query->fctx->res->taskmgr,
+                                                     4096, 2, 1, 1, 3, attrs,
+                                                     &query->dispatch);
+
+                        /*
+                         * Regardless of whether dns_dispatch_create()
+                         * succeeded or not, we don't need our reference
+                         * to the socket anymore.
+                         */
+                        isc_socket_detach(&query->tcpsocket);
+
+                        if (result == ISC_R_SUCCESS)
+                                result = resquery_send(query);
+
+                        if (result != ISC_R_SUCCESS) {
+                                fctx_cancelquery(&query, NULL, NULL,
+                                                 ISC_FALSE);
+                                fctx_done(fctx, result);
+                        }
+                        break;
+
+                case ISC_R_NETUNREACH:
+                case ISC_R_HOSTUNREACH:
+                case ISC_R_CONNREFUSED:
+                case ISC_R_NOPERM:
+                case ISC_R_ADDRNOTAVAIL:
+                case ISC_R_CONNECTIONRESET:
+                        /*
+                         * No route to remote.
+                         */
+                        isc_socket_detach(&query->tcpsocket);
+                        fctx_cancelquery(&query, NULL, NULL, ISC_TRUE);
+                        retry = ISC_TRUE;
+                        break;
+
+                default:
+                        isc_socket_detach(&query->tcpsocket);
+                        fctx_cancelquery(&query, NULL, NULL, ISC_FALSE);
+                        break;
+                }
+        }
+
+        isc_event_free(&event);
+
+        if (retry) {
+                /*
+                 * Behave as if the idle timer has expired.  For TCP
+                 * connections this may not actually reflect the latest timer.
+                 */
+                fctx->attributes &= ~FCTX_ATTR_ADDRWAIT;
+                result = fctx_stopidletimer(fctx);
+                if (result != ISC_R_SUCCESS)
+                        fctx_done(fctx, result);
+                else
+                        fctx_try(fctx);
+        }
 }
 
 static void
 fctx_finddone(isc_task_t *task, isc_event_t *event) {
-       fetchctx_t *fctx;
-       dns_adbfind_t *find;
-       dns_resolver_t *res;
-       isc_boolean_t want_try = ISC_FALSE;
-       isc_boolean_t want_done = ISC_FALSE;
-       isc_boolean_t bucket_empty = ISC_FALSE;
-       unsigned int bucketnum;
-
-       find = event->ev_sender;
-       fctx = event->ev_arg;
-       REQUIRE(VALID_FCTX(fctx));
-       res = fctx->res;
-
-       UNUSED(task);
-
-       FCTXTRACE("finddone");
-
-       INSIST(fctx->pending > 0);
-       fctx->pending--;
-
-       if (ADDRWAIT(fctx)) {
-               /*
-                * The fetch is waiting for a name to be found.
-                */
-               INSIST(!SHUTTINGDOWN(fctx));
-               fctx->attributes &= ~FCTX_ATTR_ADDRWAIT;
-               if (event->ev_type == DNS_EVENT_ADBMOREADDRESSES)
-                       want_try = ISC_TRUE;
-               else if (fctx->pending == 0) {
-                       /*
-                        * We've got nothing else to wait for and don't
-                        * know the answer.  There's nothing to do but
-                        * fail the fctx.
-                        */
-                       want_done = ISC_TRUE;
-               }
-       } else if (SHUTTINGDOWN(fctx) && fctx->pending == 0 &&
-                  fctx->nqueries == 0 && ISC_LIST_EMPTY(fctx->validators)) {
-               bucketnum = fctx->bucketnum;
-               LOCK(&res->buckets[bucketnum].lock);
-               /*
-                * Note that we had to wait until we had the lock before
-                * looking at fctx->references.
-                */
-               if (fctx->references == 0)
-                       bucket_empty = fctx_destroy(fctx);
-               UNLOCK(&res->buckets[bucketnum].lock);
-       }
-
-       isc_event_free(&event);
-       dns_adb_destroyfind(&find);
-
-       if (want_try)
-               fctx_try(fctx);
-       else if (want_done)
-               fctx_done(fctx, ISC_R_FAILURE);
-       else if (bucket_empty)
-               empty_bucket(res);
+        fetchctx_t *fctx;
+        dns_adbfind_t *find;
+        dns_resolver_t *res;
+        isc_boolean_t want_try = ISC_FALSE;
+        isc_boolean_t want_done = ISC_FALSE;
+        isc_boolean_t bucket_empty = ISC_FALSE;
+        unsigned int bucketnum;
+
+        find = event->ev_sender;
+        fctx = event->ev_arg;
+        REQUIRE(VALID_FCTX(fctx));
+        res = fctx->res;
+
+        UNUSED(task);
+
+        FCTXTRACE("finddone");
+
+        INSIST(fctx->pending > 0);
+        fctx->pending--;
+
+        if (ADDRWAIT(fctx)) {
+                /*
+                 * The fetch is waiting for a name to be found.
+                 */
+                INSIST(!SHUTTINGDOWN(fctx));
+                fctx->attributes &= ~FCTX_ATTR_ADDRWAIT;
+                if (event->ev_type == DNS_EVENT_ADBMOREADDRESSES)
+                        want_try = ISC_TRUE;
+                else if (fctx->pending == 0) {
+                        /*
+                         * We've got nothing else to wait for and don't
+                         * know the answer.  There's nothing to do but
+                         * fail the fctx.
+                         */
+                        want_done = ISC_TRUE;
+                }
+        } else if (SHUTTINGDOWN(fctx) && fctx->pending == 0 &&
+                   fctx->nqueries == 0 && ISC_LIST_EMPTY(fctx->validators)) {
+                bucketnum = fctx->bucketnum;
+                LOCK(&res->buckets[bucketnum].lock);
+                /*
+                 * Note that we had to wait until we had the lock before
+                 * looking at fctx->references.
+                 */
+                if (fctx->references == 0)
+                        bucket_empty = fctx_destroy(fctx);
+                UNLOCK(&res->buckets[bucketnum].lock);
+        }
+
+        isc_event_free(&event);
+        dns_adb_destroyfind(&find);
+
+        if (want_try)
+                fctx_try(fctx);
+        else if (want_done)
+                fctx_done(fctx, ISC_R_FAILURE);
+        else if (bucket_empty)
+                empty_bucket(res);
 }
 
 
 static inline isc_boolean_t
 bad_server(fetchctx_t *fctx, isc_sockaddr_t *address) {
-       isc_sockaddr_t *sa;
+        isc_sockaddr_t *sa;
 
-       for (sa = ISC_LIST_HEAD(fctx->bad);
-            sa != NULL;
-            sa = ISC_LIST_NEXT(sa, link)) {
-               if (isc_sockaddr_equal(sa, address))
-                       return (ISC_TRUE);
-       }
+        for (sa = ISC_LIST_HEAD(fctx->bad);
+             sa != NULL;
+             sa = ISC_LIST_NEXT(sa, link)) {
+                if (isc_sockaddr_equal(sa, address))
+                        return (ISC_TRUE);
+        }
 
-       return (ISC_FALSE);
+        return (ISC_FALSE);
 }
 
 static inline isc_boolean_t
 mark_bad(fetchctx_t *fctx) {
-       dns_adbfind_t *curr;
-       dns_adbaddrinfo_t *addrinfo;
-       isc_boolean_t all_bad = ISC_TRUE;
-
-       /*
-        * Mark all known bad servers, so we don't try to talk to them
-        * again.
-        */
-
-       /*
-        * Mark any bad nameservers.
-        */
-       for (curr = ISC_LIST_HEAD(fctx->finds);
-            curr != NULL;
-            curr = ISC_LIST_NEXT(curr, publink)) {
-               for (addrinfo = ISC_LIST_HEAD(curr->list);
-                    addrinfo != NULL;
-                    addrinfo = ISC_LIST_NEXT(addrinfo, publink)) {
-                       if (bad_server(fctx, &addrinfo->sockaddr))
-                               addrinfo->flags |= FCTX_ADDRINFO_MARK;
-                       else
-                               all_bad = ISC_FALSE;
-               }
-       }
-
-       /*
-        * Mark any bad forwarders.
-        */
-       for (addrinfo = ISC_LIST_HEAD(fctx->forwaddrs);
-            addrinfo != NULL;
-            addrinfo = ISC_LIST_NEXT(addrinfo, publink)) {
-               if (bad_server(fctx, &addrinfo->sockaddr))
-                       addrinfo->flags |= FCTX_ADDRINFO_MARK;
-               else
-                       all_bad = ISC_FALSE;
-       }
-
-       /*
-        * Mark any bad alternates.
-        */
-       for (curr = ISC_LIST_HEAD(fctx->altfinds);
-            curr != NULL;
-            curr = ISC_LIST_NEXT(curr, publink)) {
-               for (addrinfo = ISC_LIST_HEAD(curr->list);
-                    addrinfo != NULL;
-                    addrinfo = ISC_LIST_NEXT(addrinfo, publink)) {
-                       if (bad_server(fctx, &addrinfo->sockaddr))
-                               addrinfo->flags |= FCTX_ADDRINFO_MARK;
-                       else
-                               all_bad = ISC_FALSE;
-               }
-       }
-
-       for (addrinfo = ISC_LIST_HEAD(fctx->altaddrs);
-            addrinfo != NULL;
-            addrinfo = ISC_LIST_NEXT(addrinfo, publink)) {
-               if (bad_server(fctx, &addrinfo->sockaddr))
-                       addrinfo->flags |= FCTX_ADDRINFO_MARK;
-               else
-                       all_bad = ISC_FALSE;
-       }
-
-       return (all_bad);
+        dns_adbfind_t *curr;
+        dns_adbaddrinfo_t *addrinfo;
+        isc_boolean_t all_bad = ISC_TRUE;
+
+        /*
+         * Mark all known bad servers, so we don't try to talk to them
+         * again.
+         */
+
+        /*
+         * Mark any bad nameservers.
+         */
+        for (curr = ISC_LIST_HEAD(fctx->finds);
+             curr != NULL;
+             curr = ISC_LIST_NEXT(curr, publink)) {
+                for (addrinfo = ISC_LIST_HEAD(curr->list);
+                     addrinfo != NULL;
+                     addrinfo = ISC_LIST_NEXT(addrinfo, publink)) {
+                        if (bad_server(fctx, &addrinfo->sockaddr))
+                                addrinfo->flags |= FCTX_ADDRINFO_MARK;
+                        else
+                                all_bad = ISC_FALSE;
+                }
+        }
+
+        /*
+         * Mark any bad forwarders.
+         */
+        for (addrinfo = ISC_LIST_HEAD(fctx->forwaddrs);
+             addrinfo != NULL;
+             addrinfo = ISC_LIST_NEXT(addrinfo, publink)) {
+                if (bad_server(fctx, &addrinfo->sockaddr))
+                        addrinfo->flags |= FCTX_ADDRINFO_MARK;
+                else
+                        all_bad = ISC_FALSE;
+        }
+
+        /*
+         * Mark any bad alternates.
+         */
+        for (curr = ISC_LIST_HEAD(fctx->altfinds);
+             curr != NULL;
+             curr = ISC_LIST_NEXT(curr, publink)) {
+                for (addrinfo = ISC_LIST_HEAD(curr->list);
+                     addrinfo != NULL;
+                     addrinfo = ISC_LIST_NEXT(addrinfo, publink)) {
+                        if (bad_server(fctx, &addrinfo->sockaddr))
+                                addrinfo->flags |= FCTX_ADDRINFO_MARK;
+                        else
+                                all_bad = ISC_FALSE;
+                }
+        }
+
+        for (addrinfo = ISC_LIST_HEAD(fctx->altaddrs);
+             addrinfo != NULL;
+             addrinfo = ISC_LIST_NEXT(addrinfo, publink)) {
+                if (bad_server(fctx, &addrinfo->sockaddr))
+                        addrinfo->flags |= FCTX_ADDRINFO_MARK;
+                else
+                        all_bad = ISC_FALSE;
+        }
+
+        return (all_bad);
 }
 
 static void
 add_bad(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, isc_result_t reason) {
-       char namebuf[DNS_NAME_FORMATSIZE];
-       char addrbuf[ISC_SOCKADDR_FORMATSIZE];
-       char classbuf[64];
-       char typebuf[64];
-       char code[64];
-       isc_buffer_t b;
-       isc_sockaddr_t *sa;
-       const char *sep1, *sep2;
-       isc_sockaddr_t *address = &addrinfo->sockaddr;
-
-       if (bad_server(fctx, address)) {
-               /*
-                * We already know this server is bad.
-                */
-               return;
-       }
-
-       FCTXTRACE("add_bad");
-
-       sa = isc_mem_get(fctx->res->buckets[fctx->bucketnum].mctx,
-                        sizeof(*sa));
-       if (sa == NULL)
-               return;
-       *sa = *address;
-       ISC_LIST_INITANDAPPEND(fctx->bad, sa, link);
-
-       if (reason == DNS_R_LAME)       /* already logged */
-               return;
-
-       if (reason == DNS_R_UNEXPECTEDRCODE && 
-           fctx->rmessage->opcode == dns_rcode_servfail &&
-           ISFORWARDER(addrinfo))
-               return;
-
-       if (reason == DNS_R_UNEXPECTEDRCODE) {
-               isc_buffer_init(&b, code, sizeof(code) - 1);
-               dns_rcode_totext(fctx->rmessage->rcode, &b);
-               code[isc_buffer_usedlength(&b)] = '\0';
-               sep1 = "(";
-               sep2 = ") ";
-       } else if (reason == DNS_R_UNEXPECTEDOPCODE) {
-               isc_buffer_init(&b, code, sizeof(code) - 1);
-               dns_opcode_totext((dns_opcode_t)fctx->rmessage->opcode, &b);
-               code[isc_buffer_usedlength(&b)] = '\0';
-               sep1 = "(";
-               sep2 = ") ";
-       } else {
-               code[0] = '\0';
-               sep1 = "";
-               sep2 = "";
-       }
-       dns_name_format(&fctx->name, namebuf, sizeof(namebuf));
-       dns_rdatatype_format(fctx->type, typebuf, sizeof(typebuf));
-       dns_rdataclass_format(fctx->res->rdclass, classbuf, sizeof(classbuf));
-       isc_sockaddr_format(address, addrbuf, sizeof(addrbuf));
-       isc_log_write(dns_lctx, DNS_LOGCATEGORY_LAME_SERVERS,
-                     DNS_LOGMODULE_RESOLVER, ISC_LOG_INFO,
-                     "%s %s%s%sresolving '%s/%s/%s': %s",
-                     dns_result_totext(reason), sep1, code, sep2,
-                     namebuf, typebuf, classbuf, addrbuf);
+        char namebuf[DNS_NAME_FORMATSIZE];
+        char addrbuf[ISC_SOCKADDR_FORMATSIZE];
+        char classbuf[64];
+        char typebuf[64];
+        char code[64];
+        isc_buffer_t b;
+        isc_sockaddr_t *sa;
+        const char *sep1, *sep2;
+        isc_sockaddr_t *address = &addrinfo->sockaddr;
+
+        if (bad_server(fctx, address)) {
+                /*
+                 * We already know this server is bad.
+                 */
+                return;
+        }
+
+        FCTXTRACE("add_bad");
+
+        sa = isc_mem_get(fctx->res->buckets[fctx->bucketnum].mctx,
+                         sizeof(*sa));
+        if (sa == NULL)
+                return;
+        *sa = *address;
+        ISC_LIST_INITANDAPPEND(fctx->bad, sa, link);
+
+        if (reason == DNS_R_LAME)       /* already logged */
+                return;
+
+        if (reason == DNS_R_UNEXPECTEDRCODE &&
+            fctx->rmessage->opcode == dns_rcode_servfail &&
+            ISFORWARDER(addrinfo))
+                return;
+
+        if (reason == DNS_R_UNEXPECTEDRCODE) {
+                isc_buffer_init(&b, code, sizeof(code) - 1);
+                dns_rcode_totext(fctx->rmessage->rcode, &b);
+                code[isc_buffer_usedlength(&b)] = '\0';
+                sep1 = "(";
+                sep2 = ") ";
+        } else if (reason == DNS_R_UNEXPECTEDOPCODE) {
+                isc_buffer_init(&b, code, sizeof(code) - 1);
+                dns_opcode_totext((dns_opcode_t)fctx->rmessage->opcode, &b);
+                code[isc_buffer_usedlength(&b)] = '\0';
+                sep1 = "(";
+                sep2 = ") ";
+        } else {
+                code[0] = '\0';
+                sep1 = "";
+                sep2 = "";
+        }
+        dns_name_format(&fctx->name, namebuf, sizeof(namebuf));
+        dns_rdatatype_format(fctx->type, typebuf, sizeof(typebuf));
+        dns_rdataclass_format(fctx->res->rdclass, classbuf, sizeof(classbuf));
+        isc_sockaddr_format(address, addrbuf, sizeof(addrbuf));
+        isc_log_write(dns_lctx, DNS_LOGCATEGORY_LAME_SERVERS,
+                      DNS_LOGMODULE_RESOLVER, ISC_LOG_INFO,
+                      "%s %s%s%sresolving '%s/%s/%s': %s",
+                      dns_result_totext(reason), sep1, code, sep2,
+                      namebuf, typebuf, classbuf, addrbuf);
 }
 
 static void
 sort_adbfind(dns_adbfind_t *find) {
-       dns_adbaddrinfo_t *best, *curr;
-       dns_adbaddrinfolist_t sorted;
-
-       /*
-        * Lame N^2 bubble sort.
-        */
-
-       ISC_LIST_INIT(sorted);
-       while (!ISC_LIST_EMPTY(find->list)) {
-               best = ISC_LIST_HEAD(find->list);
-               curr = ISC_LIST_NEXT(best, publink);
-               while (curr != NULL) {
-                       if (curr->srtt < best->srtt)
-                               best = curr;
-                       curr = ISC_LIST_NEXT(curr, publink);
-               }
-               ISC_LIST_UNLINK(find->list, best, publink);
-               ISC_LIST_APPEND(sorted, best, publink);
-       }
-       find->list = sorted;
+        dns_adbaddrinfo_t *best, *curr;
+        dns_adbaddrinfolist_t sorted;
+
+        /*
+         * Lame N^2 bubble sort.
+         */
+
+        ISC_LIST_INIT(sorted);
+        while (!ISC_LIST_EMPTY(find->list)) {
+                best = ISC_LIST_HEAD(find->list);
+                curr = ISC_LIST_NEXT(best, publink);
+                while (curr != NULL) {
+                        if (curr->srtt < best->srtt)
+                                best = curr;
+                        curr = ISC_LIST_NEXT(curr, publink);
+                }
+                ISC_LIST_UNLINK(find->list, best, publink);
+                ISC_LIST_APPEND(sorted, best, publink);
+        }
+        find->list = sorted;
 }
 
 static void
 sort_finds(fetchctx_t *fctx) {
-       dns_adbfind_t *best, *curr;
-       dns_adbfindlist_t sorted;
-       dns_adbaddrinfo_t *addrinfo, *bestaddrinfo;
-
-       /*
-        * Lame N^2 bubble sort.
-        */
-
-       ISC_LIST_INIT(sorted);
-       while (!ISC_LIST_EMPTY(fctx->finds)) {
-               best = ISC_LIST_HEAD(fctx->finds);
-               bestaddrinfo = ISC_LIST_HEAD(best->list);
-               INSIST(bestaddrinfo != NULL);
-               curr = ISC_LIST_NEXT(best, publink);
-               while (curr != NULL) {
-                       addrinfo = ISC_LIST_HEAD(curr->list);
-                       INSIST(addrinfo != NULL);
-                       if (addrinfo->srtt < bestaddrinfo->srtt) {
-                               best = curr;
-                               bestaddrinfo = addrinfo;
-                       }
-                       curr = ISC_LIST_NEXT(curr, publink);
-               }
-               ISC_LIST_UNLINK(fctx->finds, best, publink);
-               ISC_LIST_APPEND(sorted, best, publink);
-       }
-       fctx->finds = sorted;
-
-       ISC_LIST_INIT(sorted);
-       while (!ISC_LIST_EMPTY(fctx->altfinds)) {
-               best = ISC_LIST_HEAD(fctx->altfinds);
-               bestaddrinfo = ISC_LIST_HEAD(best->list);
-               INSIST(bestaddrinfo != NULL);
-               curr = ISC_LIST_NEXT(best, publink);
-               while (curr != NULL) {
-                       addrinfo = ISC_LIST_HEAD(curr->list);
-                       INSIST(addrinfo != NULL);
-                       if (addrinfo->srtt < bestaddrinfo->srtt) {
-                               best = curr;
-                               bestaddrinfo = addrinfo;
-                       }
-                       curr = ISC_LIST_NEXT(curr, publink);
-               }
-               ISC_LIST_UNLINK(fctx->altfinds, best, publink);
-               ISC_LIST_APPEND(sorted, best, publink);
-       }
-       fctx->altfinds = sorted;
+        dns_adbfind_t *best, *curr;
+        dns_adbfindlist_t sorted;
+        dns_adbaddrinfo_t *addrinfo, *bestaddrinfo;
+
+        /*
+         * Lame N^2 bubble sort.
+         */
+
+        ISC_LIST_INIT(sorted);
+        while (!ISC_LIST_EMPTY(fctx->finds)) {
+                best = ISC_LIST_HEAD(fctx->finds);
+                bestaddrinfo = ISC_LIST_HEAD(best->list);
+                INSIST(bestaddrinfo != NULL);
+                curr = ISC_LIST_NEXT(best, publink);
+                while (curr != NULL) {
+                        addrinfo = ISC_LIST_HEAD(curr->list);
+                        INSIST(addrinfo != NULL);
+                        if (addrinfo->srtt < bestaddrinfo->srtt) {
+                                best = curr;
+                                bestaddrinfo = addrinfo;
+                        }
+                        curr = ISC_LIST_NEXT(curr, publink);
+                }
+                ISC_LIST_UNLINK(fctx->finds, best, publink);
+                ISC_LIST_APPEND(sorted, best, publink);
+        }
+        fctx->finds = sorted;
+
+        ISC_LIST_INIT(sorted);
+        while (!ISC_LIST_EMPTY(fctx->altfinds)) {
+                best = ISC_LIST_HEAD(fctx->altfinds);
+                bestaddrinfo = ISC_LIST_HEAD(best->list);
+                INSIST(bestaddrinfo != NULL);
+                curr = ISC_LIST_NEXT(best, publink);
+                while (curr != NULL) {
+                        addrinfo = ISC_LIST_HEAD(curr->list);
+                        INSIST(addrinfo != NULL);
+                        if (addrinfo->srtt < bestaddrinfo->srtt) {
+                                best = curr;
+                                bestaddrinfo = addrinfo;
+                        }
+                        curr = ISC_LIST_NEXT(curr, publink);
+                }
+                ISC_LIST_UNLINK(fctx->altfinds, best, publink);
+                ISC_LIST_APPEND(sorted, best, publink);
+        }
+        fctx->altfinds = sorted;
 }
 
 static void
 findname(fetchctx_t *fctx, dns_name_t *name, in_port_t port,
-        unsigned int options, unsigned int flags, isc_stdtime_t now,
-        isc_boolean_t *need_alternate)
+         unsigned int options, unsigned int flags, isc_stdtime_t now,
+         isc_boolean_t *need_alternate)
 {
-       dns_adbaddrinfo_t *ai;
-       dns_adbfind_t *find;
-       dns_resolver_t *res;
-       isc_boolean_t unshared;
-       isc_result_t result;
-
-       res = fctx->res;
-       unshared = ISC_TF((fctx->options | DNS_FETCHOPT_UNSHARED) != 0);
-       /*
-        * If this name is a subdomain of the query domain, tell
-        * the ADB to start looking using zone/hint data. This keeps us
-        * from getting stuck if the nameserver is beneath the zone cut
-        * and we don't know its address (e.g. because the A record has
-        * expired).
-        */
-       if (dns_name_issubdomain(name, &fctx->domain))
-               options |= DNS_ADBFIND_STARTATZONE;
-       options |= DNS_ADBFIND_GLUEOK;
-       options |= DNS_ADBFIND_HINTOK;
-
-       /*
-        * See what we know about this address.
-        */
-       find = NULL;
-       result = dns_adb_createfind(fctx->adb,
-                                   res->buckets[fctx->bucketnum].task,
-                                   fctx_finddone, fctx, name,
-                                   &fctx->name, fctx->type,
-                                   options, now, NULL,
-                                   res->view->dstport, &find);
-       if (result != ISC_R_SUCCESS) {
-               if (result == DNS_R_ALIAS) {
-                       /*
-                        * XXXRTH  Follow the CNAME/DNAME chain?
-                        */
-                       dns_adb_destroyfind(&find);
-               }
-       } else if (!ISC_LIST_EMPTY(find->list)) {
-               /*
-                * We have at least some of the addresses for the
-                * name.
-                */
-               INSIST((find->options & DNS_ADBFIND_WANTEVENT) == 0);
-               sort_adbfind(find);
-               if (flags != 0 || port != 0) {
-                       for (ai = ISC_LIST_HEAD(find->list);
-                            ai != NULL;
-                            ai = ISC_LIST_NEXT(ai, publink)) {
-                               ai->flags |= flags;
-                               if (port != 0)
-                                       isc_sockaddr_setport(&ai->sockaddr,
-                                                            port);
-                       }
-               }
-               if ((flags & FCTX_ADDRINFO_FORWARDER) != 0)
-                       ISC_LIST_APPEND(fctx->altfinds, find, publink);
-               else
-                       ISC_LIST_APPEND(fctx->finds, find, publink);
-       } else {
-               /*
-                * We don't know any of the addresses for this
-                * name.
-                */
-               if ((find->options & DNS_ADBFIND_WANTEVENT) != 0) {
-                       /*
-                        * We're looking for them and will get an
-                        * event about it later.
-                        */
-                       fctx->pending++;
-                       /*
-                        * Bootstrap.
-                        */
-                       if (need_alternate != NULL &&
-                           !*need_alternate && unshared &&
-                           ((res->dispatchv4 == NULL &&
-                             find->result_v6 != DNS_R_NXDOMAIN) ||
-                            (res->dispatchv6 == NULL &&
-                             find->result_v4 != DNS_R_NXDOMAIN)))
-                               *need_alternate = ISC_TRUE;
-               } else {
-                       /*
-                        * If we know there are no addresses for
-                        * the family we are using then try to add
-                        * an alternative server.
-                        */
-                       if (need_alternate != NULL && !*need_alternate &&
-                           ((res->dispatchv4 == NULL &&
-                             find->result_v6 == DNS_R_NXRRSET) ||
-                            (res->dispatchv6 == NULL &&
-                             find->result_v4 == DNS_R_NXRRSET)))
-                               *need_alternate = ISC_TRUE;
-                       dns_adb_destroyfind(&find);
-               }
-       }
+        dns_adbaddrinfo_t *ai;
+        dns_adbfind_t *find;
+        dns_resolver_t *res;
+        isc_boolean_t unshared;
+        isc_result_t result;
+
+        res = fctx->res;
+        unshared = ISC_TF((fctx->options | DNS_FETCHOPT_UNSHARED) != 0);
+        /*
+         * If this name is a subdomain of the query domain, tell
+         * the ADB to start looking using zone/hint data. This keeps us
+         * from getting stuck if the nameserver is beneath the zone cut
+         * and we don't know its address (e.g. because the A record has
+         * expired).
+         */
+        if (dns_name_issubdomain(name, &fctx->domain))
+                options |= DNS_ADBFIND_STARTATZONE;
+        options |= DNS_ADBFIND_GLUEOK;
+        options |= DNS_ADBFIND_HINTOK;
+
+        /*
+         * See what we know about this address.
+         */
+        find = NULL;
+        result = dns_adb_createfind(fctx->adb,
+                                    res->buckets[fctx->bucketnum].task,
+                                    fctx_finddone, fctx, name,
+                                    &fctx->name, fctx->type,
+                                    options, now, NULL,
+                                    res->view->dstport, &find);
+        if (result != ISC_R_SUCCESS) {
+                if (result == DNS_R_ALIAS) {
+                        /*
+                         * XXXRTH  Follow the CNAME/DNAME chain?
+                         */
+                        dns_adb_destroyfind(&find);
+                }
+        } else if (!ISC_LIST_EMPTY(find->list)) {
+                /*
+                 * We have at least some of the addresses for the
+                 * name.
+                 */
+                INSIST((find->options & DNS_ADBFIND_WANTEVENT) == 0);
+                sort_adbfind(find);
+                if (flags != 0 || port != 0) {
+                        for (ai = ISC_LIST_HEAD(find->list);
+                             ai != NULL;
+                             ai = ISC_LIST_NEXT(ai, publink)) {
+                                ai->flags |= flags;
+                                if (port != 0)
+                                        isc_sockaddr_setport(&ai->sockaddr,
+                                                             port);
+                        }
+                }
+                if ((flags & FCTX_ADDRINFO_FORWARDER) != 0)
+                        ISC_LIST_APPEND(fctx->altfinds, find, publink);
+                else
+                        ISC_LIST_APPEND(fctx->finds, find, publink);
+        } else {
+                /*
+                 * We don't know any of the addresses for this
+                 * name.
+                 */
+                if ((find->options & DNS_ADBFIND_WANTEVENT) != 0) {
+                        /*
+                         * We're looking for them and will get an
+                         * event about it later.
+                         */
+                        fctx->pending++;
+                        /*
+                         * Bootstrap.
+                         */
+                        if (need_alternate != NULL &&
+                            !*need_alternate && unshared &&
+                            ((res->dispatchv4 == NULL &&
+                              find->result_v6 != DNS_R_NXDOMAIN) ||
+                             (res->dispatchv6 == NULL &&
+                              find->result_v4 != DNS_R_NXDOMAIN)))
+                                *need_alternate = ISC_TRUE;
+                } else {
+                        /*
+                         * If we know there are no addresses for
+                         * the family we are using then try to add
+                         * an alternative server.
+                         */
+                        if (need_alternate != NULL && !*need_alternate &&
+                            ((res->dispatchv4 == NULL &&
+                              find->result_v6 == DNS_R_NXRRSET) ||
+                             (res->dispatchv6 == NULL &&
+                              find->result_v4 == DNS_R_NXRRSET)))
+                                *need_alternate = ISC_TRUE;
+                        dns_adb_destroyfind(&find);
+                }
+        }
 }
 
 static isc_result_t
 fctx_getaddresses(fetchctx_t *fctx) {
-       dns_rdata_t rdata = DNS_RDATA_INIT;
-       isc_result_t result;
-       dns_resolver_t *res;
-       isc_stdtime_t now;
-       unsigned int stdoptions;
-       isc_sockaddr_t *sa;
-       dns_adbaddrinfo_t *ai;
-       isc_boolean_t all_bad;
-       dns_rdata_ns_t ns;
-       isc_boolean_t need_alternate = ISC_FALSE;
-
-       FCTXTRACE("getaddresses");
-
-       /*
-        * Don't pound on remote servers.  (Failsafe!)
-        */
-       fctx->restarts++;
-       if (fctx->restarts > 10) {
-               FCTXTRACE("too many restarts");
-               return (DNS_R_SERVFAIL);
-       }
-
-       res = fctx->res;
-       stdoptions = 0;         /* Keep compiler happy. */
-
-       /*
-        * Forwarders.
-        */
-
-       INSIST(ISC_LIST_EMPTY(fctx->forwaddrs));
-       INSIST(ISC_LIST_EMPTY(fctx->altaddrs));
-
-       /*
-        * If this fctx has forwarders, use them; otherwise use any
-        * selective forwarders specified in the view; otherwise use the
-        * resolver's forwarders (if any).
-        */
-       sa = ISC_LIST_HEAD(fctx->forwarders);
-       if (sa == NULL) {
-               dns_forwarders_t *forwarders = NULL;
-               dns_name_t *name = &fctx->name;
-               dns_name_t suffix;
-               unsigned int labels;
-
-               /*
-                * DS records are found in the parent server.
-                * Strip label to get the correct forwarder (if any).
-                */
-               if (fctx->type == dns_rdatatype_ds &&
-                   dns_name_countlabels(name) > 1) {
-                       dns_name_init(&suffix, NULL);
-                       labels = dns_name_countlabels(name);
-                       dns_name_getlabelsequence(name, 1, labels - 1, &suffix);
-                       name = &suffix;
-               }
-               result = dns_fwdtable_find(fctx->res->view->fwdtable, name,
-                                          &forwarders);
-               if (result == ISC_R_SUCCESS) {
-                       sa = ISC_LIST_HEAD(forwarders->addrs);
-                       fctx->fwdpolicy = forwarders->fwdpolicy;
-               }
-       }
-
-       while (sa != NULL) {
-               ai = NULL;
-               result = dns_adb_findaddrinfo(fctx->adb,
-                                             sa, &ai, 0);  /* XXXMLG */
-               if (result == ISC_R_SUCCESS) {
-                       dns_adbaddrinfo_t *cur;
-                       ai->flags |= FCTX_ADDRINFO_FORWARDER;
-                       cur = ISC_LIST_HEAD(fctx->forwaddrs);
-                       while (cur != NULL && cur->srtt < ai->srtt)
-                               cur = ISC_LIST_NEXT(cur, publink);
-                       if (cur != NULL)
-                               ISC_LIST_INSERTBEFORE(fctx->forwaddrs, cur,
-                                                     ai, publink);
-                       else
-                               ISC_LIST_APPEND(fctx->forwaddrs, ai, publink);
-               }
-               sa = ISC_LIST_NEXT(sa, link);
-       }
-
-       /*
-        * If the forwarding policy is "only", we don't need the addresses
-        * of the nameservers.
-        */
-       if (fctx->fwdpolicy == dns_fwdpolicy_only)
-               goto out;
-
-       /*
-        * Normal nameservers.
-        */
-
-       stdoptions = DNS_ADBFIND_WANTEVENT | DNS_ADBFIND_EMPTYEVENT;
-       if (fctx->restarts == 1) {
-               /*
-                * To avoid sending out a flood of queries likely to
-                * result in NXRRSET, we suppress fetches for address
-                * families we don't have the first time through,
-                * provided that we have addresses in some family we
-                * can use.
-                *
-                * We don't want to set this option all the time, since
-                * if fctx->restarts > 1, we've clearly been having trouble
-                * with the addresses we had, so getting more could help.
-                */
-               stdoptions |= DNS_ADBFIND_AVOIDFETCHES;
-       }
-       if (res->dispatchv4 != NULL)
-               stdoptions |= DNS_ADBFIND_INET;
-       if (res->dispatchv6 != NULL)
-               stdoptions |= DNS_ADBFIND_INET6;
-       isc_stdtime_get(&now);
-
-       INSIST(ISC_LIST_EMPTY(fctx->finds));
-       INSIST(ISC_LIST_EMPTY(fctx->altfinds));
-
-       for (result = dns_rdataset_first(&fctx->nameservers);
-            result == ISC_R_SUCCESS;
-            result = dns_rdataset_next(&fctx->nameservers))
-       {
-               dns_rdataset_current(&fctx->nameservers, &rdata);
-               /*
-                * Extract the name from the NS record.
-                */
-               result = dns_rdata_tostruct(&rdata, &ns, NULL);
-               if (result != ISC_R_SUCCESS)
-                       continue;
-
-               findname(fctx, &ns.name, 0, stdoptions, 0, now,
-                        &need_alternate);
-               dns_rdata_reset(&rdata);
-               dns_rdata_freestruct(&ns);
-       }
-       if (result != ISC_R_NOMORE)
-               return (result);
-
-       /*
-        * Do we need to use 6 to 4?
-        */
-       if (need_alternate) {
-               int family;
-               alternate_t *a;
-               family = (res->dispatchv6 != NULL) ? AF_INET6 : AF_INET;
-               for (a = ISC_LIST_HEAD(fctx->res->alternates);
-                    a != NULL;
-                    a = ISC_LIST_NEXT(a, link)) {
-                       if (!a->isaddress) {
-                               findname(fctx, &a->_u._n.name, a->_u._n.port,
-                                        stdoptions, FCTX_ADDRINFO_FORWARDER,
-                                        now, NULL);
-                               continue;
-                       }
-                       if (isc_sockaddr_pf(&a->_u.addr) != family)
-                               continue;
-                       ai = NULL;
-                       result = dns_adb_findaddrinfo(fctx->adb, &a->_u.addr,
-                                                     &ai, 0);
-                       if (result == ISC_R_SUCCESS) {
-                               dns_adbaddrinfo_t *cur;
-                               ai->flags |= FCTX_ADDRINFO_FORWARDER;
-                               cur = ISC_LIST_HEAD(fctx->altaddrs);
-                               while (cur != NULL && cur->srtt < ai->srtt)
-                                       cur = ISC_LIST_NEXT(cur, publink);
-                               if (cur != NULL)
-                                       ISC_LIST_INSERTBEFORE(fctx->altaddrs,
-                                                             cur, ai, publink);
-                               else
-                                       ISC_LIST_APPEND(fctx->altaddrs, ai,
-                                                       publink);
-                       }
-               }
-       }
+        dns_rdata_t rdata = DNS_RDATA_INIT;
+        isc_result_t result;
+        dns_resolver_t *res;
+        isc_stdtime_t now;
+        unsigned int stdoptions;
+        isc_sockaddr_t *sa;
+        dns_adbaddrinfo_t *ai;
+        isc_boolean_t all_bad;
+        dns_rdata_ns_t ns;
+        isc_boolean_t need_alternate = ISC_FALSE;
+
+        FCTXTRACE("getaddresses");
+
+        /*
+         * Don't pound on remote servers.  (Failsafe!)
+         */
+        fctx->restarts++;
+        if (fctx->restarts > 10) {
+                FCTXTRACE("too many restarts");
+                return (DNS_R_SERVFAIL);
+        }
+
+        res = fctx->res;
+        stdoptions = 0;         /* Keep compiler happy. */
+
+        /*
+         * Forwarders.
+         */
+
+        INSIST(ISC_LIST_EMPTY(fctx->forwaddrs));
+        INSIST(ISC_LIST_EMPTY(fctx->altaddrs));
+
+        /*
+         * If this fctx has forwarders, use them; otherwise use any
+         * selective forwarders specified in the view; otherwise use the
+         * resolver's forwarders (if any).
+         */
+        sa = ISC_LIST_HEAD(fctx->forwarders);
+        if (sa == NULL) {
+                dns_forwarders_t *forwarders = NULL;
+                dns_name_t *name = &fctx->name;
+                dns_name_t suffix;
+                unsigned int labels;
+
+                /*
+                 * DS records are found in the parent server.
+                 * Strip label to get the correct forwarder (if any).
+                 */
+                if (fctx->type == dns_rdatatype_ds &&
+                    dns_name_countlabels(name) > 1) {
+                        dns_name_init(&suffix, NULL);
+                        labels = dns_name_countlabels(name);
+                        dns_name_getlabelsequence(name, 1, labels - 1, &suffix);
+                        name = &suffix;
+                }
+                result = dns_fwdtable_find(fctx->res->view->fwdtable, name,
+                                           &forwarders);
+                if (result == ISC_R_SUCCESS) {
+                        sa = ISC_LIST_HEAD(forwarders->addrs);
+                        fctx->fwdpolicy = forwarders->fwdpolicy;
+                }
+        }
+
+        while (sa != NULL) {
+                ai = NULL;
+                result = dns_adb_findaddrinfo(fctx->adb,
+                                              sa, &ai, 0);  /* XXXMLG */
+                if (result == ISC_R_SUCCESS) {
+                        dns_adbaddrinfo_t *cur;
+                        ai->flags |= FCTX_ADDRINFO_FORWARDER;
+                        cur = ISC_LIST_HEAD(fctx->forwaddrs);
+                        while (cur != NULL && cur->srtt < ai->srtt)
+                                cur = ISC_LIST_NEXT(cur, publink);
+                        if (cur != NULL)
+                                ISC_LIST_INSERTBEFORE(fctx->forwaddrs, cur,
+                                                      ai, publink);
+                        else
+                                ISC_LIST_APPEND(fctx->forwaddrs, ai, publink);
+                }
+                sa = ISC_LIST_NEXT(sa, link);
+        }
+
+        /*
+         * If the forwarding policy is "only", we don't need the addresses
+         * of the nameservers.
+         */
+        if (fctx->fwdpolicy == dns_fwdpolicy_only)
+                goto out;
+
+        /*
+         * Normal nameservers.
+         */
+
+        stdoptions = DNS_ADBFIND_WANTEVENT | DNS_ADBFIND_EMPTYEVENT;
+        if (fctx->restarts == 1) {
+                /*
+                 * To avoid sending out a flood of queries likely to
+                 * result in NXRRSET, we suppress fetches for address
+                 * families we don't have the first time through,
+                 * provided that we have addresses in some family we
+                 * can use.
+                 *
+                 * We don't want to set this option all the time, since
+                 * if fctx->restarts > 1, we've clearly been having trouble
+                 * with the addresses we had, so getting more could help.
+                 */
+                stdoptions |= DNS_ADBFIND_AVOIDFETCHES;
+        }
+        if (res->dispatchv4 != NULL)
+                stdoptions |= DNS_ADBFIND_INET;
+        if (res->dispatchv6 != NULL)
+                stdoptions |= DNS_ADBFIND_INET6;
+        isc_stdtime_get(&now);
+
+        INSIST(ISC_LIST_EMPTY(fctx->finds));
+        INSIST(ISC_LIST_EMPTY(fctx->altfinds));
+
+        for (result = dns_rdataset_first(&fctx->nameservers);
+             result == ISC_R_SUCCESS;
+             result = dns_rdataset_next(&fctx->nameservers))
+        {
+                dns_rdataset_current(&fctx->nameservers, &rdata);
+                /*
+                 * Extract the name from the NS record.
+                 */
+                result = dns_rdata_tostruct(&rdata, &ns, NULL);
+                if (result != ISC_R_SUCCESS)
+                        continue;
+
+                findname(fctx, &ns.name, 0, stdoptions, 0, now,
+                         &need_alternate);
+                dns_rdata_reset(&rdata);
+                dns_rdata_freestruct(&ns);
+        }
+        if (result != ISC_R_NOMORE)
+                return (result);
+
+        /*
+         * Do we need to use 6 to 4?
+         */
+        if (need_alternate) {
+                int family;
+                alternate_t *a;
+                family = (res->dispatchv6 != NULL) ? AF_INET6 : AF_INET;
+                for (a = ISC_LIST_HEAD(fctx->res->alternates);
+                     a != NULL;
+                     a = ISC_LIST_NEXT(a, link)) {
+                        if (!a->isaddress) {
+                                findname(fctx, &a->_u._n.name, a->_u._n.port,
+                                         stdoptions, FCTX_ADDRINFO_FORWARDER,
+                                         now, NULL);
+                                continue;
+                        }
+                        if (isc_sockaddr_pf(&a->_u.addr) != family)
+                                continue;
+                        ai = NULL;
+                        result = dns_adb_findaddrinfo(fctx->adb, &a->_u.addr,
+                                                      &ai, 0);
+                        if (result == ISC_R_SUCCESS) {
+                                dns_adbaddrinfo_t *cur;
+                                ai->flags |= FCTX_ADDRINFO_FORWARDER;
+                                cur = ISC_LIST_HEAD(fctx->altaddrs);
+                                while (cur != NULL && cur->srtt < ai->srtt)
+                                        cur = ISC_LIST_NEXT(cur, publink);
+                                if (cur != NULL)
+                                        ISC_LIST_INSERTBEFORE(fctx->altaddrs,
+                                                              cur, ai, publink);
+                                else
+                                        ISC_LIST_APPEND(fctx->altaddrs, ai,
+                                                        publink);
+                        }
+                }
+        }
 
  out:
-       /*
-        * Mark all known bad servers.
-        */
-       all_bad = mark_bad(fctx);
-
-       /*
-        * How are we doing?
-        */
-       if (all_bad) {
-               /*
-                * We've got no addresses.
-                */
-               if (fctx->pending > 0) {
-                       /*
-                        * We're fetching the addresses, but don't have any
-                        * yet.   Tell the caller to wait for an answer.
-                        */
-                       result = DNS_R_WAIT;
-               } else {
-                       /*
-                        * We've lost completely.  We don't know any
-                        * addresses, and the ADB has told us it can't get
-                        * them.
-                        */
-                       FCTXTRACE("no addresses");
-                       result = ISC_R_FAILURE;
-               }
-       } else {
-               /*
-                * We've found some addresses.  We might still be looking
-                * for more addresses.
-                */
-               sort_finds(fctx);
-               result = ISC_R_SUCCESS;
-       }
-
-       return (result);
+        /*
+         * Mark all known bad servers.
+         */
+        all_bad = mark_bad(fctx);
+
+        /*
+         * How are we doing?
+         */
+        if (all_bad) {
+                /*
+                 * We've got no addresses.
+                 */
+                if (fctx->pending > 0) {
+                        /*
+                         * We're fetching the addresses, but don't have any
+                         * yet.   Tell the caller to wait for an answer.
+                         */
+                        result = DNS_R_WAIT;
+                } else {
+                        /*
+                         * We've lost completely.  We don't know any
+                         * addresses, and the ADB has told us it can't get
+                         * them.
+                         */
+                        FCTXTRACE("no addresses");
+                        result = ISC_R_FAILURE;
+                }
+        } else {
+                /*
+                 * We've found some addresses.  We might still be looking
+                 * for more addresses.
+                 */
+                sort_finds(fctx);
+                result = ISC_R_SUCCESS;
+        }
+
+        return (result);
 }
 
 static inline void
 possibly_mark(fetchctx_t *fctx, dns_adbaddrinfo_t *addr)
 {
-       isc_netaddr_t na;
-       char buf[ISC_NETADDR_FORMATSIZE];
-       isc_sockaddr_t *sa;
-       isc_boolean_t aborted = ISC_FALSE;
-       isc_boolean_t bogus;
-       dns_acl_t *blackhole;
-       isc_netaddr_t ipaddr;
-       dns_peer_t *peer = NULL;
-       dns_resolver_t *res;
-       const char *msg = NULL;
-
-       sa = &addr->sockaddr;
-
-       res = fctx->res;
-       isc_netaddr_fromsockaddr(&ipaddr, sa);
-       blackhole = dns_dispatchmgr_getblackhole(res->dispatchmgr);
-       (void) dns_peerlist_peerbyaddr(res->view->peers, &ipaddr, &peer);
-       
-       if (blackhole != NULL) {
-               int match;
-
-               if (dns_acl_match(&ipaddr, NULL, blackhole,
-                                 &res->view->aclenv,
-                                 &match, NULL) == ISC_R_SUCCESS &&
-                   match > 0)
-                       aborted = ISC_TRUE;
-       }
-
-       if (peer != NULL &&
-           dns_peer_getbogus(peer, &bogus) == ISC_R_SUCCESS &&
-           bogus)
-               aborted = ISC_TRUE;
-
-       if (aborted) {
-               addr->flags |= FCTX_ADDRINFO_MARK;
-               msg = "ignoring blackholed / bogus server: ";
-       } else if (isc_sockaddr_ismulticast(sa)) {
-               addr->flags |= FCTX_ADDRINFO_MARK;
-               msg = "ignoring multicast address: ";
-       } else if (isc_sockaddr_isexperimental(sa)) {
-               addr->flags |= FCTX_ADDRINFO_MARK;
-               msg = "ignoring experimental address: ";
-       } else if (sa->type.sa.sa_family != AF_INET6) {
-               return;
-       } else if (IN6_IS_ADDR_V4MAPPED(&sa->type.sin6.sin6_addr)) {
-               addr->flags |= FCTX_ADDRINFO_MARK;
-               msg = "ignoring IPv6 mapped IPV4 address: ";
-       } else if (IN6_IS_ADDR_V4COMPAT(&sa->type.sin6.sin6_addr)) {
-               addr->flags |= FCTX_ADDRINFO_MARK;
-               msg = "ignoring IPv6 compatibility IPV4 address: ";
-       } else
-               return;
-
-       if (!isc_log_wouldlog(dns_lctx, ISC_LOG_DEBUG(3)))
-               return;
-
-       isc_netaddr_fromsockaddr(&na, sa);
-       isc_netaddr_format(&na, buf, sizeof(buf));
-       FCTXTRACE2(msg, buf);
+        isc_netaddr_t na;
+        char buf[ISC_NETADDR_FORMATSIZE];
+        isc_sockaddr_t *sa;
+        isc_boolean_t aborted = ISC_FALSE;
+        isc_boolean_t bogus;
+        dns_acl_t *blackhole;
+        isc_netaddr_t ipaddr;
+        dns_peer_t *peer = NULL;
+        dns_resolver_t *res;
+        const char *msg = NULL;
+
+        sa = &addr->sockaddr;
+
+        res = fctx->res;
+        isc_netaddr_fromsockaddr(&ipaddr, sa);
+        blackhole = dns_dispatchmgr_getblackhole(res->dispatchmgr);
+        (void) dns_peerlist_peerbyaddr(res->view->peers, &ipaddr, &peer);
+
+        if (blackhole != NULL) {
+                int match;
+
+                if (dns_acl_match(&ipaddr, NULL, blackhole,
+                                  &res->view->aclenv,
+                                  &match, NULL) == ISC_R_SUCCESS &&
+                    match > 0)
+                        aborted = ISC_TRUE;
+        }
+
+        if (peer != NULL &&
+            dns_peer_getbogus(peer, &bogus) == ISC_R_SUCCESS &&
+            bogus)
+                aborted = ISC_TRUE;
+
+        if (aborted) {
+                addr->flags |= FCTX_ADDRINFO_MARK;
+                msg = "ignoring blackholed / bogus server: ";
+        } else if (isc_sockaddr_ismulticast(sa)) {
+                addr->flags |= FCTX_ADDRINFO_MARK;
+                msg = "ignoring multicast address: ";
+        } else if (isc_sockaddr_isexperimental(sa)) {
+                addr->flags |= FCTX_ADDRINFO_MARK;
+                msg = "ignoring experimental address: ";
+        } else if (sa->type.sa.sa_family != AF_INET6) {
+                return;
+        } else if (IN6_IS_ADDR_V4MAPPED(&sa->type.sin6.sin6_addr)) {
+                addr->flags |= FCTX_ADDRINFO_MARK;
+                msg = "ignoring IPv6 mapped IPV4 address: ";
+        } else if (IN6_IS_ADDR_V4COMPAT(&sa->type.sin6.sin6_addr)) {
+                addr->flags |= FCTX_ADDRINFO_MARK;
+                msg = "ignoring IPv6 compatibility IPV4 address: ";
+        } else
+                return;
+
+        if (!isc_log_wouldlog(dns_lctx, ISC_LOG_DEBUG(3)))
+                return;
+
+        isc_netaddr_fromsockaddr(&na, sa);
+        isc_netaddr_format(&na, buf, sizeof(buf));
+        FCTXTRACE2(msg, buf);
 }
 
 static inline dns_adbaddrinfo_t *
 fctx_nextaddress(fetchctx_t *fctx) {
-       dns_adbfind_t *find, *start;
-       dns_adbaddrinfo_t *addrinfo;
-       dns_adbaddrinfo_t *faddrinfo;
-
-       /*
-        * Return the next untried address, if any.
-        */
-
-       /*
-        * Find the first unmarked forwarder (if any).
-        */
-       for (addrinfo = ISC_LIST_HEAD(fctx->forwaddrs);
-            addrinfo != NULL;
-            addrinfo = ISC_LIST_NEXT(addrinfo, publink)) {
-               if (!UNMARKED(addrinfo))
-                       continue;
-               possibly_mark(fctx, addrinfo);
-               if (UNMARKED(addrinfo)) {
-                       addrinfo->flags |= FCTX_ADDRINFO_MARK;
-                       fctx->find = NULL;
-                       return (addrinfo);
-               }
-       }
-
-       /*
-        * No forwarders.  Move to the next find.
-        */
-
-       fctx->attributes |= FCTX_ATTR_TRIEDFIND;
-
-       find = fctx->find;
-       if (find == NULL)
-               find = ISC_LIST_HEAD(fctx->finds);
-       else {
-               find = ISC_LIST_NEXT(find, publink);
-               if (find == NULL)
-                       find = ISC_LIST_HEAD(fctx->finds);
-       }
-
-       /*
-        * Find the first unmarked addrinfo.
-        */
-       addrinfo = NULL;
-       if (find != NULL) {
-               start = find;
-               do {
-                       for (addrinfo = ISC_LIST_HEAD(find->list);
-                            addrinfo != NULL;
-                            addrinfo = ISC_LIST_NEXT(addrinfo, publink)) {
-                               if (!UNMARKED(addrinfo))
-                                       continue;
-                               possibly_mark(fctx, addrinfo);
-                               if (UNMARKED(addrinfo)) {
-                                       addrinfo->flags |= FCTX_ADDRINFO_MARK;
-                                       break;
-                               }
-                       }
-                       if (addrinfo != NULL)
-                               break;
-                       find = ISC_LIST_NEXT(find, publink);
-                       if (find == NULL)
-                               find = ISC_LIST_HEAD(fctx->finds);
-               } while (find != start);
-       }
-
-       fctx->find = find;
-       if (addrinfo != NULL)
-               return (addrinfo);
-
-       /*
-        * No nameservers left.  Try alternates.
-        */
-
-       fctx->attributes |= FCTX_ATTR_TRIEDALT;
-
-       find = fctx->altfind;
-       if (find == NULL)
-               find = ISC_LIST_HEAD(fctx->altfinds);
-       else {
-               find = ISC_LIST_NEXT(find, publink);
-               if (find == NULL)
-                       find = ISC_LIST_HEAD(fctx->altfinds);
-       }
-
-       /*
-        * Find the first unmarked addrinfo.
-        */
-       addrinfo = NULL;
-       if (find != NULL) {
-               start = find;
-               do {
-                       for (addrinfo = ISC_LIST_HEAD(find->list);
-                            addrinfo != NULL;
-                            addrinfo = ISC_LIST_NEXT(addrinfo, publink)) {
-                               if (!UNMARKED(addrinfo))
-                                       continue;
-                               possibly_mark(fctx, addrinfo);
-                               if (UNMARKED(addrinfo)) {
-                                       addrinfo->flags |= FCTX_ADDRINFO_MARK;
-                                       break;
-                               }
-                       }
-                       if (addrinfo != NULL)
-                               break;
-                       find = ISC_LIST_NEXT(find, publink);
-                       if (find == NULL)
-                               find = ISC_LIST_HEAD(fctx->altfinds);
-               } while (find != start);
-       }
-
-       faddrinfo = addrinfo;
-
-       /*
-        * See if we have a better alternate server by address.
-        */
-
-       for (addrinfo = ISC_LIST_HEAD(fctx->altaddrs);
-            addrinfo != NULL;
-            addrinfo = ISC_LIST_NEXT(addrinfo, publink)) {
-               if (!UNMARKED(addrinfo))
-                       continue;
-               possibly_mark(fctx, addrinfo);
-               if (UNMARKED(addrinfo) &&
-                   (faddrinfo == NULL ||
-                    addrinfo->srtt < faddrinfo->srtt)) {
-                       if (faddrinfo != NULL)
-                               faddrinfo->flags &= ~FCTX_ADDRINFO_MARK;
-                       addrinfo->flags |= FCTX_ADDRINFO_MARK;
-                       break;
-               }
-       }
-
-       if (addrinfo == NULL) {
-               addrinfo = faddrinfo;
-               fctx->altfind = find;
-       }
-
-       return (addrinfo);
+        dns_adbfind_t *find, *start;
+        dns_adbaddrinfo_t *addrinfo;
+        dns_adbaddrinfo_t *faddrinfo;
+
+        /*
+         * Return the next untried address, if any.
+         */
+
+        /*
+         * Find the first unmarked forwarder (if any).
+         */
+        for (addrinfo = ISC_LIST_HEAD(fctx->forwaddrs);
+             addrinfo != NULL;
+             addrinfo = ISC_LIST_NEXT(addrinfo, publink)) {
+                if (!UNMARKED(addrinfo))
+                        continue;
+                possibly_mark(fctx, addrinfo);
+                if (UNMARKED(addrinfo)) {
+                        addrinfo->flags |= FCTX_ADDRINFO_MARK;
+                        fctx->find = NULL;
+                        return (addrinfo);
+                }
+        }
+
+        /*
+         * No forwarders.  Move to the next find.
+         */
+
+        fctx->attributes |= FCTX_ATTR_TRIEDFIND;
+
+        find = fctx->find;
+        if (find == NULL)
+                find = ISC_LIST_HEAD(fctx->finds);
+        else {
+                find = ISC_LIST_NEXT(find, publink);
+                if (find == NULL)
+                        find = ISC_LIST_HEAD(fctx->finds);
+        }
+
+        /*
+         * Find the first unmarked addrinfo.
+         */
+        addrinfo = NULL;
+        if (find != NULL) {
+                start = find;
+                do {
+                        for (addrinfo = ISC_LIST_HEAD(find->list);
+                             addrinfo != NULL;
+                             addrinfo = ISC_LIST_NEXT(addrinfo, publink)) {
+                                if (!UNMARKED(addrinfo))
+                                        continue;
+                                possibly_mark(fctx, addrinfo);
+                                if (UNMARKED(addrinfo)) {
+                                        addrinfo->flags |= FCTX_ADDRINFO_MARK;
+                                        break;
+                                }
+                        }
+                        if (addrinfo != NULL)
+                                break;
+                        find = ISC_LIST_NEXT(find, publink);
+                        if (find == NULL)
+                                find = ISC_LIST_HEAD(fctx->finds);
+                } while (find != start);
+        }
+
+        fctx->find = find;
+        if (addrinfo != NULL)
+                return (addrinfo);
+
+        /*
+         * No nameservers left.  Try alternates.
+         */
+
+        fctx->attributes |= FCTX_ATTR_TRIEDALT;
+
+        find = fctx->altfind;
+        if (find == NULL)
+                find = ISC_LIST_HEAD(fctx->altfinds);
+        else {
+                find = ISC_LIST_NEXT(find, publink);
+                if (find == NULL)
+                        find = ISC_LIST_HEAD(fctx->altfinds);
+        }
+
+        /*
+         * Find the first unmarked addrinfo.
+         */
+        addrinfo = NULL;
+        if (find != NULL) {
+                start = find;
+                do {
+                        for (addrinfo = ISC_LIST_HEAD(find->list);
+                             addrinfo != NULL;
+                             addrinfo = ISC_LIST_NEXT(addrinfo, publink)) {
+                                if (!UNMARKED(addrinfo))
+                                        continue;
+                                possibly_mark(fctx, addrinfo);
+                                if (UNMARKED(addrinfo)) {
+                                        addrinfo->flags |= FCTX_ADDRINFO_MARK;
+                                        break;
+                                }
+                        }
+                        if (addrinfo != NULL)
+                                break;
+                        find = ISC_LIST_NEXT(find, publink);
+                        if (find == NULL)
+                                find = ISC_LIST_HEAD(fctx->altfinds);
+                } while (find != start);
+        }
+
+        faddrinfo = addrinfo;
+
+        /*
+         * See if we have a better alternate server by address.
+         */
+
+        for (addrinfo = ISC_LIST_HEAD(fctx->altaddrs);
+             addrinfo != NULL;
+             addrinfo = ISC_LIST_NEXT(addrinfo, publink)) {
+                if (!UNMARKED(addrinfo))
+                        continue;
+                possibly_mark(fctx, addrinfo);
+                if (UNMARKED(addrinfo) &&
+                    (faddrinfo == NULL ||
+                     addrinfo->srtt < faddrinfo->srtt)) {
+                        if (faddrinfo != NULL)
+                                faddrinfo->flags &= ~FCTX_ADDRINFO_MARK;
+                        addrinfo->flags |= FCTX_ADDRINFO_MARK;
+                        break;
+                }
+        }
+
+        if (addrinfo == NULL) {
+                addrinfo = faddrinfo;
+                fctx->altfind = find;
+        }
+
+        return (addrinfo);
 }
 
 static void
 fctx_try(fetchctx_t *fctx) {
-       isc_result_t result;
-       dns_adbaddrinfo_t *addrinfo;
-
-       FCTXTRACE("try");
-
-       REQUIRE(!ADDRWAIT(fctx));
-
-       addrinfo = fctx_nextaddress(fctx);
-       if (addrinfo == NULL) {
-               /*
-                * We have no more addresses.  Start over.
-                */
-               fctx_cancelqueries(fctx, ISC_TRUE);
-               fctx_cleanupfinds(fctx);
-               fctx_cleanupaltfinds(fctx);
-               fctx_cleanupforwaddrs(fctx);
-               fctx_cleanupaltaddrs(fctx);
-               result = fctx_getaddresses(fctx);
-               if (result == DNS_R_WAIT) {
-                       /*
-                        * Sleep waiting for addresses.
-                        */
-                       FCTXTRACE("addrwait");
-                       fctx->attributes |= FCTX_ATTR_ADDRWAIT;
-                       return;
-               } else if (result != ISC_R_SUCCESS) {
-                       /*
-                        * Something bad happened.
-                        */
-                       fctx_done(fctx, result);
-                       return;
-               }
-
-               addrinfo = fctx_nextaddress(fctx);
-               /*
-                * While we may have addresses from the ADB, they
-                * might be bad ones.  In this case, return SERVFAIL.
-                */
-               if (addrinfo == NULL) {
-                       fctx_done(fctx, DNS_R_SERVFAIL);
-                       return;
-               }
-       }
-
-       result = fctx_query(fctx, addrinfo, fctx->options);
-       if (result != ISC_R_SUCCESS)
-               fctx_done(fctx, result);
+        isc_result_t result;
+        dns_adbaddrinfo_t *addrinfo;
+
+        FCTXTRACE("try");
+
+        REQUIRE(!ADDRWAIT(fctx));
+
+        addrinfo = fctx_nextaddress(fctx);
+        if (addrinfo == NULL) {
+                /*
+                 * We have no more addresses.  Start over.
+                 */
+                fctx_cancelqueries(fctx, ISC_TRUE);
+                fctx_cleanupfinds(fctx);
+                fctx_cleanupaltfinds(fctx);
+                fctx_cleanupforwaddrs(fctx);
+                fctx_cleanupaltaddrs(fctx);
+                result = fctx_getaddresses(fctx);
+                if (result == DNS_R_WAIT) {
+                        /*
+                         * Sleep waiting for addresses.
+                         */
+                        FCTXTRACE("addrwait");
+                        fctx->attributes |= FCTX_ATTR_ADDRWAIT;
+                        return;
+                } else if (result != ISC_R_SUCCESS) {
+                        /*
+                         * Something bad happened.
+                         */
+                        fctx_done(fctx, result);
+                        return;
+                }
+
+                addrinfo = fctx_nextaddress(fctx);
+                /*
+                 * While we may have addresses from the ADB, they
+                 * might be bad ones.  In this case, return SERVFAIL.
+                 */
+                if (addrinfo == NULL) {
+                        fctx_done(fctx, DNS_R_SERVFAIL);
+                        return;
+                }
+        }
+
+        result = fctx_query(fctx, addrinfo, fctx->options);
+        if (result != ISC_R_SUCCESS)
+                fctx_done(fctx, result);
 }
 
 static isc_boolean_t
 fctx_destroy(fetchctx_t *fctx) {
-       dns_resolver_t *res;
-       unsigned int bucketnum;
-       isc_sockaddr_t *sa, *next_sa;
-
-       /*
-        * Caller must be holding the bucket lock.
-        */
-
-       REQUIRE(VALID_FCTX(fctx));
-       REQUIRE(fctx->state == fetchstate_done ||
-               fctx->state == fetchstate_init);
-       REQUIRE(ISC_LIST_EMPTY(fctx->events));
-       REQUIRE(ISC_LIST_EMPTY(fctx->queries));
-       REQUIRE(ISC_LIST_EMPTY(fctx->finds));
-       REQUIRE(ISC_LIST_EMPTY(fctx->altfinds));
-       REQUIRE(fctx->pending == 0);
-       REQUIRE(fctx->references == 0);
-       REQUIRE(ISC_LIST_EMPTY(fctx->validators));
-
-       FCTXTRACE("destroy");
-
-       res = fctx->res;
-       bucketnum = fctx->bucketnum;
-
-       ISC_LIST_UNLINK(res->buckets[bucketnum].fctxs, fctx, link);
-
-       /*
-        * Free bad.
-        */
-       for (sa = ISC_LIST_HEAD(fctx->bad);
-            sa != NULL;
-            sa = next_sa) {
-               next_sa = ISC_LIST_NEXT(sa, link);
-               ISC_LIST_UNLINK(fctx->bad, sa, link);
-               isc_mem_put(res->buckets[bucketnum].mctx, sa, sizeof(*sa));
-       }
-
-       for (sa = ISC_LIST_HEAD(fctx->edns);
-            sa != NULL;
-            sa = next_sa) {
-               next_sa = ISC_LIST_NEXT(sa, link);
-               ISC_LIST_UNLINK(fctx->edns, sa, link);
-               isc_mem_put(res->buckets[bucketnum].mctx, sa, sizeof(*sa));
-       }
-
-       for (sa = ISC_LIST_HEAD(fctx->edns512);
-            sa != NULL;
-            sa = next_sa) {
-               next_sa = ISC_LIST_NEXT(sa, link);
-               ISC_LIST_UNLINK(fctx->edns512, sa, link);
-               isc_mem_put(res->buckets[bucketnum].mctx, sa, sizeof(*sa));
-       }
-
-       isc_timer_detach(&fctx->timer);
-       dns_message_destroy(&fctx->rmessage);
-       dns_message_destroy(&fctx->qmessage);
-       if (dns_name_countlabels(&fctx->domain) > 0)
-               dns_name_free(&fctx->domain, res->buckets[bucketnum].mctx);
-       if (dns_rdataset_isassociated(&fctx->nameservers))
-               dns_rdataset_disassociate(&fctx->nameservers);
-       dns_name_free(&fctx->name, res->buckets[bucketnum].mctx);
-       dns_db_detach(&fctx->cache);
-       dns_adb_detach(&fctx->adb);
-       isc_mem_free(res->buckets[bucketnum].mctx, fctx->info);
-       isc_mem_put(res->buckets[bucketnum].mctx, fctx, sizeof(*fctx));
-
-       LOCK(&res->nlock);
-       res->nfctx--;
-       UNLOCK(&res->nlock);
-
-       if (res->buckets[bucketnum].exiting &&
-           ISC_LIST_EMPTY(res->buckets[bucketnum].fctxs))
-               return (ISC_TRUE);
-
-       return (ISC_FALSE);
+        dns_resolver_t *res;
+        unsigned int bucketnum;
+        isc_sockaddr_t *sa, *next_sa;
+
+        /*
+         * Caller must be holding the bucket lock.
+         */
+
+        REQUIRE(VALID_FCTX(fctx));
+        REQUIRE(fctx->state == fetchstate_done ||
+                fctx->state == fetchstate_init);
+        REQUIRE(ISC_LIST_EMPTY(fctx->events));
+        REQUIRE(ISC_LIST_EMPTY(fctx->queries));
+        REQUIRE(ISC_LIST_EMPTY(fctx->finds));
+        REQUIRE(ISC_LIST_EMPTY(fctx->altfinds));
+        REQUIRE(fctx->pending == 0);
+        REQUIRE(fctx->references == 0);
+        REQUIRE(ISC_LIST_EMPTY(fctx->validators));
+
+        FCTXTRACE("destroy");
+
+        res = fctx->res;
+        bucketnum = fctx->bucketnum;
+
+        ISC_LIST_UNLINK(res->buckets[bucketnum].fctxs, fctx, link);
+
+        /*
+         * Free bad.
+         */
+        for (sa = ISC_LIST_HEAD(fctx->bad);
+             sa != NULL;
+             sa = next_sa) {
+                next_sa = ISC_LIST_NEXT(sa, link);
+                ISC_LIST_UNLINK(fctx->bad, sa, link);
+                isc_mem_put(res->buckets[bucketnum].mctx, sa, sizeof(*sa));
+        }
+
+        for (sa = ISC_LIST_HEAD(fctx->edns);
+             sa != NULL;
+             sa = next_sa) {
+                next_sa = ISC_LIST_NEXT(sa, link);
+                ISC_LIST_UNLINK(fctx->edns, sa, link);
+                isc_mem_put(res->buckets[bucketnum].mctx, sa, sizeof(*sa));
+        }
+
+        for (sa = ISC_LIST_HEAD(fctx->edns512);
+             sa != NULL;
+             sa = next_sa) {
+                next_sa = ISC_LIST_NEXT(sa, link);
+                ISC_LIST_UNLINK(fctx->edns512, sa, link);
+                isc_mem_put(res->buckets[bucketnum].mctx, sa, sizeof(*sa));
+        }
+
+        isc_timer_detach(&fctx->timer);
+        dns_message_destroy(&fctx->rmessage);
+        dns_message_destroy(&fctx->qmessage);
+        if (dns_name_countlabels(&fctx->domain) > 0)
+                dns_name_free(&fctx->domain, res->buckets[bucketnum].mctx);
+        if (dns_rdataset_isassociated(&fctx->nameservers))
+                dns_rdataset_disassociate(&fctx->nameservers);
+        dns_name_free(&fctx->name, res->buckets[bucketnum].mctx);
+        dns_db_detach(&fctx->cache);
+        dns_adb_detach(&fctx->adb);
+        isc_mem_free(res->buckets[bucketnum].mctx, fctx->info);
+        isc_mem_put(res->buckets[bucketnum].mctx, fctx, sizeof(*fctx));
+
+        LOCK(&res->nlock);
+        res->nfctx--;
+        UNLOCK(&res->nlock);
+
+        if (res->buckets[bucketnum].exiting &&
+            ISC_LIST_EMPTY(res->buckets[bucketnum].fctxs))
+                return (ISC_TRUE);
+
+        return (ISC_FALSE);
 }
 
 /*
@@ -2720,209 +2757,209 @@ fctx_destroy(fetchctx_t *fctx) {
 
 static void
 fctx_timeout(isc_task_t *task, isc_event_t *event) {
-       fetchctx_t *fctx = event->ev_arg;
-
-       REQUIRE(VALID_FCTX(fctx));
-
-       UNUSED(task);
-
-       FCTXTRACE("timeout");
-
-       if (event->ev_type == ISC_TIMEREVENT_LIFE) {
-               fctx_done(fctx, ISC_R_TIMEDOUT);
-       } else {
-               isc_result_t result;
-
-               fctx->timeouts++;
-               /*
-                * We could cancel the running queries here, or we could let
-                * them keep going.  Right now we choose the latter...
-                */
-               fctx->attributes &= ~FCTX_ATTR_ADDRWAIT;
-               /*
-                * Our timer has triggered.  Reestablish the fctx lifetime
-                * timer.
-                */
-               result = fctx_starttimer(fctx);
-               if (result != ISC_R_SUCCESS)
-                       fctx_done(fctx, result);
-               else
-                       /*
-                        * Keep trying.
-                        */
-                       fctx_try(fctx);
-       }
-
-       isc_event_free(&event);
+        fetchctx_t *fctx = event->ev_arg;
+
+        REQUIRE(VALID_FCTX(fctx));
+
+        UNUSED(task);
+
+        FCTXTRACE("timeout");
+
+        if (event->ev_type == ISC_TIMEREVENT_LIFE) {
+                fctx_done(fctx, ISC_R_TIMEDOUT);
+        } else {
+                isc_result_t result;
+
+                fctx->timeouts++;
+                /*
+                 * We could cancel the running queries here, or we could let
+                 * them keep going.  Right now we choose the latter...
+                 */
+                fctx->attributes &= ~FCTX_ATTR_ADDRWAIT;
+                /*
+                 * Our timer has triggered.  Reestablish the fctx lifetime
+                 * timer.
+                 */
+                result = fctx_starttimer(fctx);
+                if (result != ISC_R_SUCCESS)
+                        fctx_done(fctx, result);
+                else
+                        /*
+                         * Keep trying.
+                         */
+                        fctx_try(fctx);
+        }
+
+        isc_event_free(&event);
 }
 
 static void
 fctx_shutdown(fetchctx_t *fctx) {
-       isc_event_t *cevent;
-
-       /*
-        * Start the shutdown process for fctx, if it isn't already underway.
-        */
-
-       FCTXTRACE("shutdown");
-
-       /*
-        * The caller must be holding the appropriate bucket lock.
-        */
-
-       if (fctx->want_shutdown)
-               return;
-
-       fctx->want_shutdown = ISC_TRUE;
-
-       /*
-        * Unless we're still initializing (in which case the
-        * control event is still outstanding), we need to post
-        * the control event to tell the fetch we want it to
-        * exit.
-        */
-       if (fctx->state != fetchstate_init) {
-               cevent = &fctx->control_event;
-               isc_task_send(fctx->res->buckets[fctx->bucketnum].task,
-                             &cevent);
-       }
+        isc_event_t *cevent;
+
+        /*
+         * Start the shutdown process for fctx, if it isn't already underway.
+         */
+
+        FCTXTRACE("shutdown");
+
+        /*
+         * The caller must be holding the appropriate bucket lock.
+         */
+
+        if (fctx->want_shutdown)
+                return;
+
+        fctx->want_shutdown = ISC_TRUE;
+
+        /*
+         * Unless we're still initializing (in which case the
+         * control event is still outstanding), we need to post
+         * the control event to tell the fetch we want it to
+         * exit.
+         */
+        if (fctx->state != fetchstate_init) {
+                cevent = &fctx->control_event;
+                isc_task_send(fctx->res->buckets[fctx->bucketnum].task,
+                              &cevent);
+        }
 }
 
 static void
 fctx_doshutdown(isc_task_t *task, isc_event_t *event) {
-       fetchctx_t *fctx = event->ev_arg;
-       isc_boolean_t bucket_empty = ISC_FALSE;
-       dns_resolver_t *res;
-       unsigned int bucketnum;
-       dns_validator_t *validator;
-
-       REQUIRE(VALID_FCTX(fctx));
-
-       UNUSED(task);
-
-       res = fctx->res;
-       bucketnum = fctx->bucketnum;
-
-       FCTXTRACE("doshutdown");
-
-       /*
-        * An fctx that is shutting down is no longer in ADDRWAIT mode.
-        */
-       fctx->attributes &= ~FCTX_ATTR_ADDRWAIT;
-
-       /*
-        * Cancel all pending validators.  Note that this must be done
-        * without the bucket lock held, since that could cause deadlock.
-        */
-       validator = ISC_LIST_HEAD(fctx->validators);
-       while (validator != NULL) {
-               dns_validator_cancel(validator);
-               validator = ISC_LIST_NEXT(validator, link);
-       }
-       
-       if (fctx->nsfetch != NULL)
-               dns_resolver_cancelfetch(fctx->nsfetch);
-
-       /*
-        * Shut down anything that is still running on behalf of this
-        * fetch.  To avoid deadlock with the ADB, we must do this
-        * before we lock the bucket lock.
-        */
-       fctx_stopeverything(fctx, ISC_FALSE);
-
-       LOCK(&res->buckets[bucketnum].lock);
-
-       fctx->attributes |= FCTX_ATTR_SHUTTINGDOWN;
-
-       INSIST(fctx->state == fetchstate_active ||
-              fctx->state == fetchstate_done);
-       INSIST(fctx->want_shutdown);
-
-       if (fctx->state != fetchstate_done) {
-               fctx->state = fetchstate_done;
-               fctx_sendevents(fctx, ISC_R_CANCELED);
-       }
-
-       if (fctx->references == 0 && fctx->pending == 0 &&
-           fctx->nqueries == 0 && ISC_LIST_EMPTY(fctx->validators))
-               bucket_empty = fctx_destroy(fctx);
-
-       UNLOCK(&res->buckets[bucketnum].lock);
-
-       if (bucket_empty)
-               empty_bucket(res);
+        fetchctx_t *fctx = event->ev_arg;
+        isc_boolean_t bucket_empty = ISC_FALSE;
+        dns_resolver_t *res;
+        unsigned int bucketnum;
+        dns_validator_t *validator;
+
+        REQUIRE(VALID_FCTX(fctx));
+
+        UNUSED(task);
+
+        res = fctx->res;
+        bucketnum = fctx->bucketnum;
+
+        FCTXTRACE("doshutdown");
+
+        /*
+         * An fctx that is shutting down is no longer in ADDRWAIT mode.
+         */
+        fctx->attributes &= ~FCTX_ATTR_ADDRWAIT;
+
+        /*
+         * Cancel all pending validators.  Note that this must be done
+         * without the bucket lock held, since that could cause deadlock.
+         */
+        validator = ISC_LIST_HEAD(fctx->validators);
+        while (validator != NULL) {
+                dns_validator_cancel(validator);
+                validator = ISC_LIST_NEXT(validator, link);
+        }
+
+        if (fctx->nsfetch != NULL)
+                dns_resolver_cancelfetch(fctx->nsfetch);
+
+        /*
+         * Shut down anything that is still running on behalf of this
+         * fetch.  To avoid deadlock with the ADB, we must do this
+         * before we lock the bucket lock.
+         */
+        fctx_stopeverything(fctx, ISC_FALSE);
+
+        LOCK(&res->buckets[bucketnum].lock);
+
+        fctx->attributes |= FCTX_ATTR_SHUTTINGDOWN;
+
+        INSIST(fctx->state == fetchstate_active ||
+               fctx->state == fetchstate_done);
+        INSIST(fctx->want_shutdown);
+
+        if (fctx->state != fetchstate_done) {
+                fctx->state = fetchstate_done;
+                fctx_sendevents(fctx, ISC_R_CANCELED);
+        }
+
+        if (fctx->references == 0 && fctx->pending == 0 &&
+            fctx->nqueries == 0 && ISC_LIST_EMPTY(fctx->validators))
+                bucket_empty = fctx_destroy(fctx);
+
+        UNLOCK(&res->buckets[bucketnum].lock);
+
+        if (bucket_empty)
+                empty_bucket(res);
 }
 
 static void
 fctx_start(isc_task_t *task, isc_event_t *event) {
-       fetchctx_t *fctx = event->ev_arg;
-       isc_boolean_t done = ISC_FALSE, bucket_empty = ISC_FALSE;
-       dns_resolver_t *res;
-       unsigned int bucketnum;
-
-       REQUIRE(VALID_FCTX(fctx));
-
-       UNUSED(task);
-
-       res = fctx->res;
-       bucketnum = fctx->bucketnum;
-
-       FCTXTRACE("start");
-
-       LOCK(&res->buckets[bucketnum].lock);
-
-       INSIST(fctx->state == fetchstate_init);
-       if (fctx->want_shutdown) {
-               /*
-                * We haven't started this fctx yet, and we've been requested
-                * to shut it down.
-                */
-               fctx->attributes |= FCTX_ATTR_SHUTTINGDOWN;
-               fctx->state = fetchstate_done;
-               fctx_sendevents(fctx, ISC_R_CANCELED);
-               /*
-                * Since we haven't started, we INSIST that we have no
-                * pending ADB finds and no pending validations.
-                */
-               INSIST(fctx->pending == 0);
-               INSIST(fctx->nqueries == 0);
-               INSIST(ISC_LIST_EMPTY(fctx->validators));
-               if (fctx->references == 0) {
-                       /*
-                        * It's now safe to destroy this fctx.
-                        */
-                       bucket_empty = fctx_destroy(fctx);
-               }
-               done = ISC_TRUE;
-       } else {
-               /*
-                * Normal fctx startup.
-                */
-               fctx->state = fetchstate_active;
-               /*
-                * Reset the control event for later use in shutting down
-                * the fctx.
-                */
-               ISC_EVENT_INIT(event, sizeof(*event), 0, NULL,
-                              DNS_EVENT_FETCHCONTROL, fctx_doshutdown, fctx,
-                              NULL, NULL, NULL);
-       }
-
-       UNLOCK(&res->buckets[bucketnum].lock);
-
-       if (!done) {
-               isc_result_t result;
-
-               /*
-                * All is well.  Start working on the fetch.
-                */
-               result = fctx_starttimer(fctx);
-               if (result != ISC_R_SUCCESS)
-                       fctx_done(fctx, result);
-               else
-                       fctx_try(fctx);
-       } else if (bucket_empty)
-               empty_bucket(res);
+        fetchctx_t *fctx = event->ev_arg;
+        isc_boolean_t done = ISC_FALSE, bucket_empty = ISC_FALSE;
+        dns_resolver_t *res;
+        unsigned int bucketnum;
+
+        REQUIRE(VALID_FCTX(fctx));
+
+        UNUSED(task);
+
+        res = fctx->res;
+        bucketnum = fctx->bucketnum;
+
+        FCTXTRACE("start");
+
+        LOCK(&res->buckets[bucketnum].lock);
+
+        INSIST(fctx->state == fetchstate_init);
+        if (fctx->want_shutdown) {
+                /*
+                 * We haven't started this fctx yet, and we've been requested
+                 * to shut it down.
+                 */
+                fctx->attributes |= FCTX_ATTR_SHUTTINGDOWN;
+                fctx->state = fetchstate_done;
+                fctx_sendevents(fctx, ISC_R_CANCELED);
+                /*
+                 * Since we haven't started, we INSIST that we have no
+                 * pending ADB finds and no pending validations.
+                 */
+                INSIST(fctx->pending == 0);
+                INSIST(fctx->nqueries == 0);
+                INSIST(ISC_LIST_EMPTY(fctx->validators));
+                if (fctx->references == 0) {
+                        /*
+                         * It's now safe to destroy this fctx.
+                         */
+                        bucket_empty = fctx_destroy(fctx);
+                }
+                done = ISC_TRUE;
+        } else {
+                /*
+                 * Normal fctx startup.
+                 */
+                fctx->state = fetchstate_active;
+                /*
+                 * Reset the control event for later use in shutting down
+                 * the fctx.
+                 */
+                ISC_EVENT_INIT(event, sizeof(*event), 0, NULL,
+                               DNS_EVENT_FETCHCONTROL, fctx_doshutdown, fctx,
+                               NULL, NULL, NULL);
+        }
+
+        UNLOCK(&res->buckets[bucketnum].lock);
+
+        if (!done) {
+                isc_result_t result;
+
+                /*
+                 * All is well.  Start working on the fetch.
+                 */
+                result = fctx_starttimer(fctx);
+                if (result != ISC_R_SUCCESS)
+                        fctx_done(fctx, result);
+                else
+                        fctx_try(fctx);
+        } else if (bucket_empty)
+                empty_bucket(res);
 }
 
 /*
@@ -2931,295 +2968,295 @@ fctx_start(isc_task_t *task, isc_event_t *event) {
 
 static inline isc_result_t
 fctx_join(fetchctx_t *fctx, isc_task_t *task, isc_sockaddr_t *client,
-         dns_messageid_t id, isc_taskaction_t action, void *arg,
-         dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
-         dns_fetch_t *fetch)
+          dns_messageid_t id, isc_taskaction_t action, void *arg,
+          dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
+          dns_fetch_t *fetch)
 {
-       isc_task_t *clone;
-       dns_fetchevent_t *event;
-
-       FCTXTRACE("join");
-
-       /*
-        * We store the task we're going to send this event to in the
-        * sender field.  We'll make the fetch the sender when we actually
-        * send the event.
-        */
-       clone = NULL;
-       isc_task_attach(task, &clone);
-       event = (dns_fetchevent_t *)
-               isc_event_allocate(fctx->res->mctx, clone, DNS_EVENT_FETCHDONE,
-                                  action, arg, sizeof(*event));
-       if (event == NULL) {
-               isc_task_detach(&clone);
-               return (ISC_R_NOMEMORY);
-       }
-       event->result = DNS_R_SERVFAIL;
-       event->qtype = fctx->type;
-       event->db = NULL;
-       event->node = NULL;
-       event->rdataset = rdataset;
-       event->sigrdataset = sigrdataset;
-       event->fetch = fetch;
-       event->client = client;
-       event->id = id;
-       dns_fixedname_init(&event->foundname);
-
-       /*
-        * Make sure that we can store the sigrdataset in the
-        * first event if it is needed by any of the events.
-        */
-       if (event->sigrdataset != NULL)
-               ISC_LIST_PREPEND(fctx->events, event, ev_link);
-       else
-               ISC_LIST_APPEND(fctx->events, event, ev_link);
-       fctx->references++;
-
-       fetch->magic = DNS_FETCH_MAGIC;
-       fetch->private = fctx;
-
-       return (ISC_R_SUCCESS);
+        isc_task_t *clone;
+        dns_fetchevent_t *event;
+
+        FCTXTRACE("join");
+
+        /*
+         * We store the task we're going to send this event to in the
+         * sender field.  We'll make the fetch the sender when we actually
+         * send the event.
+         */
+        clone = NULL;
+        isc_task_attach(task, &clone);
+        event = (dns_fetchevent_t *)
+                isc_event_allocate(fctx->res->mctx, clone, DNS_EVENT_FETCHDONE,
+                                   action, arg, sizeof(*event));
+        if (event == NULL) {
+                isc_task_detach(&clone);
+                return (ISC_R_NOMEMORY);
+        }
+        event->result = DNS_R_SERVFAIL;
+        event->qtype = fctx->type;
+        event->db = NULL;
+        event->node = NULL;
+        event->rdataset = rdataset;
+        event->sigrdataset = sigrdataset;
+        event->fetch = fetch;
+        event->client = client;
+        event->id = id;
+        dns_fixedname_init(&event->foundname);
+
+        /*
+         * Make sure that we can store the sigrdataset in the
+         * first event if it is needed by any of the events.
+         */
+        if (event->sigrdataset != NULL)
+                ISC_LIST_PREPEND(fctx->events, event, ev_link);
+        else
+                ISC_LIST_APPEND(fctx->events, event, ev_link);
+        fctx->references++;
+
+        fetch->magic = DNS_FETCH_MAGIC;
+        fetch->private = fctx;
+
+        return (ISC_R_SUCCESS);
 }
 
 static isc_result_t
 fctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type,
-           dns_name_t *domain, dns_rdataset_t *nameservers,
-           unsigned int options, unsigned int bucketnum, fetchctx_t **fctxp)
+            dns_name_t *domain, dns_rdataset_t *nameservers,
+            unsigned int options, unsigned int bucketnum, fetchctx_t **fctxp)
 {
-       fetchctx_t *fctx;
-       isc_result_t result;
-       isc_result_t iresult;
-       isc_interval_t interval;
-       dns_fixedname_t fixed;
-       unsigned int findoptions = 0;
-       char buf[DNS_NAME_FORMATSIZE + DNS_RDATATYPE_FORMATSIZE];
-       char typebuf[DNS_RDATATYPE_FORMATSIZE];
-       dns_name_t suffix;
-
-       /*
-        * Caller must be holding the lock for bucket number 'bucketnum'.
-        */
-       REQUIRE(fctxp != NULL && *fctxp == NULL);
-
-       fctx = isc_mem_get(res->buckets[bucketnum].mctx, sizeof(*fctx));
-       if (fctx == NULL)
-               return (ISC_R_NOMEMORY);
-       dns_name_format(name, buf, sizeof(buf));
-       dns_rdatatype_format(type, typebuf, sizeof(typebuf));
-       strcat(buf, "/");       /* checked */
-       strcat(buf, typebuf);   /* checked */
-       fctx->info = isc_mem_strdup(res->buckets[bucketnum].mctx, buf);
-       if (fctx->info == NULL) {
-               result = ISC_R_NOMEMORY;
-               goto cleanup_fetch;
-       }
-       FCTXTRACE("create");
-       dns_name_init(&fctx->name, NULL);
-       result = dns_name_dup(name, res->buckets[bucketnum].mctx, &fctx->name);
-       if (result != ISC_R_SUCCESS)
-               goto cleanup_info;
-       dns_name_init(&fctx->domain, NULL);
-       dns_rdataset_init(&fctx->nameservers);
-
-       fctx->type = type;
-       fctx->options = options;
-       /*
-        * Note!  We do not attach to the task.  We are relying on the
-        * resolver to ensure that this task doesn't go away while we are
-        * using it.
-        */
-       fctx->res = res;
-       fctx->references = 0;
-       fctx->bucketnum = bucketnum;
-       fctx->state = fetchstate_init;
-       fctx->want_shutdown = ISC_FALSE;
-       fctx->cloned = ISC_FALSE;
-       ISC_LIST_INIT(fctx->queries);
-       ISC_LIST_INIT(fctx->finds);
-       ISC_LIST_INIT(fctx->altfinds);
-       ISC_LIST_INIT(fctx->forwaddrs);
-       ISC_LIST_INIT(fctx->altaddrs);
-       ISC_LIST_INIT(fctx->forwarders);
-       fctx->fwdpolicy = dns_fwdpolicy_none;
-       ISC_LIST_INIT(fctx->bad);
-       ISC_LIST_INIT(fctx->edns);
-       ISC_LIST_INIT(fctx->edns512);
-       ISC_LIST_INIT(fctx->validators);
-       fctx->validator = NULL;
-       fctx->find = NULL;
-       fctx->altfind = NULL;
-       fctx->pending = 0;
-       fctx->restarts = 0;
-       fctx->timeouts = 0;
-       fctx->attributes = 0;
-       fctx->spilled = ISC_FALSE;
-       fctx->nqueries = 0;
-
-       dns_name_init(&fctx->nsname, NULL);
-       fctx->nsfetch = NULL;
-       dns_rdataset_init(&fctx->nsrrset);
-
-       if (domain == NULL) {
-               dns_forwarders_t *forwarders = NULL;
-               unsigned int labels;
-
-               /*
-                * DS records are found in the parent server.
-                * Strip label to get the correct forwarder (if any).
-                */
-               if (fctx->type == dns_rdatatype_ds &&
-                   dns_name_countlabels(name) > 1) {
-                       dns_name_init(&suffix, NULL);
-                       labels = dns_name_countlabels(name);
-                       dns_name_getlabelsequence(name, 1, labels - 1, &suffix);
-                       name = &suffix;
-               }
-               dns_fixedname_init(&fixed);
-               domain = dns_fixedname_name(&fixed);
-               result = dns_fwdtable_find2(fctx->res->view->fwdtable, name,
-                                           domain, &forwarders);
-               if (result == ISC_R_SUCCESS)
-                       fctx->fwdpolicy = forwarders->fwdpolicy;
-
-               if (fctx->fwdpolicy != dns_fwdpolicy_only) {
-                       /*
-                        * The caller didn't supply a query domain and
-                        * nameservers, and we're not in forward-only mode,
-                        * so find the best nameservers to use.
-                        */
-                       if (dns_rdatatype_atparent(type))
-                               findoptions |= DNS_DBFIND_NOEXACT;
-                       result = dns_view_findzonecut(res->view, name, domain,
-                                                     0, findoptions, ISC_TRUE,
-                                                     &fctx->nameservers,
-                                                     NULL);
-                       if (result != ISC_R_SUCCESS)
-                               goto cleanup_name;
-                       result = dns_name_dup(domain,
-                                             res->buckets[bucketnum].mctx,
-                                             &fctx->domain);
-                       if (result != ISC_R_SUCCESS) {
-                               dns_rdataset_disassociate(&fctx->nameservers);
-                               goto cleanup_name;
-                       }
-               } else {
-                       /*
-                        * We're in forward-only mode.  Set the query domain.
-                        */
-                       result = dns_name_dup(domain,
-                                             res->buckets[bucketnum].mctx,
-                                             &fctx->domain);
-                       if (result != ISC_R_SUCCESS)
-                               goto cleanup_name;
-               }
-       } else {
-               result = dns_name_dup(domain,
-                                     res->buckets[bucketnum].mctx,
-                                     &fctx->domain);
-               if (result != ISC_R_SUCCESS)
-                       goto cleanup_name;
-               dns_rdataset_clone(nameservers, &fctx->nameservers);
-       }
-
-       INSIST(dns_name_issubdomain(&fctx->name, &fctx->domain));
-
-       fctx->qmessage = NULL;
-       result = dns_message_create(res->buckets[bucketnum].mctx,
-                                   DNS_MESSAGE_INTENTRENDER,
-                                   &fctx->qmessage);
-
-       if (result != ISC_R_SUCCESS)
-               goto cleanup_domain;
-
-       fctx->rmessage = NULL;
-       result = dns_message_create(res->buckets[bucketnum].mctx,
-                                   DNS_MESSAGE_INTENTPARSE,
-                                   &fctx->rmessage);
-
-       if (result != ISC_R_SUCCESS)
-               goto cleanup_qmessage;
-
-       /*
-        * Compute an expiration time for the entire fetch.
-        */
-       isc_interval_set(&interval, 30, 0);             /* XXXRTH constant */
-       iresult = isc_time_nowplusinterval(&fctx->expires, &interval);
-       if (iresult != ISC_R_SUCCESS) {
-               UNEXPECTED_ERROR(__FILE__, __LINE__,
-                                "isc_time_nowplusinterval: %s",
-                                isc_result_totext(iresult));
-               result = ISC_R_UNEXPECTED;
-               goto cleanup_rmessage;
-       }
-
-       /*
-        * Default retry interval initialization.  We set the interval now
-        * mostly so it won't be uninitialized.  It will be set to the
-        * correct value before a query is issued.
-        */
-       isc_interval_set(&fctx->interval, 2, 0);
-
-       /*
-        * Create an inactive timer.  It will be made active when the fetch
-        * is actually started.
-        */
-       fctx->timer = NULL;
-       iresult = isc_timer_create(res->timermgr, isc_timertype_inactive,
-                                  NULL, NULL,
-                                  res->buckets[bucketnum].task, fctx_timeout,
-                                  fctx, &fctx->timer);
-       if (iresult != ISC_R_SUCCESS) {
-               UNEXPECTED_ERROR(__FILE__, __LINE__,
-                                "isc_timer_create: %s",
-                                isc_result_totext(iresult));
-               result = ISC_R_UNEXPECTED;
-               goto cleanup_rmessage;
-       }
-
-       /*
-        * Attach to the view's cache and adb.
-        */
-       fctx->cache = NULL;
-       dns_db_attach(res->view->cachedb, &fctx->cache);
-       fctx->adb = NULL;
-       dns_adb_attach(res->view->adb, &fctx->adb);
-
-       ISC_LIST_INIT(fctx->events);
-       ISC_LINK_INIT(fctx, link);
-       fctx->magic = FCTX_MAGIC;
-
-       ISC_LIST_APPEND(res->buckets[bucketnum].fctxs, fctx, link);
-
-       LOCK(&res->nlock);
-       res->nfctx++;
-       UNLOCK(&res->nlock);
-
-       *fctxp = fctx;
-
-       return (ISC_R_SUCCESS);
+        fetchctx_t *fctx;
+        isc_result_t result;
+        isc_result_t iresult;
+        isc_interval_t interval;
+        dns_fixedname_t fixed;
+        unsigned int findoptions = 0;
+        char buf[DNS_NAME_FORMATSIZE + DNS_RDATATYPE_FORMATSIZE];
+        char typebuf[DNS_RDATATYPE_FORMATSIZE];
+        dns_name_t suffix;
+
+        /*
+         * Caller must be holding the lock for bucket number 'bucketnum'.
+         */
+        REQUIRE(fctxp != NULL && *fctxp == NULL);
+
+        fctx = isc_mem_get(res->buckets[bucketnum].mctx, sizeof(*fctx));
+        if (fctx == NULL)
+                return (ISC_R_NOMEMORY);
+        dns_name_format(name, buf, sizeof(buf));
+        dns_rdatatype_format(type, typebuf, sizeof(typebuf));
+        strcat(buf, "/");       /* checked */
+        strcat(buf, typebuf);   /* checked */
+        fctx->info = isc_mem_strdup(res->buckets[bucketnum].mctx, buf);
+        if (fctx->info == NULL) {
+                result = ISC_R_NOMEMORY;
+                goto cleanup_fetch;
+        }
+        FCTXTRACE("create");
+        dns_name_init(&fctx->name, NULL);
+        result = dns_name_dup(name, res->buckets[bucketnum].mctx, &fctx->name);
+        if (result != ISC_R_SUCCESS)
+                goto cleanup_info;
+        dns_name_init(&fctx->domain, NULL);
+        dns_rdataset_init(&fctx->nameservers);
+
+        fctx->type = type;
+        fctx->options = options;
+        /*
+         * Note!  We do not attach to the task.  We are relying on the
+         * resolver to ensure that this task doesn't go away while we are
+         * using it.
+         */
+        fctx->res = res;
+        fctx->references = 0;
+        fctx->bucketnum = bucketnum;
+        fctx->state = fetchstate_init;
+        fctx->want_shutdown = ISC_FALSE;
+        fctx->cloned = ISC_FALSE;
+        ISC_LIST_INIT(fctx->queries);
+        ISC_LIST_INIT(fctx->finds);
+        ISC_LIST_INIT(fctx->altfinds);
+        ISC_LIST_INIT(fctx->forwaddrs);
+        ISC_LIST_INIT(fctx->altaddrs);
+        ISC_LIST_INIT(fctx->forwarders);
+        fctx->fwdpolicy = dns_fwdpolicy_none;
+        ISC_LIST_INIT(fctx->bad);
+        ISC_LIST_INIT(fctx->edns);
+        ISC_LIST_INIT(fctx->edns512);
+        ISC_LIST_INIT(fctx->validators);
+        fctx->validator = NULL;
+        fctx->find = NULL;
+        fctx->altfind = NULL;
+        fctx->pending = 0;
+        fctx->restarts = 0;
+        fctx->timeouts = 0;
+        fctx->attributes = 0;
+        fctx->spilled = ISC_FALSE;
+        fctx->nqueries = 0;
+
+        dns_name_init(&fctx->nsname, NULL);
+        fctx->nsfetch = NULL;
+        dns_rdataset_init(&fctx->nsrrset);
+
+        if (domain == NULL) {
+                dns_forwarders_t *forwarders = NULL;
+                unsigned int labels;
+
+                /*
+                 * DS records are found in the parent server.
+                 * Strip label to get the correct forwarder (if any).
+                 */
+                if (fctx->type == dns_rdatatype_ds &&
+                    dns_name_countlabels(name) > 1) {
+                        dns_name_init(&suffix, NULL);
+                        labels = dns_name_countlabels(name);
+                        dns_name_getlabelsequence(name, 1, labels - 1, &suffix);
+                        name = &suffix;
+                }
+                dns_fixedname_init(&fixed);
+                domain = dns_fixedname_name(&fixed);
+                result = dns_fwdtable_find2(fctx->res->view->fwdtable, name,
+                                            domain, &forwarders);
+                if (result == ISC_R_SUCCESS)
+                        fctx->fwdpolicy = forwarders->fwdpolicy;
+
+                if (fctx->fwdpolicy != dns_fwdpolicy_only) {
+                        /*
+                         * The caller didn't supply a query domain and
+                         * nameservers, and we're not in forward-only mode,
+                         * so find the best nameservers to use.
+                         */
+                        if (dns_rdatatype_atparent(type))
+                                findoptions |= DNS_DBFIND_NOEXACT;
+                        result = dns_view_findzonecut(res->view, name, domain,
+                                                      0, findoptions, ISC_TRUE,
+                                                      &fctx->nameservers,
+                                                      NULL);
+                        if (result != ISC_R_SUCCESS)
+                                goto cleanup_name;
+                        result = dns_name_dup(domain,
+                                              res->buckets[bucketnum].mctx,
+                                              &fctx->domain);
+                        if (result != ISC_R_SUCCESS) {
+                                dns_rdataset_disassociate(&fctx->nameservers);
+                                goto cleanup_name;
+                        }
+                } else {
+                        /*
+                         * We're in forward-only mode.  Set the query domain.
+                         */
+                        result = dns_name_dup(domain,
+                                              res->buckets[bucketnum].mctx,
+                                              &fctx->domain);
+                        if (result != ISC_R_SUCCESS)
+                                goto cleanup_name;
+                }
+        } else {
+                result = dns_name_dup(domain,
+                                      res->buckets[bucketnum].mctx,
+                                      &fctx->domain);
+                if (result != ISC_R_SUCCESS)
+                        goto cleanup_name;
+                dns_rdataset_clone(nameservers, &fctx->nameservers);
+        }
+
+        INSIST(dns_name_issubdomain(&fctx->name, &fctx->domain));
+
+        fctx->qmessage = NULL;
+        result = dns_message_create(res->buckets[bucketnum].mctx,
+                                    DNS_MESSAGE_INTENTRENDER,
+                                    &fctx->qmessage);
+
+        if (result != ISC_R_SUCCESS)
+                goto cleanup_domain;
+
+        fctx->rmessage = NULL;
+        result = dns_message_create(res->buckets[bucketnum].mctx,
+                                    DNS_MESSAGE_INTENTPARSE,
+                                    &fctx->rmessage);
+
+        if (result != ISC_R_SUCCESS)
+                goto cleanup_qmessage;
+
+        /*
+         * Compute an expiration time for the entire fetch.
+         */
+        isc_interval_set(&interval, 30, 0);             /* XXXRTH constant */
+        iresult = isc_time_nowplusinterval(&fctx->expires, &interval);
+        if (iresult != ISC_R_SUCCESS) {
+                UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                 "isc_time_nowplusinterval: %s",
+                                 isc_result_totext(iresult));
+                result = ISC_R_UNEXPECTED;
+                goto cleanup_rmessage;
+        }
+
+        /*
+         * Default retry interval initialization.  We set the interval now
+         * mostly so it won't be uninitialized.  It will be set to the
+         * correct value before a query is issued.
+         */
+        isc_interval_set(&fctx->interval, 2, 0);
+
+        /*
+         * Create an inactive timer.  It will be made active when the fetch
+         * is actually started.
+         */
+        fctx->timer = NULL;
+        iresult = isc_timer_create(res->timermgr, isc_timertype_inactive,
+                                   NULL, NULL,
+                                   res->buckets[bucketnum].task, fctx_timeout,
+                                   fctx, &fctx->timer);
+        if (iresult != ISC_R_SUCCESS) {
+                UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                 "isc_timer_create: %s",
+                                 isc_result_totext(iresult));
+                result = ISC_R_UNEXPECTED;
+                goto cleanup_rmessage;
+        }
+
+        /*
+         * Attach to the view's cache and adb.
+         */
+        fctx->cache = NULL;
+        dns_db_attach(res->view->cachedb, &fctx->cache);
+        fctx->adb = NULL;
+        dns_adb_attach(res->view->adb, &fctx->adb);
+
+        ISC_LIST_INIT(fctx->events);
+        ISC_LINK_INIT(fctx, link);
+        fctx->magic = FCTX_MAGIC;
+
+        ISC_LIST_APPEND(res->buckets[bucketnum].fctxs, fctx, link);
+
+        LOCK(&res->nlock);
+        res->nfctx++;
+        UNLOCK(&res->nlock);
+
+        *fctxp = fctx;
+
+        return (ISC_R_SUCCESS);
 
  cleanup_rmessage:
-       dns_message_destroy(&fctx->rmessage);
+        dns_message_destroy(&fctx->rmessage);
 
  cleanup_qmessage:
-       dns_message_destroy(&fctx->qmessage);
+        dns_message_destroy(&fctx->qmessage);
 
  cleanup_domain:
-       if (dns_name_countlabels(&fctx->domain) > 0)
-               dns_name_free(&fctx->domain, res->buckets[bucketnum].mctx);
-       if (dns_rdataset_isassociated(&fctx->nameservers))
-               dns_rdataset_disassociate(&fctx->nameservers);
+        if (dns_name_countlabels(&fctx->domain) > 0)
+                dns_name_free(&fctx->domain, res->buckets[bucketnum].mctx);
+        if (dns_rdataset_isassociated(&fctx->nameservers))
+                dns_rdataset_disassociate(&fctx->nameservers);
 
  cleanup_name:
-       dns_name_free(&fctx->name, res->buckets[bucketnum].mctx);
+        dns_name_free(&fctx->name, res->buckets[bucketnum].mctx);
 
  cleanup_info:
-       isc_mem_free(res->buckets[bucketnum].mctx, fctx->info);
+        isc_mem_free(res->buckets[bucketnum].mctx, fctx->info);
 
  cleanup_fetch:
-       isc_mem_put(res->buckets[bucketnum].mctx, fctx, sizeof(*fctx));
+        isc_mem_put(res->buckets[bucketnum].mctx, fctx, sizeof(*fctx));
 
-       return (result);
+        return (result);
 }
 
 /*
@@ -3227,148 +3264,148 @@ fctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type,
  */
 static inline isc_boolean_t
 is_lame(fetchctx_t *fctx) {
-       dns_message_t *message = fctx->rmessage;
-       dns_name_t *name;
-       dns_rdataset_t *rdataset;
-       isc_result_t result;
-
-       if (message->rcode != dns_rcode_noerror &&
-           message->rcode != dns_rcode_nxdomain)
-               return (ISC_FALSE);
-
-       if (message->counts[DNS_SECTION_ANSWER] != 0)
-               return (ISC_FALSE);
-
-       if (message->counts[DNS_SECTION_AUTHORITY] == 0)
-               return (ISC_FALSE);
-
-       result = dns_message_firstname(message, DNS_SECTION_AUTHORITY);
-       while (result == ISC_R_SUCCESS) {
-               name = NULL;
-               dns_message_currentname(message, DNS_SECTION_AUTHORITY, &name);
-               for (rdataset = ISC_LIST_HEAD(name->list);
-                    rdataset != NULL;
-                    rdataset = ISC_LIST_NEXT(rdataset, link)) {
-                       dns_namereln_t namereln;
-                       int order;
-                       unsigned int labels;
-                       if (rdataset->type != dns_rdatatype_ns)
-                               continue;
-                       namereln = dns_name_fullcompare(name, &fctx->domain,
-                                                       &order, &labels);
-                       if (namereln == dns_namereln_equal &&
-                           (message->flags & DNS_MESSAGEFLAG_AA) != 0)
-                               return (ISC_FALSE);
-                       if (namereln == dns_namereln_subdomain)
-                               return (ISC_FALSE);
-                       return (ISC_TRUE);
-               }
-               result = dns_message_nextname(message, DNS_SECTION_AUTHORITY);
-       }
-
-       return (ISC_FALSE);
+        dns_message_t *message = fctx->rmessage;
+        dns_name_t *name;
+        dns_rdataset_t *rdataset;
+        isc_result_t result;
+
+        if (message->rcode != dns_rcode_noerror &&
+            message->rcode != dns_rcode_nxdomain)
+                return (ISC_FALSE);
+
+        if (message->counts[DNS_SECTION_ANSWER] != 0)
+                return (ISC_FALSE);
+
+        if (message->counts[DNS_SECTION_AUTHORITY] == 0)
+                return (ISC_FALSE);
+
+        result = dns_message_firstname(message, DNS_SECTION_AUTHORITY);
+        while (result == ISC_R_SUCCESS) {
+                name = NULL;
+                dns_message_currentname(message, DNS_SECTION_AUTHORITY, &name);
+                for (rdataset = ISC_LIST_HEAD(name->list);
+                     rdataset != NULL;
+                     rdataset = ISC_LIST_NEXT(rdataset, link)) {
+                        dns_namereln_t namereln;
+                        int order;
+                        unsigned int labels;
+                        if (rdataset->type != dns_rdatatype_ns)
+                                continue;
+                        namereln = dns_name_fullcompare(name, &fctx->domain,
+                                                        &order, &labels);
+                        if (namereln == dns_namereln_equal &&
+                            (message->flags & DNS_MESSAGEFLAG_AA) != 0)
+                                return (ISC_FALSE);
+                        if (namereln == dns_namereln_subdomain)
+                                return (ISC_FALSE);
+                        return (ISC_TRUE);
+                }
+                result = dns_message_nextname(message, DNS_SECTION_AUTHORITY);
+        }
+
+        return (ISC_FALSE);
 }
 
 static inline void
 log_lame(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo) {
-       char namebuf[DNS_NAME_FORMATSIZE];
-       char domainbuf[DNS_NAME_FORMATSIZE];    
-       char addrbuf[ISC_SOCKADDR_FORMATSIZE];
-       
-       dns_name_format(&fctx->name, namebuf, sizeof(namebuf));
-       dns_name_format(&fctx->domain, domainbuf, sizeof(domainbuf));
-       isc_sockaddr_format(&addrinfo->sockaddr, addrbuf, sizeof(addrbuf));
-       isc_log_write(dns_lctx, DNS_LOGCATEGORY_LAME_SERVERS,
-                     DNS_LOGMODULE_RESOLVER, ISC_LOG_INFO,
-                     "lame server resolving '%s' (in '%s'?): %s",
-                     namebuf, domainbuf, addrbuf);
+        char namebuf[DNS_NAME_FORMATSIZE];
+        char domainbuf[DNS_NAME_FORMATSIZE];
+        char addrbuf[ISC_SOCKADDR_FORMATSIZE];
+
+        dns_name_format(&fctx->name, namebuf, sizeof(namebuf));
+        dns_name_format(&fctx->domain, domainbuf, sizeof(domainbuf));
+        isc_sockaddr_format(&addrinfo->sockaddr, addrbuf, sizeof(addrbuf));
+        isc_log_write(dns_lctx, DNS_LOGCATEGORY_LAME_SERVERS,
+                      DNS_LOGMODULE_RESOLVER, ISC_LOG_INFO,
+                      "lame server resolving '%s' (in '%s'?): %s",
+                      namebuf, domainbuf, addrbuf);
 }
 
 static inline isc_result_t
 same_question(fetchctx_t *fctx) {
-       isc_result_t result;
-       dns_message_t *message = fctx->rmessage;
-       dns_name_t *name;
-       dns_rdataset_t *rdataset;
-
-       /*
-        * Caller must be holding the fctx lock.
-        */
-
-       /*
-        * XXXRTH  Currently we support only one question.
-        */
-       if (message->counts[DNS_SECTION_QUESTION] != 1)
-               return (DNS_R_FORMERR);
-
-       result = dns_message_firstname(message, DNS_SECTION_QUESTION);
-       if (result != ISC_R_SUCCESS)
-               return (result);
-       name = NULL;
-       dns_message_currentname(message, DNS_SECTION_QUESTION, &name);
-       rdataset = ISC_LIST_HEAD(name->list);
-       INSIST(rdataset != NULL);
-       INSIST(ISC_LIST_NEXT(rdataset, link) == NULL);
-       if (fctx->type != rdataset->type ||
-           fctx->res->rdclass != rdataset->rdclass ||
-           !dns_name_equal(&fctx->name, name))
-               return (DNS_R_FORMERR);
-
-       return (ISC_R_SUCCESS);
+        isc_result_t result;
+        dns_message_t *message = fctx->rmessage;
+        dns_name_t *name;
+        dns_rdataset_t *rdataset;
+
+        /*
+         * Caller must be holding the fctx lock.
+         */
+
+        /*
+         * XXXRTH  Currently we support only one question.
+         */
+        if (message->counts[DNS_SECTION_QUESTION] != 1)
+                return (DNS_R_FORMERR);
+
+        result = dns_message_firstname(message, DNS_SECTION_QUESTION);
+        if (result != ISC_R_SUCCESS)
+                return (result);
+        name = NULL;
+        dns_message_currentname(message, DNS_SECTION_QUESTION, &name);
+        rdataset = ISC_LIST_HEAD(name->list);
+        INSIST(rdataset != NULL);
+        INSIST(ISC_LIST_NEXT(rdataset, link) == NULL);
+        if (fctx->type != rdataset->type ||
+            fctx->res->rdclass != rdataset->rdclass ||
+            !dns_name_equal(&fctx->name, name))
+                return (DNS_R_FORMERR);
+
+        return (ISC_R_SUCCESS);
 }
 
 static void
 clone_results(fetchctx_t *fctx) {
-       dns_fetchevent_t *event, *hevent;
-       isc_result_t result;
-       dns_name_t *name, *hname;
-
-       FCTXTRACE("clone_results");
-
-       /*
-        * Set up any other events to have the same data as the first
-        * event.
-        *
-        * Caller must be holding the appropriate lock.
-        */
-
-       fctx->cloned = ISC_TRUE;
-       hevent = ISC_LIST_HEAD(fctx->events);
-       if (hevent == NULL)
-               return;
-       hname = dns_fixedname_name(&hevent->foundname);
-       for (event = ISC_LIST_NEXT(hevent, ev_link);
-            event != NULL;
-            event = ISC_LIST_NEXT(event, ev_link)) {
-               name = dns_fixedname_name(&event->foundname);
-               result = dns_name_copy(hname, name, NULL);
-               if (result != ISC_R_SUCCESS)
-                       event->result = result;
-               else
-                       event->result = hevent->result;
-               dns_db_attach(hevent->db, &event->db);
-               dns_db_attachnode(hevent->db, hevent->node, &event->node);
-               INSIST(hevent->rdataset != NULL);
-               INSIST(event->rdataset != NULL);
-               if (dns_rdataset_isassociated(hevent->rdataset))
-                       dns_rdataset_clone(hevent->rdataset, event->rdataset);
-               INSIST(! (hevent->sigrdataset == NULL &&
-                         event->sigrdataset != NULL));
-               if (hevent->sigrdataset != NULL &&
-                   dns_rdataset_isassociated(hevent->sigrdataset) &&
-                   event->sigrdataset != NULL)
-                       dns_rdataset_clone(hevent->sigrdataset,
-                                          event->sigrdataset);
-       }
+        dns_fetchevent_t *event, *hevent;
+        isc_result_t result;
+        dns_name_t *name, *hname;
+
+        FCTXTRACE("clone_results");
+
+        /*
+         * Set up any other events to have the same data as the first
+         * event.
+         *
+         * Caller must be holding the appropriate lock.
+         */
+
+        fctx->cloned = ISC_TRUE;
+        hevent = ISC_LIST_HEAD(fctx->events);
+        if (hevent == NULL)
+                return;
+        hname = dns_fixedname_name(&hevent->foundname);
+        for (event = ISC_LIST_NEXT(hevent, ev_link);
+             event != NULL;
+             event = ISC_LIST_NEXT(event, ev_link)) {
+                name = dns_fixedname_name(&event->foundname);
+                result = dns_name_copy(hname, name, NULL);
+                if (result != ISC_R_SUCCESS)
+                        event->result = result;
+                else
+                        event->result = hevent->result;
+                dns_db_attach(hevent->db, &event->db);
+                dns_db_attachnode(hevent->db, hevent->node, &event->node);
+                INSIST(hevent->rdataset != NULL);
+                INSIST(event->rdataset != NULL);
+                if (dns_rdataset_isassociated(hevent->rdataset))
+                        dns_rdataset_clone(hevent->rdataset, event->rdataset);
+                INSIST(! (hevent->sigrdataset == NULL &&
+                          event->sigrdataset != NULL));
+                if (hevent->sigrdataset != NULL &&
+                    dns_rdataset_isassociated(hevent->sigrdataset) &&
+                    event->sigrdataset != NULL)
+                        dns_rdataset_clone(hevent->sigrdataset,
+                                           event->sigrdataset);
+        }
 }
 
-#define CACHE(r)       (((r)->attributes & DNS_RDATASETATTR_CACHE) != 0)
-#define ANSWER(r)      (((r)->attributes & DNS_RDATASETATTR_ANSWER) != 0)
-#define ANSWERSIG(r)   (((r)->attributes & DNS_RDATASETATTR_ANSWERSIG) != 0)
-#define EXTERNAL(r)    (((r)->attributes & DNS_RDATASETATTR_EXTERNAL) != 0)
-#define CHAINING(r)    (((r)->attributes & DNS_RDATASETATTR_CHAINING) != 0)
-#define CHASE(r)       (((r)->attributes & DNS_RDATASETATTR_CHASE) != 0)
-#define CHECKNAMES(r)  (((r)->attributes & DNS_RDATASETATTR_CHECKNAMES) != 0)
+#define CACHE(r)        (((r)->attributes & DNS_RDATASETATTR_CACHE) != 0)
+#define ANSWER(r)       (((r)->attributes & DNS_RDATASETATTR_ANSWER) != 0)
+#define ANSWERSIG(r)    (((r)->attributes & DNS_RDATASETATTR_ANSWERSIG) != 0)
+#define EXTERNAL(r)     (((r)->attributes & DNS_RDATASETATTR_EXTERNAL) != 0)
+#define CHAINING(r)     (((r)->attributes & DNS_RDATASETATTR_CHAINING) != 0)
+#define CHASE(r)        (((r)->attributes & DNS_RDATASETATTR_CHASE) != 0)
+#define CHECKNAMES(r)   (((r)->attributes & DNS_RDATASETATTR_CHECKNAMES) != 0)
 
 
 /*
@@ -3377,42 +3414,42 @@ clone_results(fetchctx_t *fctx) {
  * was the last fctx in the resolver, destroy the resolver.
  *
  * Requires:
- *     '*fctx' is shutting down.
+ *      '*fctx' is shutting down.
  */
 static void
 maybe_destroy(fetchctx_t *fctx) {
-       unsigned int bucketnum;
-       isc_boolean_t bucket_empty = ISC_FALSE;
-       dns_resolver_t *res = fctx->res;
-       dns_validator_t *validator, *next_validator;
-
-       REQUIRE(SHUTTINGDOWN(fctx));
-
-       if (fctx->pending != 0 || fctx->nqueries != 0)
-               return;
-
-       for (validator = ISC_LIST_HEAD(fctx->validators);
-            validator != NULL; validator = next_validator) {
-               next_validator = ISC_LIST_NEXT(validator, link);
-               dns_validator_cancel(validator);
-               /*
-                * If this is a active validator wait for the cancel
-                * to complete before calling dns_validator_destroy().
-                */
-               if (validator == fctx->validator)
-                       continue;
-               ISC_LIST_UNLINK(fctx->validators, validator, link);
-               dns_validator_destroy(&validator);
-       }
-
-       bucketnum = fctx->bucketnum;
-       LOCK(&res->buckets[bucketnum].lock);
-       if (fctx->references == 0 && ISC_LIST_EMPTY(fctx->validators))
-               bucket_empty = fctx_destroy(fctx);
-       UNLOCK(&res->buckets[bucketnum].lock);
-
-       if (bucket_empty)
-               empty_bucket(res);
+        unsigned int bucketnum;
+        isc_boolean_t bucket_empty = ISC_FALSE;
+        dns_resolver_t *res = fctx->res;
+        dns_validator_t *validator, *next_validator;
+
+        REQUIRE(SHUTTINGDOWN(fctx));
+
+        if (fctx->pending != 0 || fctx->nqueries != 0)
+                return;
+
+        for (validator = ISC_LIST_HEAD(fctx->validators);
+             validator != NULL; validator = next_validator) {
+                next_validator = ISC_LIST_NEXT(validator, link);
+                dns_validator_cancel(validator);
+                /*
+                 * If this is a active validator wait for the cancel
+                 * to complete before calling dns_validator_destroy().
+                 */
+                if (validator == fctx->validator)
+                        continue;
+                ISC_LIST_UNLINK(fctx->validators, validator, link);
+                dns_validator_destroy(&validator);
+        }
+
+        bucketnum = fctx->bucketnum;
+        LOCK(&res->buckets[bucketnum].lock);
+        if (fctx->references == 0 && ISC_LIST_EMPTY(fctx->validators))
+                bucket_empty = fctx_destroy(fctx);
+        UNLOCK(&res->buckets[bucketnum].lock);
+
+        if (bucket_empty)
+                empty_bucket(res);
 }
 
 /*
@@ -3420,718 +3457,718 @@ maybe_destroy(fetchctx_t *fctx) {
  */
 static void
 validated(isc_task_t *task, isc_event_t *event) {
-       isc_result_t result = ISC_R_SUCCESS;
-       isc_result_t eresult = ISC_R_SUCCESS;
-       isc_stdtime_t now;
-       fetchctx_t *fctx;
-       dns_validatorevent_t *vevent;
-       dns_fetchevent_t *hevent;
-       dns_rdataset_t *ardataset = NULL;
-       dns_rdataset_t *asigrdataset = NULL;
-       dns_dbnode_t *node = NULL;
-       isc_boolean_t negative;
-       isc_boolean_t chaining;
-       isc_boolean_t sentresponse;
-       isc_uint32_t ttl;
-       dns_dbnode_t *nsnode = NULL;
-       dns_name_t *name;
-       dns_rdataset_t *rdataset;
-       dns_rdataset_t *sigrdataset;
-       dns_valarg_t *valarg;
-       dns_adbaddrinfo_t *addrinfo;
-
-       UNUSED(task); /* for now */
-
-       REQUIRE(event->ev_type == DNS_EVENT_VALIDATORDONE);
-       valarg = event->ev_arg;
-       fctx = valarg->fctx;
-       addrinfo = valarg->addrinfo;
-       REQUIRE(VALID_FCTX(fctx));
-       REQUIRE(!ISC_LIST_EMPTY(fctx->validators));
-
-       vevent = (dns_validatorevent_t *)event;
-
-       FCTXTRACE("received validation completion event");
-
-       ISC_LIST_UNLINK(fctx->validators, vevent->validator, link);
-       fctx->validator = NULL;
-
-       /*
-        * Destroy the validator early so that we can
-        * destroy the fctx if necessary.
-        */
-       dns_validator_destroy(&vevent->validator);
-       isc_mem_put(fctx->res->buckets[fctx->bucketnum].mctx,
-                   valarg, sizeof(*valarg));
-
-       negative = ISC_TF(vevent->rdataset == NULL);
-
-       sentresponse = ISC_TF((fctx->options & DNS_FETCHOPT_NOVALIDATE) != 0);
-
-       /*
-        * If shutting down, ignore the results.  Check to see if we're
-        * done waiting for validator completions and ADB pending events; if
-        * so, destroy the fctx.
-        */
-       if (SHUTTINGDOWN(fctx) && !sentresponse) {
-               maybe_destroy(fctx);    /* Locks bucket. */
-               goto cleanup_event;
-       }
-
-       LOCK(&fctx->res->buckets[fctx->bucketnum].lock);
-
-       /*
-        * If chaining, we need to make sure that the right result code is
-        * returned, and that the rdatasets are bound.
-        */
-       if (vevent->result == ISC_R_SUCCESS &&
-           !negative &&
-           vevent->rdataset != NULL &&
-           CHAINING(vevent->rdataset))
-       {
-               if (vevent->rdataset->type == dns_rdatatype_cname)
-                       eresult = DNS_R_CNAME;
-               else {
-                       INSIST(vevent->rdataset->type == dns_rdatatype_dname);
-                       eresult = DNS_R_DNAME;
-               }
-               chaining = ISC_TRUE;
-       } else
-               chaining = ISC_FALSE;
-
-       /*
-        * Either we're not shutting down, or we are shutting down but want
-        * to cache the result anyway (if this was a validation started by
-        * a query with cd set)
-        */
-
-       hevent = ISC_LIST_HEAD(fctx->events);
-       if (hevent != NULL) {
-               if (!negative && !chaining &&
-                   (fctx->type == dns_rdatatype_any ||
-                    fctx->type == dns_rdatatype_rrsig ||
-                    fctx->type == dns_rdatatype_sig)) {
-                       /*
-                        * Don't bind rdatasets; the caller
-                        * will iterate the node.
-                        */
-               } else {
-                       ardataset = hevent->rdataset;
-                       asigrdataset = hevent->sigrdataset;
-               }
-       }
-
-       if (vevent->result != ISC_R_SUCCESS) {
-               FCTXTRACE("validation failed");
-               result = ISC_R_NOTFOUND;
-               if (vevent->rdataset != NULL)
-                       result = dns_db_findnode(fctx->cache, vevent->name,
-                                                ISC_TRUE, &node);
-               if (result == ISC_R_SUCCESS)
-                       (void)dns_db_deleterdataset(fctx->cache, node, NULL,
-                                                   vevent->type, 0);
-               if (result == ISC_R_SUCCESS && vevent->sigrdataset != NULL)
-                       (void)dns_db_deleterdataset(fctx->cache, node, NULL,
-                                                   dns_rdatatype_rrsig,
-                                                   vevent->type);
-               if (result == ISC_R_SUCCESS)
-                       dns_db_detachnode(fctx->cache, &node);
-               result = vevent->result;
-               add_bad(fctx, addrinfo, result);
-               isc_event_free(&event);
-               UNLOCK(&fctx->res->buckets[fctx->bucketnum].lock);
-               INSIST(fctx->validator == NULL);
-               fctx->validator = ISC_LIST_HEAD(fctx->validators);
-               if (fctx->validator != NULL) {
-                       dns_validator_send(fctx->validator);
-               } else if (sentresponse)
-                       fctx_done(fctx, result);        /* Locks bucket. */
-               else
-                       fctx_try(fctx);                 /* Locks bucket. */
-               return;
-       }
-
-       isc_stdtime_get(&now);
-
-       if (negative) {
-               dns_rdatatype_t covers;
-               FCTXTRACE("nonexistence validation OK");
-
-               if (fctx->rmessage->rcode == dns_rcode_nxdomain)
-                       covers = dns_rdatatype_any;
-               else
-                       covers = fctx->type;
-
-               result = dns_db_findnode(fctx->cache, vevent->name, ISC_TRUE,
-                                        &node);
-               if (result != ISC_R_SUCCESS)
-                       goto noanswer_response;
-
-               /*
-                * If we are asking for a SOA record set the cache time
-                * to zero to facilitate locating the containing zone of
-                * a arbitary zone.
-                */
-               ttl = fctx->res->view->maxncachettl;
-               if (fctx->type == dns_rdatatype_soa &&
-                   covers == dns_rdatatype_any &&
-                   fctx->res->zero_no_soa_ttl)
-                       ttl = 0;
-
-               result = ncache_adderesult(fctx->rmessage, fctx->cache, node,
-                                          covers, now, ttl,
-                                          ardataset, &eresult);
-               if (result != ISC_R_SUCCESS)
-                       goto noanswer_response;
-               goto answer_response;
-       }
-
-       FCTXTRACE("validation OK");
-
-       if (vevent->proofs[DNS_VALIDATOR_NOQNAMEPROOF] != NULL) {
-
-               result = dns_rdataset_addnoqname(vevent->rdataset,
-                                  vevent->proofs[DNS_VALIDATOR_NOQNAMEPROOF]);
-               RUNTIME_CHECK(result == ISC_R_SUCCESS);
-               INSIST(vevent->sigrdataset != NULL);
-               vevent->sigrdataset->ttl = vevent->rdataset->ttl;
-       }
-
-       /*
-        * The data was already cached as pending data.
-        * Re-cache it as secure and bind the cached
-        * rdatasets to the first event on the fetch
-        * event list.
-        */
-       result = dns_db_findnode(fctx->cache, vevent->name, ISC_TRUE, &node);
-       if (result != ISC_R_SUCCESS)
-               goto noanswer_response;
-
-       result = dns_db_addrdataset(fctx->cache, node, NULL, now,
-                                   vevent->rdataset, 0, ardataset);
-       if (result != ISC_R_SUCCESS &&
-           result != DNS_R_UNCHANGED)
-               goto noanswer_response;
-       if (ardataset != NULL && ardataset->type == 0) {
-               if (NXDOMAIN(ardataset))
-                       eresult = DNS_R_NCACHENXDOMAIN;
-               else
-                       eresult = DNS_R_NCACHENXRRSET;
-       } else if (vevent->sigrdataset != NULL) {
-               result = dns_db_addrdataset(fctx->cache, node, NULL, now,
-                                           vevent->sigrdataset, 0,
-                                           asigrdataset);
-               if (result != ISC_R_SUCCESS &&
-                   result != DNS_R_UNCHANGED)
-                       goto noanswer_response;
-       }
-
-       if (sentresponse) {
-               /*
-                * If we only deferred the destroy because we wanted to cache
-                * the data, destroy now.
-                */
-               dns_db_detachnode(fctx->cache, &node);
-               UNLOCK(&fctx->res->buckets[fctx->bucketnum].lock);
-               if (SHUTTINGDOWN(fctx))
-                       maybe_destroy(fctx);    /* Locks bucket. */
-               goto cleanup_event;
-       }
-
-       if (!ISC_LIST_EMPTY(fctx->validators)) {
-               INSIST(!negative);
-               INSIST(fctx->type == dns_rdatatype_any ||
-                      fctx->type == dns_rdatatype_rrsig ||
-                      fctx->type == dns_rdatatype_sig);
-               /*
-                * Don't send a response yet - we have
-                * more rdatasets that still need to
-                * be validated.
-                */
-               dns_db_detachnode(fctx->cache, &node);
-               UNLOCK(&fctx->res->buckets[fctx->bucketnum].lock);
-               dns_validator_send(ISC_LIST_HEAD(fctx->validators));
-               goto cleanup_event;
-       }
+        isc_result_t result = ISC_R_SUCCESS;
+        isc_result_t eresult = ISC_R_SUCCESS;
+        isc_stdtime_t now;
+        fetchctx_t *fctx;
+        dns_validatorevent_t *vevent;
+        dns_fetchevent_t *hevent;
+        dns_rdataset_t *ardataset = NULL;
+        dns_rdataset_t *asigrdataset = NULL;
+        dns_dbnode_t *node = NULL;
+        isc_boolean_t negative;
+        isc_boolean_t chaining;
+        isc_boolean_t sentresponse;
+        isc_uint32_t ttl;
+        dns_dbnode_t *nsnode = NULL;
+        dns_name_t *name;
+        dns_rdataset_t *rdataset;
+        dns_rdataset_t *sigrdataset;
+        dns_valarg_t *valarg;
+        dns_adbaddrinfo_t *addrinfo;
+
+        UNUSED(task); /* for now */
+
+        REQUIRE(event->ev_type == DNS_EVENT_VALIDATORDONE);
+        valarg = event->ev_arg;
+        fctx = valarg->fctx;
+        addrinfo = valarg->addrinfo;
+        REQUIRE(VALID_FCTX(fctx));
+        REQUIRE(!ISC_LIST_EMPTY(fctx->validators));
+
+        vevent = (dns_validatorevent_t *)event;
+
+        FCTXTRACE("received validation completion event");
+
+        ISC_LIST_UNLINK(fctx->validators, vevent->validator, link);
+        fctx->validator = NULL;
+
+        /*
+         * Destroy the validator early so that we can
+         * destroy the fctx if necessary.
+         */
+        dns_validator_destroy(&vevent->validator);
+        isc_mem_put(fctx->res->buckets[fctx->bucketnum].mctx,
+                    valarg, sizeof(*valarg));
+
+        negative = ISC_TF(vevent->rdataset == NULL);
+
+        sentresponse = ISC_TF((fctx->options & DNS_FETCHOPT_NOVALIDATE) != 0);
+
+        /*
+         * If shutting down, ignore the results.  Check to see if we're
+         * done waiting for validator completions and ADB pending events; if
+         * so, destroy the fctx.
+         */
+        if (SHUTTINGDOWN(fctx) && !sentresponse) {
+                maybe_destroy(fctx);    /* Locks bucket. */
+                goto cleanup_event;
+        }
+
+        LOCK(&fctx->res->buckets[fctx->bucketnum].lock);
+
+        /*
+         * If chaining, we need to make sure that the right result code is
+         * returned, and that the rdatasets are bound.
+         */
+        if (vevent->result == ISC_R_SUCCESS &&
+            !negative &&
+            vevent->rdataset != NULL &&
+            CHAINING(vevent->rdataset))
+        {
+                if (vevent->rdataset->type == dns_rdatatype_cname)
+                        eresult = DNS_R_CNAME;
+                else {
+                        INSIST(vevent->rdataset->type == dns_rdatatype_dname);
+                        eresult = DNS_R_DNAME;
+                }
+                chaining = ISC_TRUE;
+        } else
+                chaining = ISC_FALSE;
+
+        /*
+         * Either we're not shutting down, or we are shutting down but want
+         * to cache the result anyway (if this was a validation started by
+         * a query with cd set)
+         */
+
+        hevent = ISC_LIST_HEAD(fctx->events);
+        if (hevent != NULL) {
+                if (!negative && !chaining &&
+                    (fctx->type == dns_rdatatype_any ||
+                     fctx->type == dns_rdatatype_rrsig ||
+                     fctx->type == dns_rdatatype_sig)) {
+                        /*
+                         * Don't bind rdatasets; the caller
+                         * will iterate the node.
+                         */
+                } else {
+                        ardataset = hevent->rdataset;
+                        asigrdataset = hevent->sigrdataset;
+                }
+        }
+
+        if (vevent->result != ISC_R_SUCCESS) {
+                FCTXTRACE("validation failed");
+                result = ISC_R_NOTFOUND;
+                if (vevent->rdataset != NULL)
+                        result = dns_db_findnode(fctx->cache, vevent->name,
+                                                 ISC_TRUE, &node);
+                if (result == ISC_R_SUCCESS)
+                        (void)dns_db_deleterdataset(fctx->cache, node, NULL,
+                                                    vevent->type, 0);
+                if (result == ISC_R_SUCCESS && vevent->sigrdataset != NULL)
+                        (void)dns_db_deleterdataset(fctx->cache, node, NULL,
+                                                    dns_rdatatype_rrsig,
+                                                    vevent->type);
+                if (result == ISC_R_SUCCESS)
+                        dns_db_detachnode(fctx->cache, &node);
+                result = vevent->result;
+                add_bad(fctx, addrinfo, result);
+                isc_event_free(&event);
+                UNLOCK(&fctx->res->buckets[fctx->bucketnum].lock);
+                INSIST(fctx->validator == NULL);
+                fctx->validator = ISC_LIST_HEAD(fctx->validators);
+                if (fctx->validator != NULL) {
+                        dns_validator_send(fctx->validator);
+                } else if (sentresponse)
+                        fctx_done(fctx, result);        /* Locks bucket. */
+                else
+                        fctx_try(fctx);                 /* Locks bucket. */
+                return;
+        }
+
+        isc_stdtime_get(&now);
+
+        if (negative) {
+                dns_rdatatype_t covers;
+                FCTXTRACE("nonexistence validation OK");
+
+                if (fctx->rmessage->rcode == dns_rcode_nxdomain)
+                        covers = dns_rdatatype_any;
+                else
+                        covers = fctx->type;
+
+                result = dns_db_findnode(fctx->cache, vevent->name, ISC_TRUE,
+                                         &node);
+                if (result != ISC_R_SUCCESS)
+                        goto noanswer_response;
+
+                /*
+                 * If we are asking for a SOA record set the cache time
+                 * to zero to facilitate locating the containing zone of
+                 * a arbitary zone.
+                 */
+                ttl = fctx->res->view->maxncachettl;
+                if (fctx->type == dns_rdatatype_soa &&
+                    covers == dns_rdatatype_any &&
+                    fctx->res->zero_no_soa_ttl)
+                        ttl = 0;
+
+                result = ncache_adderesult(fctx->rmessage, fctx->cache, node,
+                                           covers, now, ttl,
+                                           ardataset, &eresult);
+                if (result != ISC_R_SUCCESS)
+                        goto noanswer_response;
+                goto answer_response;
+        }
+
+        FCTXTRACE("validation OK");
+
+        if (vevent->proofs[DNS_VALIDATOR_NOQNAMEPROOF] != NULL) {
+
+                result = dns_rdataset_addnoqname(vevent->rdataset,
+                                   vevent->proofs[DNS_VALIDATOR_NOQNAMEPROOF]);
+                RUNTIME_CHECK(result == ISC_R_SUCCESS);
+                INSIST(vevent->sigrdataset != NULL);
+                vevent->sigrdataset->ttl = vevent->rdataset->ttl;
+        }
+
+        /*
+         * The data was already cached as pending data.
+         * Re-cache it as secure and bind the cached
+         * rdatasets to the first event on the fetch
+         * event list.
+         */
+        result = dns_db_findnode(fctx->cache, vevent->name, ISC_TRUE, &node);
+        if (result != ISC_R_SUCCESS)
+                goto noanswer_response;
+
+        result = dns_db_addrdataset(fctx->cache, node, NULL, now,
+                                    vevent->rdataset, 0, ardataset);
+        if (result != ISC_R_SUCCESS &&
+            result != DNS_R_UNCHANGED)
+                goto noanswer_response;
+        if (ardataset != NULL && ardataset->type == 0) {
+                if (NXDOMAIN(ardataset))
+                        eresult = DNS_R_NCACHENXDOMAIN;
+                else
+                        eresult = DNS_R_NCACHENXRRSET;
+        } else if (vevent->sigrdataset != NULL) {
+                result = dns_db_addrdataset(fctx->cache, node, NULL, now,
+                                            vevent->sigrdataset, 0,
+                                            asigrdataset);
+                if (result != ISC_R_SUCCESS &&
+                    result != DNS_R_UNCHANGED)
+                        goto noanswer_response;
+        }
+
+        if (sentresponse) {
+                /*
+                 * If we only deferred the destroy because we wanted to cache
+                 * the data, destroy now.
+                 */
+                dns_db_detachnode(fctx->cache, &node);
+                UNLOCK(&fctx->res->buckets[fctx->bucketnum].lock);
+                if (SHUTTINGDOWN(fctx))
+                        maybe_destroy(fctx);    /* Locks bucket. */
+                goto cleanup_event;
+        }
+
+        if (!ISC_LIST_EMPTY(fctx->validators)) {
+                INSIST(!negative);
+                INSIST(fctx->type == dns_rdatatype_any ||
+                       fctx->type == dns_rdatatype_rrsig ||
+                       fctx->type == dns_rdatatype_sig);
+                /*
+                 * Don't send a response yet - we have
+                 * more rdatasets that still need to
+                 * be validated.
+                 */
+                dns_db_detachnode(fctx->cache, &node);
+                UNLOCK(&fctx->res->buckets[fctx->bucketnum].lock);
+                dns_validator_send(ISC_LIST_HEAD(fctx->validators));
+                goto cleanup_event;
+        }
 
  answer_response:
-       /*
-        * Cache any NS/NSEC records that happened to be validated.
-        */
-       result = dns_message_firstname(fctx->rmessage, DNS_SECTION_AUTHORITY);
-       while (result == ISC_R_SUCCESS) {
-               name = NULL;
-               dns_message_currentname(fctx->rmessage, DNS_SECTION_AUTHORITY,
-                                       &name);
-               for (rdataset = ISC_LIST_HEAD(name->list);
-                    rdataset != NULL;
-                    rdataset = ISC_LIST_NEXT(rdataset, link)) {
-                       if ((rdataset->type != dns_rdatatype_ns &&
-                            rdataset->type != dns_rdatatype_nsec) ||
-                           rdataset->trust != dns_trust_secure)
-                               continue;
-                       for (sigrdataset = ISC_LIST_HEAD(name->list);
-                            sigrdataset != NULL;
-                            sigrdataset = ISC_LIST_NEXT(sigrdataset, link)) {
-                               if (sigrdataset->type != dns_rdatatype_rrsig ||
-                                   sigrdataset->covers != rdataset->type)
-                                       continue;
-                               break;
-                       }
-                       if (sigrdataset == NULL ||
-                           sigrdataset->trust != dns_trust_secure)
-                               continue;
-                       result = dns_db_findnode(fctx->cache, name, ISC_TRUE,
-                                                &nsnode);
-                       if (result != ISC_R_SUCCESS)
-                               continue;
-
-                       result = dns_db_addrdataset(fctx->cache, nsnode, NULL,
-                                                   now, rdataset, 0, NULL);
-                       if (result == ISC_R_SUCCESS)
-                               result = dns_db_addrdataset(fctx->cache, nsnode,
-                                                           NULL, now,
-                                                           sigrdataset, 0,
-                                                           NULL);
-                       dns_db_detachnode(fctx->cache, &nsnode);
-               }
-               result = dns_message_nextname(fctx->rmessage,
-                                             DNS_SECTION_AUTHORITY);
-       }
-
-       result = ISC_R_SUCCESS;
-
-       /*
-        * Respond with an answer, positive or negative,
-        * as opposed to an error.  'node' must be non-NULL.
-        */
-
-       fctx->attributes |= FCTX_ATTR_HAVEANSWER;
-
-       if (hevent != NULL) {
-               hevent->result = eresult;
-               RUNTIME_CHECK(dns_name_copy(vevent->name,
-                             dns_fixedname_name(&hevent->foundname), NULL)
-                             == ISC_R_SUCCESS);
-               dns_db_attach(fctx->cache, &hevent->db);
-               dns_db_transfernode(fctx->cache, &node, &hevent->node);
-               clone_results(fctx);
-       }
+        /*
+         * Cache any NS/NSEC records that happened to be validated.
+         */
+        result = dns_message_firstname(fctx->rmessage, DNS_SECTION_AUTHORITY);
+        while (result == ISC_R_SUCCESS) {
+                name = NULL;
+                dns_message_currentname(fctx->rmessage, DNS_SECTION_AUTHORITY,
+                                        &name);
+                for (rdataset = ISC_LIST_HEAD(name->list);
+                     rdataset != NULL;
+                     rdataset = ISC_LIST_NEXT(rdataset, link)) {
+                        if ((rdataset->type != dns_rdatatype_ns &&
+                             rdataset->type != dns_rdatatype_nsec) ||
+                            rdataset->trust != dns_trust_secure)
+                                continue;
+                        for (sigrdataset = ISC_LIST_HEAD(name->list);
+                             sigrdataset != NULL;
+                             sigrdataset = ISC_LIST_NEXT(sigrdataset, link)) {
+                                if (sigrdataset->type != dns_rdatatype_rrsig ||
+                                    sigrdataset->covers != rdataset->type)
+                                        continue;
+                                break;
+                        }
+                        if (sigrdataset == NULL ||
+                            sigrdataset->trust != dns_trust_secure)
+                                continue;
+                        result = dns_db_findnode(fctx->cache, name, ISC_TRUE,
+                                                 &nsnode);
+                        if (result != ISC_R_SUCCESS)
+                                continue;
+
+                        result = dns_db_addrdataset(fctx->cache, nsnode, NULL,
+                                                    now, rdataset, 0, NULL);
+                        if (result == ISC_R_SUCCESS)
+                                result = dns_db_addrdataset(fctx->cache, nsnode,
+                                                            NULL, now,
+                                                            sigrdataset, 0,
+                                                            NULL);
+                        dns_db_detachnode(fctx->cache, &nsnode);
+                }
+                result = dns_message_nextname(fctx->rmessage,
+                                              DNS_SECTION_AUTHORITY);
+        }
+
+        result = ISC_R_SUCCESS;
+
+        /*
+         * Respond with an answer, positive or negative,
+         * as opposed to an error.  'node' must be non-NULL.
+         */
+
+        fctx->attributes |= FCTX_ATTR_HAVEANSWER;
+
+        if (hevent != NULL) {
+                hevent->result = eresult;
+                RUNTIME_CHECK(dns_name_copy(vevent->name,
+                              dns_fixedname_name(&hevent->foundname), NULL)
+                              == ISC_R_SUCCESS);
+                dns_db_attach(fctx->cache, &hevent->db);
+                dns_db_transfernode(fctx->cache, &node, &hevent->node);
+                clone_results(fctx);
+        }
 
  noanswer_response:
-       if (node != NULL)
-               dns_db_detachnode(fctx->cache, &node);
+        if (node != NULL)
+                dns_db_detachnode(fctx->cache, &node);
 
-       UNLOCK(&fctx->res->buckets[fctx->bucketnum].lock);
+        UNLOCK(&fctx->res->buckets[fctx->bucketnum].lock);
 
-       fctx_done(fctx, result);        /* Locks bucket. */
+        fctx_done(fctx, result);        /* Locks bucket. */
 
  cleanup_event:
-       INSIST(node == NULL);
-       isc_event_free(&event);
+        INSIST(node == NULL);
+        isc_event_free(&event);
 }
 
 static inline isc_result_t
 cache_name(fetchctx_t *fctx, dns_name_t *name, dns_adbaddrinfo_t *addrinfo,
-          isc_stdtime_t now)
+           isc_stdtime_t now)
 {
-       dns_rdataset_t *rdataset, *sigrdataset;
-       dns_rdataset_t *addedrdataset, *ardataset, *asigrdataset;
-       dns_rdataset_t *valrdataset = NULL, *valsigrdataset = NULL;
-       dns_dbnode_t *node, **anodep;
-       dns_db_t **adbp;
-       dns_name_t *aname;
-       dns_resolver_t *res;
-       isc_boolean_t need_validation, secure_domain, have_answer;
-       isc_result_t result, eresult;
-       dns_fetchevent_t *event;
-       unsigned int options;
-       isc_task_t *task;
-       isc_boolean_t fail;
-       unsigned int valoptions = 0;
-
-       /*
-        * The appropriate bucket lock must be held.
-        */
-
-       res = fctx->res;
-       need_validation = ISC_FALSE;
-       secure_domain = ISC_FALSE;
-       have_answer = ISC_FALSE;
-       eresult = ISC_R_SUCCESS;
-       task = res->buckets[fctx->bucketnum].task;
-
-       /*
-        * Is DNSSEC validation required for this name?
-        */
-       if (res->view->enablevalidation) {
-               result = dns_keytable_issecuredomain(res->view->secroots, name,
-                                                    &secure_domain);
-               if (result != ISC_R_SUCCESS)
-                       return (result);
-
-               if (!secure_domain && res->view->dlv != NULL) {
-                       valoptions = DNS_VALIDATOR_DLV;
-                       secure_domain = ISC_TRUE;
-               }
-       }
-
-       if ((fctx->options & DNS_FETCHOPT_NOVALIDATE) != 0)
-               need_validation = ISC_FALSE;
-       else
-               need_validation = secure_domain;
-
-       adbp = NULL;
-       aname = NULL;
-       anodep = NULL;
-       ardataset = NULL;
-       asigrdataset = NULL;
-       event = NULL;
-       if ((name->attributes & DNS_NAMEATTR_ANSWER) != 0 &&
-           !need_validation) {
-               have_answer = ISC_TRUE;
-               event = ISC_LIST_HEAD(fctx->events);
-               if (event != NULL) {
-                       adbp = &event->db;
-                       aname = dns_fixedname_name(&event->foundname);
-                       result = dns_name_copy(name, aname, NULL);
-                       if (result != ISC_R_SUCCESS)
-                               return (result);
-                       anodep = &event->node;
-                       /*
-                        * If this is an ANY, SIG or RRSIG query, we're not
-                        * going to return any rdatasets, unless we encountered
-                        * a CNAME or DNAME as "the answer".  In this case,
-                        * we're going to return DNS_R_CNAME or DNS_R_DNAME
-                        * and we must set up the rdatasets.
-                        */
-                       if ((fctx->type != dns_rdatatype_any &&
-                            fctx->type != dns_rdatatype_rrsig &&
-                            fctx->type != dns_rdatatype_sig) ||
-                           (name->attributes & DNS_NAMEATTR_CHAINING) != 0) {
-                               ardataset = event->rdataset;
-                               asigrdataset = event->sigrdataset;
-                       }
-               }
-       }
-
-       /*
-        * Find or create the cache node.
-        */
-       node = NULL;
-       result = dns_db_findnode(fctx->cache, name, ISC_TRUE, &node);
-       if (result != ISC_R_SUCCESS)
-               return (result);
-
-       /*
-        * Cache or validate each cacheable rdataset.
-        */
-       fail = ISC_TF((fctx->res->options & DNS_RESOLVER_CHECKNAMESFAIL) != 0);
-       for (rdataset = ISC_LIST_HEAD(name->list);
-            rdataset != NULL;
-            rdataset = ISC_LIST_NEXT(rdataset, link)) {
-               if (!CACHE(rdataset))
-                       continue;
-               if (CHECKNAMES(rdataset)) {
-                       char namebuf[DNS_NAME_FORMATSIZE];
-                       char typebuf[DNS_RDATATYPE_FORMATSIZE];
-                       char classbuf[DNS_RDATATYPE_FORMATSIZE];
-
-                       dns_name_format(name, namebuf, sizeof(namebuf));
-                       dns_rdatatype_format(rdataset->type, typebuf,
-                                            sizeof(typebuf));
-                       dns_rdataclass_format(rdataset->rdclass, classbuf,
-                                             sizeof(classbuf));
-                       isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,  
-                                     DNS_LOGMODULE_RESOLVER, ISC_LOG_NOTICE,
-                                     "check-names %s %s/%s/%s", 
-                                     fail ? "failure" : "warning",
-                                     namebuf, typebuf, classbuf);
-                       if (fail) {
-                               if (ANSWER(rdataset)) {
-                                       dns_db_detachnode(fctx->cache, &node);
-                                       return (DNS_R_BADNAME);
-                               }
-                               continue;
-                       }
-               }
-
-               /*
-                * Enforce the configure maximum cache TTL.
-                */
-               if (rdataset->ttl > res->view->maxcachettl)
-                       rdataset->ttl = res->view->maxcachettl;
-
-               /*
-                * If this rrset is in a secure domain, do DNSSEC validation
-                * for it, unless it is glue.
-                */
-               if (secure_domain && rdataset->trust != dns_trust_glue) {
-                       /*
-                        * RRSIGs are validated as part of validating the
-                        * type they cover.
-                        */
-                       if (rdataset->type == dns_rdatatype_rrsig)
-                               continue;
-                       /*
-                        * Find the SIG for this rdataset, if we have it.
-                        */
-                       for (sigrdataset = ISC_LIST_HEAD(name->list);
-                            sigrdataset != NULL;
-                            sigrdataset = ISC_LIST_NEXT(sigrdataset, link)) {
-                               if (sigrdataset->type == dns_rdatatype_rrsig &&
-                                   sigrdataset->covers == rdataset->type)
-                                       break;
-                       }
-                       if (sigrdataset == NULL) {
-                               if (!ANSWER(rdataset) && need_validation) {
-                                       /*
-                                        * Ignore non-answer rdatasets that
-                                        * are missing signatures.
-                                        */
-                                       continue;
-                               }
-                       }
-
-                       /*
-                        * Normalize the rdataset and sigrdataset TTLs.
-                        */
-                       if (sigrdataset != NULL) {
-                               rdataset->ttl = ISC_MIN(rdataset->ttl,
-                                                       sigrdataset->ttl);
-                               sigrdataset->ttl = rdataset->ttl;
-                       }
-
-                       /*
-                        * Cache this rdataset/sigrdataset pair as
-                        * pending data.
-                        */
-                       rdataset->trust = dns_trust_pending;
-                       if (sigrdataset != NULL)
-                               sigrdataset->trust = dns_trust_pending;
-                       if (!need_validation)
-                               addedrdataset = ardataset;
-                       else
-                               addedrdataset = NULL;
-                       result = dns_db_addrdataset(fctx->cache, node, NULL,
-                                                   now, rdataset, 0,
-                                                   addedrdataset);
-                       if (result == DNS_R_UNCHANGED) {
-                               result = ISC_R_SUCCESS;
-                               if (!need_validation &&
-                                   ardataset != NULL &&
-                                   ardataset->type == 0) {
-                                       /*
-                                        * The answer in the cache is better
-                                        * than the answer we found, and is
-                                        * a negative cache entry, so we
-                                        * must set eresult appropriately.
-                                        */
-                                       if (NXDOMAIN(ardataset))
-                                               eresult = DNS_R_NCACHENXDOMAIN;
-                                       else
-                                               eresult = DNS_R_NCACHENXRRSET;
-                                       /*
-                                        * We have a negative response from
-                                        * the cache so don't attempt to
-                                        * add the RRSIG rrset.
-                                        */
-                                       continue;
-                               }
-                       }
-                       if (result != ISC_R_SUCCESS)
-                               break;
-                       if (sigrdataset != NULL) {
-                               if (!need_validation)
-                                       addedrdataset = asigrdataset;
-                               else
-                                       addedrdataset = NULL;
-                               result = dns_db_addrdataset(fctx->cache,
-                                                           node, NULL, now,
-                                                           sigrdataset, 0,
-                                                           addedrdataset);
-                               if (result == DNS_R_UNCHANGED)
-                                       result = ISC_R_SUCCESS;
-                               if (result != ISC_R_SUCCESS)
-                                       break;
-                       } else if (!ANSWER(rdataset))
-                               continue;
-
-                       if (ANSWER(rdataset) && need_validation) {
-                               if (fctx->type != dns_rdatatype_any &&
-                                   fctx->type != dns_rdatatype_rrsig &&
-                                   fctx->type != dns_rdatatype_sig) {
-                                       /*
-                                        * This is The Answer.  We will
-                                        * validate it, but first we cache
-                                        * the rest of the response - it may
-                                        * contain useful keys.
-                                        */
-                                       INSIST(valrdataset == NULL &&
-                                              valsigrdataset == NULL);
-                                       valrdataset = rdataset;
-                                       valsigrdataset = sigrdataset;
-                               } else {
-                                       /*
-                                        * This is one of (potentially)
-                                        * multiple answers to an ANY
-                                        * or SIG query.  To keep things
-                                        * simple, we just start the
-                                        * validator right away rather
-                                        * than caching first and
-                                        * having to remember which
-                                        * rdatasets needed validation.
-                                        */
-                                       result = valcreate(fctx, addrinfo,
-                                                          name, rdataset->type,
-                                                          rdataset,
-                                                          sigrdataset,
-                                                          valoptions, task);
-                                       /*
-                                        * Defer any further validations.
-                                        * This prevents multiple validators
-                                        * from manipulating fctx->rmessage
-                                        * simultaniously.
-                                        */
-                                       valoptions |= DNS_VALIDATOR_DEFER;
-                               }
-                       } else if (CHAINING(rdataset)) {
-                               if (rdataset->type == dns_rdatatype_cname)
-                                       eresult = DNS_R_CNAME;
-                               else {
-                                       INSIST(rdataset->type ==
-                                              dns_rdatatype_dname);
-                                       eresult = DNS_R_DNAME;
-                               }
-                       }
-               } else if (!EXTERNAL(rdataset)) {
-                       /*
-                        * It's OK to cache this rdataset now.
-                        */
-                       if (ANSWER(rdataset))
-                               addedrdataset = ardataset;
-                       else if (ANSWERSIG(rdataset))
-                               addedrdataset = asigrdataset;
-                       else
-                               addedrdataset = NULL;
-                       if (CHAINING(rdataset)) {
-                               if (rdataset->type == dns_rdatatype_cname)
-                                       eresult = DNS_R_CNAME;
-                               else {
-                                       INSIST(rdataset->type ==
-                                              dns_rdatatype_dname);
-                                       eresult = DNS_R_DNAME;
-                               }
-                       }
-                       if (rdataset->trust == dns_trust_glue &&
-                           (rdataset->type == dns_rdatatype_ns ||
-                            (rdataset->type == dns_rdatatype_rrsig &&
-                             rdataset->covers == dns_rdatatype_ns))) {
-                               /*
-                                * If the trust level is 'dns_trust_glue'
-                                * then we are adding data from a referral
-                                * we got while executing the search algorithm.
-                                * New referral data always takes precedence
-                                * over the existing cache contents.
-                                */
-                               options = DNS_DBADD_FORCE;
-                       } else
-                               options = 0;
-                       /*
-                        * Now we can add the rdataset.
-                        */
-                       result = dns_db_addrdataset(fctx->cache,
-                                                   node, NULL, now,
-                                                   rdataset,
-                                                   options,
-                                                   addedrdataset);
-                       if (result == DNS_R_UNCHANGED) {
-                               if (ANSWER(rdataset) &&
-                                   ardataset != NULL &&
-                                   ardataset->type == 0) {
-                                       /*
-                                        * The answer in the cache is better
-                                        * than the answer we found, and is
-                                        * a negative cache entry, so we
-                                        * must set eresult appropriately.
-                                        */
-                                       if (NXDOMAIN(ardataset))
-                                               eresult = DNS_R_NCACHENXDOMAIN;
-                                       else
-                                               eresult = DNS_R_NCACHENXRRSET;
-                               }
-                               result = ISC_R_SUCCESS;
-                       } else if (result != ISC_R_SUCCESS)
-                               break;
-               }
-       }
-
-       if (valrdataset != NULL)
-               result = valcreate(fctx, addrinfo, name, fctx->type,
-                                  valrdataset, valsigrdataset, valoptions,
-                                  task);
-
-       if (result == ISC_R_SUCCESS && have_answer) {
-               fctx->attributes |= FCTX_ATTR_HAVEANSWER;
-               if (event != NULL) {
-                       /*
-                        * Negative results must be indicated in event->result.
-                        */
-                       if (dns_rdataset_isassociated(event->rdataset) &&
-                           event->rdataset->type == dns_rdatatype_none) {
-                               INSIST(eresult == DNS_R_NCACHENXDOMAIN ||
-                                      eresult == DNS_R_NCACHENXRRSET);
-                       }
-                       event->result = eresult;
-                       dns_db_attach(fctx->cache, adbp);
-                       dns_db_transfernode(fctx->cache, &node, anodep);
-                       clone_results(fctx);
-               }
-       }
-
-       if (node != NULL)
-               dns_db_detachnode(fctx->cache, &node);
-
-       return (result);
+        dns_rdataset_t *rdataset, *sigrdataset;
+        dns_rdataset_t *addedrdataset, *ardataset, *asigrdataset;
+        dns_rdataset_t *valrdataset = NULL, *valsigrdataset = NULL;
+        dns_dbnode_t *node, **anodep;
+        dns_db_t **adbp;
+        dns_name_t *aname;
+        dns_resolver_t *res;
+        isc_boolean_t need_validation, secure_domain, have_answer;
+        isc_result_t result, eresult;
+        dns_fetchevent_t *event;
+        unsigned int options;
+        isc_task_t *task;
+        isc_boolean_t fail;
+        unsigned int valoptions = 0;
+
+        /*
+         * The appropriate bucket lock must be held.
+         */
+
+        res = fctx->res;
+        need_validation = ISC_FALSE;
+        secure_domain = ISC_FALSE;
+        have_answer = ISC_FALSE;
+        eresult = ISC_R_SUCCESS;
+        task = res->buckets[fctx->bucketnum].task;
+
+        /*
+         * Is DNSSEC validation required for this name?
+         */
+        if (res->view->enablevalidation) {
+                result = dns_keytable_issecuredomain(res->view->secroots, name,
+                                                     &secure_domain);
+                if (result != ISC_R_SUCCESS)
+                        return (result);
+
+                if (!secure_domain && res->view->dlv != NULL) {
+                        valoptions = DNS_VALIDATOR_DLV;
+                        secure_domain = ISC_TRUE;
+                }
+        }
+
+        if ((fctx->options & DNS_FETCHOPT_NOVALIDATE) != 0)
+                need_validation = ISC_FALSE;
+        else
+                need_validation = secure_domain;
+
+        adbp = NULL;
+        aname = NULL;
+        anodep = NULL;
+        ardataset = NULL;
+        asigrdataset = NULL;
+        event = NULL;
+        if ((name->attributes & DNS_NAMEATTR_ANSWER) != 0 &&
+            !need_validation) {
+                have_answer = ISC_TRUE;
+                event = ISC_LIST_HEAD(fctx->events);
+                if (event != NULL) {
+                        adbp = &event->db;
+                        aname = dns_fixedname_name(&event->foundname);
+                        result = dns_name_copy(name, aname, NULL);
+                        if (result != ISC_R_SUCCESS)
+                                return (result);
+                        anodep = &event->node;
+                        /*
+                         * If this is an ANY, SIG or RRSIG query, we're not
+                         * going to return any rdatasets, unless we encountered
+                         * a CNAME or DNAME as "the answer".  In this case,
+                         * we're going to return DNS_R_CNAME or DNS_R_DNAME
+                         * and we must set up the rdatasets.
+                         */
+                        if ((fctx->type != dns_rdatatype_any &&
+                             fctx->type != dns_rdatatype_rrsig &&
+                             fctx->type != dns_rdatatype_sig) ||
+                            (name->attributes & DNS_NAMEATTR_CHAINING) != 0) {
+                                ardataset = event->rdataset;
+                                asigrdataset = event->sigrdataset;
+                        }
+                }
+        }
+
+        /*
+         * Find or create the cache node.
+         */
+        node = NULL;
+        result = dns_db_findnode(fctx->cache, name, ISC_TRUE, &node);
+        if (result != ISC_R_SUCCESS)
+                return (result);
+
+        /*
+         * Cache or validate each cacheable rdataset.
+         */
+        fail = ISC_TF((fctx->res->options & DNS_RESOLVER_CHECKNAMESFAIL) != 0);
+        for (rdataset = ISC_LIST_HEAD(name->list);
+             rdataset != NULL;
+             rdataset = ISC_LIST_NEXT(rdataset, link)) {
+                if (!CACHE(rdataset))
+                        continue;
+                if (CHECKNAMES(rdataset)) {
+                        char namebuf[DNS_NAME_FORMATSIZE];
+                        char typebuf[DNS_RDATATYPE_FORMATSIZE];
+                        char classbuf[DNS_RDATATYPE_FORMATSIZE];
+
+                        dns_name_format(name, namebuf, sizeof(namebuf));
+                        dns_rdatatype_format(rdataset->type, typebuf,
+                                             sizeof(typebuf));
+                        dns_rdataclass_format(rdataset->rdclass, classbuf,
+                                              sizeof(classbuf));
+                        isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,
+                                      DNS_LOGMODULE_RESOLVER, ISC_LOG_NOTICE,
+                                      "check-names %s %s/%s/%s",
+                                      fail ? "failure" : "warning",
+                                      namebuf, typebuf, classbuf);
+                        if (fail) {
+                                if (ANSWER(rdataset)) {
+                                        dns_db_detachnode(fctx->cache, &node);
+                                        return (DNS_R_BADNAME);
+                                }
+                                continue;
+                        }
+                }
+
+                /*
+                 * Enforce the configure maximum cache TTL.
+                 */
+                if (rdataset->ttl > res->view->maxcachettl)
+                        rdataset->ttl = res->view->maxcachettl;
+
+                /*
+                 * If this rrset is in a secure domain, do DNSSEC validation
+                 * for it, unless it is glue.
+                 */
+                if (secure_domain && rdataset->trust != dns_trust_glue) {
+                        /*
+                         * RRSIGs are validated as part of validating the
+                         * type they cover.
+                         */
+                        if (rdataset->type == dns_rdatatype_rrsig)
+                                continue;
+                        /*
+                         * Find the SIG for this rdataset, if we have it.
+                         */
+                        for (sigrdataset = ISC_LIST_HEAD(name->list);
+                             sigrdataset != NULL;
+                             sigrdataset = ISC_LIST_NEXT(sigrdataset, link)) {
+                                if (sigrdataset->type == dns_rdatatype_rrsig &&
+                                    sigrdataset->covers == rdataset->type)
+                                        break;
+                        }
+                        if (sigrdataset == NULL) {
+                                if (!ANSWER(rdataset) && need_validation) {
+                                        /*
+                                         * Ignore non-answer rdatasets that
+                                         * are missing signatures.
+                                         */
+                                        continue;
+                                }
+                        }
+
+                        /*
+                         * Normalize the rdataset and sigrdataset TTLs.
+                         */
+                        if (sigrdataset != NULL) {
+                                rdataset->ttl = ISC_MIN(rdataset->ttl,
+                                                        sigrdataset->ttl);
+                                sigrdataset->ttl = rdataset->ttl;
+                        }
+
+                        /*
+                         * Cache this rdataset/sigrdataset pair as
+                         * pending data.
+                         */
+                        rdataset->trust = dns_trust_pending;
+                        if (sigrdataset != NULL)
+                                sigrdataset->trust = dns_trust_pending;
+                        if (!need_validation)
+                                addedrdataset = ardataset;
+                        else
+                                addedrdataset = NULL;
+                        result = dns_db_addrdataset(fctx->cache, node, NULL,
+                                                    now, rdataset, 0,
+                                                    addedrdataset);
+                        if (result == DNS_R_UNCHANGED) {
+                                result = ISC_R_SUCCESS;
+                                if (!need_validation &&
+                                    ardataset != NULL &&
+                                    ardataset->type == 0) {
+                                        /*
+                                         * The answer in the cache is better
+                                         * than the answer we found, and is
+                                         * a negative cache entry, so we
+                                         * must set eresult appropriately.
+                                         */
+                                        if (NXDOMAIN(ardataset))
+                                                eresult = DNS_R_NCACHENXDOMAIN;
+                                        else
+                                                eresult = DNS_R_NCACHENXRRSET;
+                                        /*
+                                         * We have a negative response from
+                                         * the cache so don't attempt to
+                                         * add the RRSIG rrset.
+                                         */
+                                        continue;
+                                }
+                        }
+                        if (result != ISC_R_SUCCESS)
+                                break;
+                        if (sigrdataset != NULL) {
+                                if (!need_validation)
+                                        addedrdataset = asigrdataset;
+                                else
+                                        addedrdataset = NULL;
+                                result = dns_db_addrdataset(fctx->cache,
+                                                            node, NULL, now,
+                                                            sigrdataset, 0,
+                                                            addedrdataset);
+                                if (result == DNS_R_UNCHANGED)
+                                        result = ISC_R_SUCCESS;
+                                if (result != ISC_R_SUCCESS)
+                                        break;
+                        } else if (!ANSWER(rdataset))
+                                continue;
+
+                        if (ANSWER(rdataset) && need_validation) {
+                                if (fctx->type != dns_rdatatype_any &&
+                                    fctx->type != dns_rdatatype_rrsig &&
+                                    fctx->type != dns_rdatatype_sig) {
+                                        /*
+                                         * This is The Answer.  We will
+                                         * validate it, but first we cache
+                                         * the rest of the response - it may
+                                         * contain useful keys.
+                                         */
+                                        INSIST(valrdataset == NULL &&
+                                               valsigrdataset == NULL);
+                                        valrdataset = rdataset;
+                                        valsigrdataset = sigrdataset;
+                                } else {
+                                        /*
+                                         * This is one of (potentially)
+                                         * multiple answers to an ANY
+                                         * or SIG query.  To keep things
+                                         * simple, we just start the
+                                         * validator right away rather
+                                         * than caching first and
+                                         * having to remember which
+                                         * rdatasets needed validation.
+                                         */
+                                        result = valcreate(fctx, addrinfo,
+                                                           name, rdataset->type,
+                                                           rdataset,
+                                                           sigrdataset,
+                                                           valoptions, task);
+                                        /*
+                                         * Defer any further validations.
+                                         * This prevents multiple validators
+                                         * from manipulating fctx->rmessage
+                                         * simultaniously.
+                                         */
+                                        valoptions |= DNS_VALIDATOR_DEFER;
+                                }
+                        } else if (CHAINING(rdataset)) {
+                                if (rdataset->type == dns_rdatatype_cname)
+                                        eresult = DNS_R_CNAME;
+                                else {
+                                        INSIST(rdataset->type ==
+                                               dns_rdatatype_dname);
+                                        eresult = DNS_R_DNAME;
+                                }
+                        }
+                } else if (!EXTERNAL(rdataset)) {
+                        /*
+                         * It's OK to cache this rdataset now.
+                         */
+                        if (ANSWER(rdataset))
+                                addedrdataset = ardataset;
+                        else if (ANSWERSIG(rdataset))
+                                addedrdataset = asigrdataset;
+                        else
+                                addedrdataset = NULL;
+                        if (CHAINING(rdataset)) {
+                                if (rdataset->type == dns_rdatatype_cname)
+                                        eresult = DNS_R_CNAME;
+                                else {
+                                        INSIST(rdataset->type ==
+                                               dns_rdatatype_dname);
+                                        eresult = DNS_R_DNAME;
+                                }
+                        }
+                        if (rdataset->trust == dns_trust_glue &&
+                            (rdataset->type == dns_rdatatype_ns ||
+                             (rdataset->type == dns_rdatatype_rrsig &&
+                              rdataset->covers == dns_rdatatype_ns))) {
+                                /*
+                                 * If the trust level is 'dns_trust_glue'
+                                 * then we are adding data from a referral
+                                 * we got while executing the search algorithm.
+                                 * New referral data always takes precedence
+                                 * over the existing cache contents.
+                                 */
+                                options = DNS_DBADD_FORCE;
+                        } else
+                                options = 0;
+                        /*
+                         * Now we can add the rdataset.
+                         */
+                        result = dns_db_addrdataset(fctx->cache,
+                                                    node, NULL, now,
+                                                    rdataset,
+                                                    options,
+                                                    addedrdataset);
+                        if (result == DNS_R_UNCHANGED) {
+                                if (ANSWER(rdataset) &&
+                                    ardataset != NULL &&
+                                    ardataset->type == 0) {
+                                        /*
+                                         * The answer in the cache is better
+                                         * than the answer we found, and is
+                                         * a negative cache entry, so we
+                                         * must set eresult appropriately.
+                                         */
+                                        if (NXDOMAIN(ardataset))
+                                                eresult = DNS_R_NCACHENXDOMAIN;
+                                        else
+                                                eresult = DNS_R_NCACHENXRRSET;
+                                }
+                                result = ISC_R_SUCCESS;
+                        } else if (result != ISC_R_SUCCESS)
+                                break;
+                }
+        }
+
+        if (valrdataset != NULL)
+                result = valcreate(fctx, addrinfo, name, fctx->type,
+                                   valrdataset, valsigrdataset, valoptions,
+                                   task);
+
+        if (result == ISC_R_SUCCESS && have_answer) {
+                fctx->attributes |= FCTX_ATTR_HAVEANSWER;
+                if (event != NULL) {
+                        /*
+                         * Negative results must be indicated in event->result.
+                         */
+                        if (dns_rdataset_isassociated(event->rdataset) &&
+                            event->rdataset->type == dns_rdatatype_none) {
+                                INSIST(eresult == DNS_R_NCACHENXDOMAIN ||
+                                       eresult == DNS_R_NCACHENXRRSET);
+                        }
+                        event->result = eresult;
+                        dns_db_attach(fctx->cache, adbp);
+                        dns_db_transfernode(fctx->cache, &node, anodep);
+                        clone_results(fctx);
+                }
+        }
+
+        if (node != NULL)
+                dns_db_detachnode(fctx->cache, &node);
+
+        return (result);
 }
 
 static inline isc_result_t
 cache_message(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, isc_stdtime_t now)
 {
-       isc_result_t result;
-       dns_section_t section;
-       dns_name_t *name;
-
-       FCTXTRACE("cache_message");
-
-       fctx->attributes &= ~FCTX_ATTR_WANTCACHE;
-
-       LOCK(&fctx->res->buckets[fctx->bucketnum].lock);
-
-       for (section = DNS_SECTION_ANSWER;
-            section <= DNS_SECTION_ADDITIONAL;
-            section++) {
-               result = dns_message_firstname(fctx->rmessage, section);
-               while (result == ISC_R_SUCCESS) {
-                       name = NULL;
-                       dns_message_currentname(fctx->rmessage, section,
-                                               &name);
-                       if ((name->attributes & DNS_NAMEATTR_CACHE) != 0) {
-                               result = cache_name(fctx, name, addrinfo, now);
-                               if (result != ISC_R_SUCCESS)
-                                       break;
-                       }
-                       result = dns_message_nextname(fctx->rmessage, section);
-               }
-               if (result != ISC_R_NOMORE)
-                       break;
-       }
-       if (result == ISC_R_NOMORE)
-               result = ISC_R_SUCCESS;
-
-       UNLOCK(&fctx->res->buckets[fctx->bucketnum].lock);
-
-       return (result);
+        isc_result_t result;
+        dns_section_t section;
+        dns_name_t *name;
+
+        FCTXTRACE("cache_message");
+
+        fctx->attributes &= ~FCTX_ATTR_WANTCACHE;
+
+        LOCK(&fctx->res->buckets[fctx->bucketnum].lock);
+
+        for (section = DNS_SECTION_ANSWER;
+             section <= DNS_SECTION_ADDITIONAL;
+             section++) {
+                result = dns_message_firstname(fctx->rmessage, section);
+                while (result == ISC_R_SUCCESS) {
+                        name = NULL;
+                        dns_message_currentname(fctx->rmessage, section,
+                                                &name);
+                        if ((name->attributes & DNS_NAMEATTR_CACHE) != 0) {
+                                result = cache_name(fctx, name, addrinfo, now);
+                                if (result != ISC_R_SUCCESS)
+                                        break;
+                        }
+                        result = dns_message_nextname(fctx->rmessage, section);
+                }
+                if (result != ISC_R_NOMORE)
+                        break;
+        }
+        if (result == ISC_R_NOMORE)
+                result = ISC_R_SUCCESS;
+
+        UNLOCK(&fctx->res->buckets[fctx->bucketnum].lock);
+
+        return (result);
 }
 
 /*
@@ -4139,385 +4176,385 @@ cache_message(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, isc_stdtime_t now)
  */
 static isc_result_t
 ncache_adderesult(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node,
-                 dns_rdatatype_t covers, isc_stdtime_t now, dns_ttl_t maxttl,
-                 dns_rdataset_t *ardataset,
-                 isc_result_t *eresultp)
+                  dns_rdatatype_t covers, isc_stdtime_t now, dns_ttl_t maxttl,
+                  dns_rdataset_t *ardataset,
+                  isc_result_t *eresultp)
 {
-       isc_result_t result;
-       dns_rdataset_t rdataset;
-
-       if (ardataset == NULL) {
-               dns_rdataset_init(&rdataset);
-               ardataset = &rdataset;
-       }
-       result = dns_ncache_add(message, cache, node, covers, now,
-                               maxttl, ardataset);
-       if (result == DNS_R_UNCHANGED || result == ISC_R_SUCCESS) {
-               /*
-                * If the cache now contains a negative entry and we
-                * care about whether it is DNS_R_NCACHENXDOMAIN or
-                * DNS_R_NCACHENXRRSET then extract it.
-                */
-               if (ardataset->type == 0) {
-                       /*
-                        * The cache data is a negative cache entry.
-                        */
-                       if (NXDOMAIN(ardataset))
-                               *eresultp = DNS_R_NCACHENXDOMAIN;
-                       else
-                               *eresultp = DNS_R_NCACHENXRRSET;
-               } else {
-                       /*
-                        * Either we don't care about the nature of the
-                        * cache rdataset (because no fetch is interested
-                        * in the outcome), or the cache rdataset is not
-                        * a negative cache entry.  Whichever case it is,
-                        * we can return success.
-                        *
-                        * XXXRTH  There's a CNAME/DNAME problem here.
-                        */
-                       *eresultp = ISC_R_SUCCESS;
-               }
-               result = ISC_R_SUCCESS;
-       }
-       if (ardataset == &rdataset && dns_rdataset_isassociated(ardataset))
-               dns_rdataset_disassociate(ardataset);
-
-       return (result);
+        isc_result_t result;
+        dns_rdataset_t rdataset;
+
+        if (ardataset == NULL) {
+                dns_rdataset_init(&rdataset);
+                ardataset = &rdataset;
+        }
+        result = dns_ncache_add(message, cache, node, covers, now,
+                                maxttl, ardataset);
+        if (result == DNS_R_UNCHANGED || result == ISC_R_SUCCESS) {
+                /*
+                 * If the cache now contains a negative entry and we
+                 * care about whether it is DNS_R_NCACHENXDOMAIN or
+                 * DNS_R_NCACHENXRRSET then extract it.
+                 */
+                if (ardataset->type == 0) {
+                        /*
+                         * The cache data is a negative cache entry.
+                         */
+                        if (NXDOMAIN(ardataset))
+                                *eresultp = DNS_R_NCACHENXDOMAIN;
+                        else
+                                *eresultp = DNS_R_NCACHENXRRSET;
+                } else {
+                        /*
+                         * Either we don't care about the nature of the
+                         * cache rdataset (because no fetch is interested
+                         * in the outcome), or the cache rdataset is not
+                         * a negative cache entry.  Whichever case it is,
+                         * we can return success.
+                         *
+                         * XXXRTH  There's a CNAME/DNAME problem here.
+                         */
+                        *eresultp = ISC_R_SUCCESS;
+                }
+                result = ISC_R_SUCCESS;
+        }
+        if (ardataset == &rdataset && dns_rdataset_isassociated(ardataset))
+                dns_rdataset_disassociate(ardataset);
+
+        return (result);
 }
 
 static inline isc_result_t
 ncache_message(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo,
-              dns_rdatatype_t covers, isc_stdtime_t now)
+               dns_rdatatype_t covers, isc_stdtime_t now)
 {
-       isc_result_t result, eresult;
-       dns_name_t *name;
-       dns_resolver_t *res;
-       dns_db_t **adbp;
-       dns_dbnode_t *node, **anodep;
-       dns_rdataset_t *ardataset;
-       isc_boolean_t need_validation, secure_domain;
-       dns_name_t *aname;
-       dns_fetchevent_t *event;
-       isc_uint32_t ttl;
-       unsigned int valoptions = 0;
-
-       FCTXTRACE("ncache_message");
-
-       fctx->attributes &= ~FCTX_ATTR_WANTNCACHE;
-
-       res = fctx->res;
-       need_validation = ISC_FALSE;
-       secure_domain = ISC_FALSE;
-       eresult = ISC_R_SUCCESS;
-       name = &fctx->name;
-       node = NULL;
-
-       /*
-        * XXXMPA remove when we follow cnames and adjust the setting
-        * of FCTX_ATTR_WANTNCACHE in noanswer_response().
-        */
-       INSIST(fctx->rmessage->counts[DNS_SECTION_ANSWER] == 0);
-
-       /*
-        * Is DNSSEC validation required for this name?
-        */
-       if (fctx->res->view->enablevalidation) {
-               result = dns_keytable_issecuredomain(res->view->secroots, name,
-                                                    &secure_domain);
-               if (result != ISC_R_SUCCESS)
-                       return (result);
-
-               if (!secure_domain && res->view->dlv != NULL) {
-                       valoptions = DNS_VALIDATOR_DLV;
-                       secure_domain = ISC_TRUE;
-               }
-       }
-
-       if ((fctx->options & DNS_FETCHOPT_NOVALIDATE) != 0)
-               need_validation = ISC_FALSE;
-       else
-               need_validation = secure_domain;
-
-       if (secure_domain) {
-               /*
-                * Mark all rdatasets as pending.
-                */
-               dns_rdataset_t *trdataset;
-               dns_name_t *tname;
-
-               result = dns_message_firstname(fctx->rmessage,
-                                              DNS_SECTION_AUTHORITY);
-               while (result == ISC_R_SUCCESS) {
-                       tname = NULL;
-                       dns_message_currentname(fctx->rmessage,
-                                               DNS_SECTION_AUTHORITY,
-                                               &tname);
-                       for (trdataset = ISC_LIST_HEAD(tname->list);
-                            trdataset != NULL;
-                            trdataset = ISC_LIST_NEXT(trdataset, link))
-                               trdataset->trust = dns_trust_pending;
-                       result = dns_message_nextname(fctx->rmessage,
-                                                     DNS_SECTION_AUTHORITY);
-               }
-               if (result != ISC_R_NOMORE)
-                       return (result);
-
-       }
-
-       if (need_validation) {
-               /*
-                * Do negative response validation.
-                */
-               result = valcreate(fctx, addrinfo, name, fctx->type,
-                                  NULL, NULL, valoptions,
-                                  res->buckets[fctx->bucketnum].task);
-               /*
-                * If validation is necessary, return now.  Otherwise continue
-                * to process the message, letting the validation complete
-                * in its own good time.
-                */
-               return (result);
-       }
-
-       LOCK(&res->buckets[fctx->bucketnum].lock);
-
-       adbp = NULL;
-       aname = NULL;
-       anodep = NULL;
-       ardataset = NULL;
-       if (!HAVE_ANSWER(fctx)) {
-               event = ISC_LIST_HEAD(fctx->events);
-               if (event != NULL) {
-                       adbp = &event->db;
-                       aname = dns_fixedname_name(&event->foundname);
-                       result = dns_name_copy(name, aname, NULL);
-                       if (result != ISC_R_SUCCESS)
-                               goto unlock;
-                       anodep = &event->node;
-                       ardataset = event->rdataset;
-               }
-       } else
-               event = NULL;
-
-       result = dns_db_findnode(fctx->cache, name, ISC_TRUE, &node);
-       if (result != ISC_R_SUCCESS)
-               goto unlock;
-
-       /*
-        * If we are asking for a SOA record set the cache time
-        * to zero to facilitate locating the containing zone of
-        * a arbitary zone.
-        */
-       ttl = fctx->res->view->maxncachettl;
-       if (fctx->type == dns_rdatatype_soa &&
-           covers == dns_rdatatype_any)
-               ttl = 0;
-
-       result = ncache_adderesult(fctx->rmessage, fctx->cache, node,
-                                  covers, now, ttl, ardataset, &eresult);
-       if (result != ISC_R_SUCCESS)
-               goto unlock;
-
-       if (!HAVE_ANSWER(fctx)) {
-               fctx->attributes |= FCTX_ATTR_HAVEANSWER;
-               if (event != NULL) {
-                       event->result = eresult;
-                       dns_db_attach(fctx->cache, adbp);
-                       dns_db_transfernode(fctx->cache, &node, anodep);
-                       clone_results(fctx);
-               }
-       }
+        isc_result_t result, eresult;
+        dns_name_t *name;
+        dns_resolver_t *res;
+        dns_db_t **adbp;
+        dns_dbnode_t *node, **anodep;
+        dns_rdataset_t *ardataset;
+        isc_boolean_t need_validation, secure_domain;
+        dns_name_t *aname;
+        dns_fetchevent_t *event;
+        isc_uint32_t ttl;
+        unsigned int valoptions = 0;
+
+        FCTXTRACE("ncache_message");
+
+        fctx->attributes &= ~FCTX_ATTR_WANTNCACHE;
+
+        res = fctx->res;
+        need_validation = ISC_FALSE;
+        secure_domain = ISC_FALSE;
+        eresult = ISC_R_SUCCESS;
+        name = &fctx->name;
+        node = NULL;
+
+        /*
+         * XXXMPA remove when we follow cnames and adjust the setting
+         * of FCTX_ATTR_WANTNCACHE in noanswer_response().
+         */
+        INSIST(fctx->rmessage->counts[DNS_SECTION_ANSWER] == 0);
+
+        /*
+         * Is DNSSEC validation required for this name?
+         */
+        if (fctx->res->view->enablevalidation) {
+                result = dns_keytable_issecuredomain(res->view->secroots, name,
+                                                     &secure_domain);
+                if (result != ISC_R_SUCCESS)
+                        return (result);
+
+                if (!secure_domain && res->view->dlv != NULL) {
+                        valoptions = DNS_VALIDATOR_DLV;
+                        secure_domain = ISC_TRUE;
+                }
+        }
+
+        if ((fctx->options & DNS_FETCHOPT_NOVALIDATE) != 0)
+                need_validation = ISC_FALSE;
+        else
+                need_validation = secure_domain;
+
+        if (secure_domain) {
+                /*
+                 * Mark all rdatasets as pending.
+                 */
+                dns_rdataset_t *trdataset;
+                dns_name_t *tname;
+
+                result = dns_message_firstname(fctx->rmessage,
+                                               DNS_SECTION_AUTHORITY);
+                while (result == ISC_R_SUCCESS) {
+                        tname = NULL;
+                        dns_message_currentname(fctx->rmessage,
+                                                DNS_SECTION_AUTHORITY,
+                                                &tname);
+                        for (trdataset = ISC_LIST_HEAD(tname->list);
+                             trdataset != NULL;
+                             trdataset = ISC_LIST_NEXT(trdataset, link))
+                                trdataset->trust = dns_trust_pending;
+                        result = dns_message_nextname(fctx->rmessage,
+                                                      DNS_SECTION_AUTHORITY);
+                }
+                if (result != ISC_R_NOMORE)
+                        return (result);
+
+        }
+
+        if (need_validation) {
+                /*
+                 * Do negative response validation.
+                 */
+                result = valcreate(fctx, addrinfo, name, fctx->type,
+                                   NULL, NULL, valoptions,
+                                   res->buckets[fctx->bucketnum].task);
+                /*
+                 * If validation is necessary, return now.  Otherwise continue
+                 * to process the message, letting the validation complete
+                 * in its own good time.
+                 */
+                return (result);
+        }
+
+        LOCK(&res->buckets[fctx->bucketnum].lock);
+
+        adbp = NULL;
+        aname = NULL;
+        anodep = NULL;
+        ardataset = NULL;
+        if (!HAVE_ANSWER(fctx)) {
+                event = ISC_LIST_HEAD(fctx->events);
+                if (event != NULL) {
+                        adbp = &event->db;
+                        aname = dns_fixedname_name(&event->foundname);
+                        result = dns_name_copy(name, aname, NULL);
+                        if (result != ISC_R_SUCCESS)
+                                goto unlock;
+                        anodep = &event->node;
+                        ardataset = event->rdataset;
+                }
+        } else
+                event = NULL;
+
+        result = dns_db_findnode(fctx->cache, name, ISC_TRUE, &node);
+        if (result != ISC_R_SUCCESS)
+                goto unlock;
+
+        /*
+         * If we are asking for a SOA record set the cache time
+         * to zero to facilitate locating the containing zone of
+         * a arbitary zone.
+         */
+        ttl = fctx->res->view->maxncachettl;
+        if (fctx->type == dns_rdatatype_soa &&
+            covers == dns_rdatatype_any)
+                ttl = 0;
+
+        result = ncache_adderesult(fctx->rmessage, fctx->cache, node,
+                                   covers, now, ttl, ardataset, &eresult);
+        if (result != ISC_R_SUCCESS)
+                goto unlock;
+
+        if (!HAVE_ANSWER(fctx)) {
+                fctx->attributes |= FCTX_ATTR_HAVEANSWER;
+                if (event != NULL) {
+                        event->result = eresult;
+                        dns_db_attach(fctx->cache, adbp);
+                        dns_db_transfernode(fctx->cache, &node, anodep);
+                        clone_results(fctx);
+                }
+        }
 
  unlock:
-       UNLOCK(&res->buckets[fctx->bucketnum].lock);
+        UNLOCK(&res->buckets[fctx->bucketnum].lock);
 
-       if (node != NULL)
-               dns_db_detachnode(fctx->cache, &node);
+        if (node != NULL)
+                dns_db_detachnode(fctx->cache, &node);
 
-       return (result);
+        return (result);
 }
 
 static inline void
 mark_related(dns_name_t *name, dns_rdataset_t *rdataset,
-            isc_boolean_t external, isc_boolean_t gluing)
+             isc_boolean_t external, isc_boolean_t gluing)
 {
-       name->attributes |= DNS_NAMEATTR_CACHE;
-       if (gluing) {
-               rdataset->trust = dns_trust_glue;
-               /*
-                * Glue with 0 TTL causes problems.  We force the TTL to
-                * 1 second to prevent this.
-                */
-               if (rdataset->ttl == 0)
-                       rdataset->ttl = 1;
-       } else
-               rdataset->trust = dns_trust_additional;
-       /*
-        * Avoid infinite loops by only marking new rdatasets.
-        */
-       if (!CACHE(rdataset)) {
-               name->attributes |= DNS_NAMEATTR_CHASE;
-               rdataset->attributes |= DNS_RDATASETATTR_CHASE;
-       }
-       rdataset->attributes |= DNS_RDATASETATTR_CACHE;
-       if (external)
-               rdataset->attributes |= DNS_RDATASETATTR_EXTERNAL;
+        name->attributes |= DNS_NAMEATTR_CACHE;
+        if (gluing) {
+                rdataset->trust = dns_trust_glue;
+                /*
+                 * Glue with 0 TTL causes problems.  We force the TTL to
+                 * 1 second to prevent this.
+                 */
+                if (rdataset->ttl == 0)
+                        rdataset->ttl = 1;
+        } else
+                rdataset->trust = dns_trust_additional;
+        /*
+         * Avoid infinite loops by only marking new rdatasets.
+         */
+        if (!CACHE(rdataset)) {
+                name->attributes |= DNS_NAMEATTR_CHASE;
+                rdataset->attributes |= DNS_RDATASETATTR_CHASE;
+        }
+        rdataset->attributes |= DNS_RDATASETATTR_CACHE;
+        if (external)
+                rdataset->attributes |= DNS_RDATASETATTR_EXTERNAL;
 }
 
 static isc_result_t
 check_related(void *arg, dns_name_t *addname, dns_rdatatype_t type) {
-       fetchctx_t *fctx = arg;
-       isc_result_t result;
-       dns_name_t *name;
-       dns_rdataset_t *rdataset;
-       isc_boolean_t external;
-       dns_rdatatype_t rtype;
-       isc_boolean_t gluing;
-
-       REQUIRE(VALID_FCTX(fctx));
-
-       if (GLUING(fctx))
-               gluing = ISC_TRUE;
-       else
-               gluing = ISC_FALSE;
-       name = NULL;
-       rdataset = NULL;
-       result = dns_message_findname(fctx->rmessage, DNS_SECTION_ADDITIONAL,
-                                     addname, dns_rdatatype_any, 0, &name,
-                                     NULL);
-       if (result == ISC_R_SUCCESS) {
-               external = ISC_TF(!dns_name_issubdomain(name, &fctx->domain));
-               if (type == dns_rdatatype_a) {
-                       for (rdataset = ISC_LIST_HEAD(name->list);
-                            rdataset != NULL;
-                            rdataset = ISC_LIST_NEXT(rdataset, link)) {
-                               if (rdataset->type == dns_rdatatype_rrsig)
-                                       rtype = rdataset->covers;
-                               else
-                                       rtype = rdataset->type;
-                               if (rtype == dns_rdatatype_a ||
-                                   rtype == dns_rdatatype_aaaa)
-                                       mark_related(name, rdataset, external,
-                                                    gluing);
-                       }
-               } else {
-                       result = dns_message_findtype(name, type, 0,
-                                                     &rdataset);
-                       if (result == ISC_R_SUCCESS) {
-                               mark_related(name, rdataset, external, gluing);
-                               /*
-                                * Do we have its SIG too?
-                                */
-                               rdataset = NULL;
-                               result = dns_message_findtype(name,
-                                                     dns_rdatatype_rrsig,
-                                                     type, &rdataset);
-                               if (result == ISC_R_SUCCESS)
-                                       mark_related(name, rdataset, external,
-                                                    gluing);
-                       }
-               }
-       }
-
-       return (ISC_R_SUCCESS);
+        fetchctx_t *fctx = arg;
+        isc_result_t result;
+        dns_name_t *name;
+        dns_rdataset_t *rdataset;
+        isc_boolean_t external;
+        dns_rdatatype_t rtype;
+        isc_boolean_t gluing;
+
+        REQUIRE(VALID_FCTX(fctx));
+
+        if (GLUING(fctx))
+                gluing = ISC_TRUE;
+        else
+                gluing = ISC_FALSE;
+        name = NULL;
+        rdataset = NULL;
+        result = dns_message_findname(fctx->rmessage, DNS_SECTION_ADDITIONAL,
+                                      addname, dns_rdatatype_any, 0, &name,
+                                      NULL);
+        if (result == ISC_R_SUCCESS) {
+                external = ISC_TF(!dns_name_issubdomain(name, &fctx->domain));
+                if (type == dns_rdatatype_a) {
+                        for (rdataset = ISC_LIST_HEAD(name->list);
+                             rdataset != NULL;
+                             rdataset = ISC_LIST_NEXT(rdataset, link)) {
+                                if (rdataset->type == dns_rdatatype_rrsig)
+                                        rtype = rdataset->covers;
+                                else
+                                        rtype = rdataset->type;
+                                if (rtype == dns_rdatatype_a ||
+                                    rtype == dns_rdatatype_aaaa)
+                                        mark_related(name, rdataset, external,
+                                                     gluing);
+                        }
+                } else {
+                        result = dns_message_findtype(name, type, 0,
+                                                      &rdataset);
+                        if (result == ISC_R_SUCCESS) {
+                                mark_related(name, rdataset, external, gluing);
+                                /*
+                                 * Do we have its SIG too?
+                                 */
+                                rdataset = NULL;
+                                result = dns_message_findtype(name,
+                                                      dns_rdatatype_rrsig,
+                                                      type, &rdataset);
+                                if (result == ISC_R_SUCCESS)
+                                        mark_related(name, rdataset, external,
+                                                     gluing);
+                        }
+                }
+        }
+
+        return (ISC_R_SUCCESS);
 }
 
 static void
 chase_additional(fetchctx_t *fctx) {
-       isc_boolean_t rescan;
-       dns_section_t section = DNS_SECTION_ADDITIONAL;
-       isc_result_t result;
+        isc_boolean_t rescan;
+        dns_section_t section = DNS_SECTION_ADDITIONAL;
+        isc_result_t result;
 
  again:
-       rescan = ISC_FALSE;
-       
-       for (result = dns_message_firstname(fctx->rmessage, section);
-            result == ISC_R_SUCCESS;
-            result = dns_message_nextname(fctx->rmessage, section)) {
-               dns_name_t *name = NULL;
-               dns_rdataset_t *rdataset;
-               dns_message_currentname(fctx->rmessage, DNS_SECTION_ADDITIONAL,
-                                       &name);
-               if ((name->attributes & DNS_NAMEATTR_CHASE) == 0)
-                       continue;
-               name->attributes &= ~DNS_NAMEATTR_CHASE;
-               for (rdataset = ISC_LIST_HEAD(name->list);
-                    rdataset != NULL;
-                    rdataset = ISC_LIST_NEXT(rdataset, link)) {
-                       if (CHASE(rdataset)) {
-                               rdataset->attributes &= ~DNS_RDATASETATTR_CHASE;
-                               (void)dns_rdataset_additionaldata(rdataset,
-                                                                 check_related,
-                                                                 fctx);
-                               rescan = ISC_TRUE;
-                       }
-               }
-       }
-       if (rescan)
-               goto again;
+        rescan = ISC_FALSE;
+
+        for (result = dns_message_firstname(fctx->rmessage, section);
+             result == ISC_R_SUCCESS;
+             result = dns_message_nextname(fctx->rmessage, section)) {
+                dns_name_t *name = NULL;
+                dns_rdataset_t *rdataset;
+                dns_message_currentname(fctx->rmessage, DNS_SECTION_ADDITIONAL,
+                                        &name);
+                if ((name->attributes & DNS_NAMEATTR_CHASE) == 0)
+                        continue;
+                name->attributes &= ~DNS_NAMEATTR_CHASE;
+                for (rdataset = ISC_LIST_HEAD(name->list);
+                     rdataset != NULL;
+                     rdataset = ISC_LIST_NEXT(rdataset, link)) {
+                        if (CHASE(rdataset)) {
+                                rdataset->attributes &= ~DNS_RDATASETATTR_CHASE;
+                                (void)dns_rdataset_additionaldata(rdataset,
+                                                                  check_related,
+                                                                  fctx);
+                                rescan = ISC_TRUE;
+                        }
+                }
+        }
+        if (rescan)
+                goto again;
 }
 
 static inline isc_result_t
 cname_target(dns_rdataset_t *rdataset, dns_name_t *tname) {
-       isc_result_t result;
-       dns_rdata_t rdata = DNS_RDATA_INIT;
-       dns_rdata_cname_t cname;
-
-       result = dns_rdataset_first(rdataset);
-       if (result != ISC_R_SUCCESS)
-               return (result);
-       dns_rdataset_current(rdataset, &rdata);
-       result = dns_rdata_tostruct(&rdata, &cname, NULL);
-       if (result != ISC_R_SUCCESS)
-               return (result);
-       dns_name_init(tname, NULL);
-       dns_name_clone(&cname.cname, tname);
-       dns_rdata_freestruct(&cname);
-
-       return (ISC_R_SUCCESS);
+        isc_result_t result;
+        dns_rdata_t rdata = DNS_RDATA_INIT;
+        dns_rdata_cname_t cname;
+
+        result = dns_rdataset_first(rdataset);
+        if (result != ISC_R_SUCCESS)
+                return (result);
+        dns_rdataset_current(rdataset, &rdata);
+        result = dns_rdata_tostruct(&rdata, &cname, NULL);
+        if (result != ISC_R_SUCCESS)
+                return (result);
+        dns_name_init(tname, NULL);
+        dns_name_clone(&cname.cname, tname);
+        dns_rdata_freestruct(&cname);
+
+        return (ISC_R_SUCCESS);
 }
 
 static inline isc_result_t
 dname_target(dns_rdataset_t *rdataset, dns_name_t *qname, dns_name_t *oname,
-            dns_fixedname_t *fixeddname)
+             dns_fixedname_t *fixeddname)
 {
-       isc_result_t result;
-       dns_rdata_t rdata = DNS_RDATA_INIT;
-       unsigned int nlabels;
-       int order;
-       dns_namereln_t namereln;
-       dns_rdata_dname_t dname;
-       dns_fixedname_t prefix;
-
-       /*
-        * Get the target name of the DNAME.
-        */
-
-       result = dns_rdataset_first(rdataset);
-       if (result != ISC_R_SUCCESS)
-               return (result);
-       dns_rdataset_current(rdataset, &rdata);
-       result = dns_rdata_tostruct(&rdata, &dname, NULL);
-       if (result != ISC_R_SUCCESS)
-               return (result);
-
-       /*
-        * Get the prefix of qname.
-        */
-       namereln = dns_name_fullcompare(qname, oname, &order, &nlabels);
-       if (namereln != dns_namereln_subdomain) {
-               dns_rdata_freestruct(&dname);
-               return (DNS_R_FORMERR);
-       }
-       dns_fixedname_init(&prefix);
-       dns_name_split(qname, nlabels, dns_fixedname_name(&prefix), NULL); 
-       dns_fixedname_init(fixeddname);
-       result = dns_name_concatenate(dns_fixedname_name(&prefix),
-                                     &dname.dname,
-                                     dns_fixedname_name(fixeddname), NULL);
-       dns_rdata_freestruct(&dname);
-       return (result);
+        isc_result_t result;
+        dns_rdata_t rdata = DNS_RDATA_INIT;
+        unsigned int nlabels;
+        int order;
+        dns_namereln_t namereln;
+        dns_rdata_dname_t dname;
+        dns_fixedname_t prefix;
+
+        /*
+         * Get the target name of the DNAME.
+         */
+
+        result = dns_rdataset_first(rdataset);
+        if (result != ISC_R_SUCCESS)
+                return (result);
+        dns_rdataset_current(rdataset, &rdata);
+        result = dns_rdata_tostruct(&rdata, &dname, NULL);
+        if (result != ISC_R_SUCCESS)
+                return (result);
+
+        /*
+         * Get the prefix of qname.
+         */
+        namereln = dns_name_fullcompare(qname, oname, &order, &nlabels);
+        if (namereln != dns_namereln_subdomain) {
+                dns_rdata_freestruct(&dname);
+                return (DNS_R_FORMERR);
+        }
+        dns_fixedname_init(&prefix);
+        dns_name_split(qname, nlabels, dns_fixedname_name(&prefix), NULL);
+        dns_fixedname_init(fixeddname);
+        result = dns_name_concatenate(dns_fixedname_name(&prefix),
+                                      &dname.dname,
+                                      dns_fixedname_name(fixeddname), NULL);
+        dns_rdata_freestruct(&dname);
+        return (result);
 }
 
 /*
@@ -4529,1552 +4566,1552 @@ dname_target(dns_rdataset_t *rdataset, dns_name_t *qname, dns_name_t *oname,
  */
 static isc_result_t
 noanswer_response(fetchctx_t *fctx, dns_name_t *oqname,
-                 isc_boolean_t bind8_ns_resp)
+                  isc_boolean_t bind8_ns_resp)
 {
-       isc_result_t result;
-       dns_message_t *message;
-       dns_name_t *name, *qname, *ns_name, *soa_name, *ds_name;
-       dns_rdataset_t *rdataset, *ns_rdataset;
-       isc_boolean_t aa, negative_response;
-       dns_rdatatype_t type;
-       dns_section_t section =
-               bind8_ns_resp ? DNS_SECTION_ANSWER : DNS_SECTION_AUTHORITY;
-
-       FCTXTRACE("noanswer_response");
-
-       message = fctx->rmessage;
-
-       /*
-        * Setup qname.
-        */
-       if (oqname == NULL) {
-               /*
-                * We have a normal, non-chained negative response or
-                * referral.
-                */
-               if ((message->flags & DNS_MESSAGEFLAG_AA) != 0)
-                       aa = ISC_TRUE;
-               else
-                       aa = ISC_FALSE;
-               qname = &fctx->name;
-       } else {
-               /*
-                * We're being invoked by answer_response() after it has
-                * followed a CNAME/DNAME chain.
-                */
-               qname = oqname;
-               aa = ISC_FALSE;
-               /*
-                * If the current qname is not a subdomain of the query
-                * domain, there's no point in looking at the authority
-                * section without doing DNSSEC validation.
-                *
-                * Until we do that validation, we'll just return success
-                * in this case.
-                */
-               if (!dns_name_issubdomain(qname, &fctx->domain))
-                       return (ISC_R_SUCCESS);
-       }
-
-       /*
-        * We have to figure out if this is a negative response, or a
-        * referral.
-        */
-
-       /*
-        * Sometimes we can tell if its a negative response by looking at
-        * the message header.
-        */
-       negative_response = ISC_FALSE;
-       if (message->rcode == dns_rcode_nxdomain ||
-           (message->counts[DNS_SECTION_ANSWER] == 0 &&
-            message->counts[DNS_SECTION_AUTHORITY] == 0))
-               negative_response = ISC_TRUE;
-
-       /*
-        * Process the authority section.
-        */
-       ns_name = NULL;
-       ns_rdataset = NULL;
-       soa_name = NULL;
-       ds_name = NULL;
-       result = dns_message_firstname(message, section);
-       while (result == ISC_R_SUCCESS) {
-               name = NULL;
-               dns_message_currentname(message, section, &name);
-               if (dns_name_issubdomain(name, &fctx->domain)) {
-                       /*
-                        * Look for NS/SOA RRsets first.
-                        */
-                       for (rdataset = ISC_LIST_HEAD(name->list);
-                            rdataset != NULL;
-                            rdataset = ISC_LIST_NEXT(rdataset, link)) {
-                               type = rdataset->type;
-                               if (type == dns_rdatatype_rrsig)
-                                       type = rdataset->covers;
-                               if (((type == dns_rdatatype_ns ||
-                                     type == dns_rdatatype_soa) &&
-                                    !dns_name_issubdomain(qname, name)))
-                                       return (DNS_R_FORMERR);
-                               if (type == dns_rdatatype_ns) {
-                                       /*
-                                        * NS or RRSIG NS.
-                                        *
-                                        * Only one set of NS RRs is allowed.
-                                        */
-                                       if (rdataset->type ==
-                                           dns_rdatatype_ns) {
-                                               if (ns_name != NULL &&
-                                                   name != ns_name)
-                                                       return (DNS_R_FORMERR);
-                                               ns_name = name;
-                                               ns_rdataset = rdataset;
-                                       }
-                                       name->attributes |=
-                                               DNS_NAMEATTR_CACHE;
-                                       rdataset->attributes |=
-                                               DNS_RDATASETATTR_CACHE;
-                                       rdataset->trust = dns_trust_glue;
-                               }
-                               if (type == dns_rdatatype_soa) {
-                                       /*
-                                        * SOA, or RRSIG SOA.
-                                        *
-                                        * Only one SOA is allowed.
-                                        */
-                                       if (rdataset->type ==
-                                           dns_rdatatype_soa) {
-                                               if (soa_name != NULL &&
-                                                   name != soa_name)
-                                                       return (DNS_R_FORMERR);
-                                               soa_name = name;
-                                       }
-                                       name->attributes |=
-                                               DNS_NAMEATTR_NCACHE;
-                                       rdataset->attributes |=
-                                               DNS_RDATASETATTR_NCACHE;
-                                       if (aa)
-                                               rdataset->trust =
-                                                   dns_trust_authauthority;
-                                       else
-                                               rdataset->trust =
-                                                       dns_trust_additional;
-                               }
-                       }
-               }
-               result = dns_message_nextname(message, section);
-               if (result == ISC_R_NOMORE)
-                       break;
-               else if (result != ISC_R_SUCCESS)
-                       return (result);
-       }
-
-       /*
-        * A negative response has a SOA record (Type 2) 
-        * and a optional NS RRset (Type 1) or it has neither
-        * a SOA or a NS RRset (Type 3, handled above) or
-        * rcode is NXDOMAIN (handled above) in which case
-        * the NS RRset is allowed (Type 4).
-        */
-       if (soa_name != NULL)
-               negative_response = ISC_TRUE;
-
-       result = dns_message_firstname(message, section);
-       while (result == ISC_R_SUCCESS) {
-               name = NULL;
-               dns_message_currentname(message, section, &name);
-               if (dns_name_issubdomain(name, &fctx->domain)) {
-                       for (rdataset = ISC_LIST_HEAD(name->list);
-                            rdataset != NULL;
-                            rdataset = ISC_LIST_NEXT(rdataset, link)) {
-                               type = rdataset->type;
-                               if (type == dns_rdatatype_rrsig)
-                                       type = rdataset->covers;
-                               if (type == dns_rdatatype_nsec) {
-                                       /*
-                                        * NSEC or RRSIG NSEC.
-                                        */
-                                       if (negative_response) {
-                                               name->attributes |=
-                                                       DNS_NAMEATTR_NCACHE;
-                                               rdataset->attributes |=
-                                                       DNS_RDATASETATTR_NCACHE;
-                                       } else {
-                                               name->attributes |=
-                                                       DNS_NAMEATTR_CACHE;
-                                               rdataset->attributes |=
-                                                       DNS_RDATASETATTR_CACHE;
-                                       }
-                                       if (aa)
-                                               rdataset->trust =
-                                                   dns_trust_authauthority;
-                                       else
-                                               rdataset->trust =
-                                                       dns_trust_additional;
-                                       /*
-                                        * No additional data needs to be
-                                        * marked.
-                                        */
-                               } else if (type == dns_rdatatype_ds) {
-                                       /*
-                                        * DS or SIG DS.
-                                        *
-                                        * These should only be here if
-                                        * this is a referral, and there
-                                        * should only be one DS.
-                                        */
-                                       if (ns_name == NULL)
-                                               return (DNS_R_FORMERR);
-                                       if (rdataset->type ==
-                                           dns_rdatatype_ds) {
-                                               if (ds_name != NULL &&
-                                                   name != ds_name)
-                                                       return (DNS_R_FORMERR);
-                                               ds_name = name;
-                                       }
-                                       name->attributes |=
-                                               DNS_NAMEATTR_CACHE;
-                                       rdataset->attributes |=
-                                               DNS_RDATASETATTR_CACHE;
-                                       if (aa)
-                                               rdataset->trust =
-                                                   dns_trust_authauthority;
-                                       else
-                                               rdataset->trust =
-                                                       dns_trust_additional;
-                               }
-                       }
-               }
-               result = dns_message_nextname(message, section);
-               if (result == ISC_R_NOMORE)
-                       break;
-               else if (result != ISC_R_SUCCESS)
-                       return (result);
-       }
-
-       /*
-        * Trigger lookups for DNS nameservers.
-        */
-       if (negative_response && message->rcode == dns_rcode_noerror &&
-           fctx->type == dns_rdatatype_ds && soa_name != NULL &&
-           dns_name_equal(soa_name, qname) &&
-           !dns_name_equal(qname, dns_rootname))
-               return (DNS_R_CHASEDSSERVERS);
-
-       /*
-        * Did we find anything?
-        */
-       if (!negative_response && ns_name == NULL) {
-               /*
-                * Nope.
-                */
-               if (oqname != NULL) {
-                       /*
-                        * We've already got a partial CNAME/DNAME chain,
-                        * and haven't found else anything useful here, but
-                        * no error has occurred since we have an answer.
-                        */
-                       return (ISC_R_SUCCESS);
-               } else {
-                       /*
-                        * The responder is insane.
-                        */
-                       return (DNS_R_FORMERR);
-               }
-       }
-
-       /*
-        * If we found both NS and SOA, they should be the same name.
-        */
-       if (ns_name != NULL && soa_name != NULL && ns_name != soa_name)
-               return (DNS_R_FORMERR);
-
-       /*
-        * Do we have a referral?  (We only want to follow a referral if
-        * we're not following a chain.)
-        */
-       if (!negative_response && ns_name != NULL && oqname == NULL) {
-               /*
-                * We already know ns_name is a subdomain of fctx->domain.
-                * If ns_name is equal to fctx->domain, we're not making
-                * progress.  We return DNS_R_FORMERR so that we'll keep
-                * trying other servers.
-                */
-               if (dns_name_equal(ns_name, &fctx->domain))
-                       return (DNS_R_FORMERR);
-
-               /*
-                * If the referral name is not a parent of the query
-                * name, consider the responder insane.
-                */
-               if (! dns_name_issubdomain(&fctx->name, ns_name)) {
-                       FCTXTRACE("referral to non-parent");
-                       return (DNS_R_FORMERR);
-               }
-
-               /*
-                * Mark any additional data related to this rdataset.
-                * It's important that we do this before we change the
-                * query domain.
-                */
-               INSIST(ns_rdataset != NULL);
-               fctx->attributes |= FCTX_ATTR_GLUING;
-               (void)dns_rdataset_additionaldata(ns_rdataset, check_related,
-                                                 fctx);
-               fctx->attributes &= ~FCTX_ATTR_GLUING;
-               /*
-                * NS rdatasets with 0 TTL cause problems.
-                * dns_view_findzonecut() will not find them when we
-                * try to follow the referral, and we'll SERVFAIL
-                * because the best nameservers are now above QDOMAIN.
-                * We force the TTL to 1 second to prevent this.
-                */
-               if (ns_rdataset->ttl == 0)
-                       ns_rdataset->ttl = 1;
-               /*
-                * Set the current query domain to the referral name.
-                *
-                * XXXRTH  We should check if we're in forward-only mode, and
-                *         if so we should bail out.
-                */
-               INSIST(dns_name_countlabels(&fctx->domain) > 0);
-               dns_name_free(&fctx->domain,
-                             fctx->res->buckets[fctx->bucketnum].mctx);
-               if (dns_rdataset_isassociated(&fctx->nameservers))
-                       dns_rdataset_disassociate(&fctx->nameservers);
-               dns_name_init(&fctx->domain, NULL);
-               result = dns_name_dup(ns_name,
-                                     fctx->res->buckets[fctx->bucketnum].mctx,
-                                     &fctx->domain);
-               if (result != ISC_R_SUCCESS)
-                       return (result);
-               fctx->attributes |= FCTX_ATTR_WANTCACHE;
-               return (DNS_R_DELEGATION);
-       }
-
-       /*
-        * Since we're not doing a referral, we don't want to cache any
-        * NS RRs we may have found.
-        */
-       if (ns_name != NULL)
-               ns_name->attributes &= ~DNS_NAMEATTR_CACHE;
-
-       if (negative_response && oqname == NULL)
-               fctx->attributes |= FCTX_ATTR_WANTNCACHE;
-
-       return (ISC_R_SUCCESS);
+        isc_result_t result;
+        dns_message_t *message;
+        dns_name_t *name, *qname, *ns_name, *soa_name, *ds_name;
+        dns_rdataset_t *rdataset, *ns_rdataset;
+        isc_boolean_t aa, negative_response;
+        dns_rdatatype_t type;
+        dns_section_t section =
+                bind8_ns_resp ? DNS_SECTION_ANSWER : DNS_SECTION_AUTHORITY;
+
+        FCTXTRACE("noanswer_response");
+
+        message = fctx->rmessage;
+
+        /*
+         * Setup qname.
+         */
+        if (oqname == NULL) {
+                /*
+                 * We have a normal, non-chained negative response or
+                 * referral.
+                 */
+                if ((message->flags & DNS_MESSAGEFLAG_AA) != 0)
+                        aa = ISC_TRUE;
+                else
+                        aa = ISC_FALSE;
+                qname = &fctx->name;
+        } else {
+                /*
+                 * We're being invoked by answer_response() after it has
+                 * followed a CNAME/DNAME chain.
+                 */
+                qname = oqname;
+                aa = ISC_FALSE;
+                /*
+                 * If the current qname is not a subdomain of the query
+                 * domain, there's no point in looking at the authority
+                 * section without doing DNSSEC validation.
+                 *
+                 * Until we do that validation, we'll just return success
+                 * in this case.
+                 */
+                if (!dns_name_issubdomain(qname, &fctx->domain))
+                        return (ISC_R_SUCCESS);
+        }
+
+        /*
+         * We have to figure out if this is a negative response, or a
+         * referral.
+         */
+
+        /*
+         * Sometimes we can tell if its a negative response by looking at
+         * the message header.
+         */
+        negative_response = ISC_FALSE;
+        if (message->rcode == dns_rcode_nxdomain ||
+            (message->counts[DNS_SECTION_ANSWER] == 0 &&
+             message->counts[DNS_SECTION_AUTHORITY] == 0))
+                negative_response = ISC_TRUE;
+
+        /*
+         * Process the authority section.
+         */
+        ns_name = NULL;
+        ns_rdataset = NULL;
+        soa_name = NULL;
+        ds_name = NULL;
+        result = dns_message_firstname(message, section);
+        while (result == ISC_R_SUCCESS) {
+                name = NULL;
+                dns_message_currentname(message, section, &name);
+                if (dns_name_issubdomain(name, &fctx->domain)) {
+                        /*
+                         * Look for NS/SOA RRsets first.
+                         */
+                        for (rdataset = ISC_LIST_HEAD(name->list);
+                             rdataset != NULL;
+                             rdataset = ISC_LIST_NEXT(rdataset, link)) {
+                                type = rdataset->type;
+                                if (type == dns_rdatatype_rrsig)
+                                        type = rdataset->covers;
+                                if (((type == dns_rdatatype_ns ||
+                                      type == dns_rdatatype_soa) &&
+                                     !dns_name_issubdomain(qname, name)))
+                                        return (DNS_R_FORMERR);
+                                if (type == dns_rdatatype_ns) {
+                                        /*
+                                         * NS or RRSIG NS.
+                                         *
+                                         * Only one set of NS RRs is allowed.
+                                         */
+                                        if (rdataset->type ==
+                                            dns_rdatatype_ns) {
+                                                if (ns_name != NULL &&
+                                                    name != ns_name)
+                                                        return (DNS_R_FORMERR);
+                                                ns_name = name;
+                                                ns_rdataset = rdataset;
+                                        }
+                                        name->attributes |=
+                                                DNS_NAMEATTR_CACHE;
+                                        rdataset->attributes |=
+                                                DNS_RDATASETATTR_CACHE;
+                                        rdataset->trust = dns_trust_glue;
+                                }
+                                if (type == dns_rdatatype_soa) {
+                                        /*
+                                         * SOA, or RRSIG SOA.
+                                         *
+                                         * Only one SOA is allowed.
+                                         */
+                                        if (rdataset->type ==
+                                            dns_rdatatype_soa) {
+                                                if (soa_name != NULL &&
+                                                    name != soa_name)
+                                                        return (DNS_R_FORMERR);
+                                                soa_name = name;
+                                        }
+                                        name->attributes |=
+                                                DNS_NAMEATTR_NCACHE;
+                                        rdataset->attributes |=
+                                                DNS_RDATASETATTR_NCACHE;
+                                        if (aa)
+                                                rdataset->trust =
+                                                    dns_trust_authauthority;
+                                        else
+                                                rdataset->trust =
+                                                        dns_trust_additional;
+                                }
+                        }
+                }
+                result = dns_message_nextname(message, section);
+                if (result == ISC_R_NOMORE)
+                        break;
+                else if (result != ISC_R_SUCCESS)
+                        return (result);
+        }
+
+        /*
+         * A negative response has a SOA record (Type 2)
+         * and a optional NS RRset (Type 1) or it has neither
+         * a SOA or a NS RRset (Type 3, handled above) or
+         * rcode is NXDOMAIN (handled above) in which case
+         * the NS RRset is allowed (Type 4).
+         */
+        if (soa_name != NULL)
+                negative_response = ISC_TRUE;
+
+        result = dns_message_firstname(message, section);
+        while (result == ISC_R_SUCCESS) {
+                name = NULL;
+                dns_message_currentname(message, section, &name);
+                if (dns_name_issubdomain(name, &fctx->domain)) {
+                        for (rdataset = ISC_LIST_HEAD(name->list);
+                             rdataset != NULL;
+                             rdataset = ISC_LIST_NEXT(rdataset, link)) {
+                                type = rdataset->type;
+                                if (type == dns_rdatatype_rrsig)
+                                        type = rdataset->covers;
+                                if (type == dns_rdatatype_nsec) {
+                                        /*
+                                         * NSEC or RRSIG NSEC.
+                                         */
+                                        if (negative_response) {
+                                                name->attributes |=
+                                                        DNS_NAMEATTR_NCACHE;
+                                                rdataset->attributes |=
+                                                        DNS_RDATASETATTR_NCACHE;
+                                        } else {
+                                                name->attributes |=
+                                                        DNS_NAMEATTR_CACHE;
+                                                rdataset->attributes |=
+                                                        DNS_RDATASETATTR_CACHE;
+                                        }
+                                        if (aa)
+                                                rdataset->trust =
+                                                    dns_trust_authauthority;
+                                        else
+                                                rdataset->trust =
+                                                        dns_trust_additional;
+                                        /*
+                                         * No additional data needs to be
+                                         * marked.
+                                         */
+                                } else if (type == dns_rdatatype_ds) {
+                                        /*
+                                         * DS or SIG DS.
+                                         *
+                                         * These should only be here if
+                                         * this is a referral, and there
+                                         * should only be one DS.
+                                         */
+                                        if (ns_name == NULL)
+                                                return (DNS_R_FORMERR);
+                                        if (rdataset->type ==
+                                            dns_rdatatype_ds) {
+                                                if (ds_name != NULL &&
+                                                    name != ds_name)
+                                                        return (DNS_R_FORMERR);
+                                                ds_name = name;
+                                        }
+                                        name->attributes |=
+                                                DNS_NAMEATTR_CACHE;
+                                        rdataset->attributes |=
+                                                DNS_RDATASETATTR_CACHE;
+                                        if (aa)
+                                                rdataset->trust =
+                                                    dns_trust_authauthority;
+                                        else
+                                                rdataset->trust =
+                                                        dns_trust_additional;
+                                }
+                        }
+                }
+                result = dns_message_nextname(message, section);
+                if (result == ISC_R_NOMORE)
+                        break;
+                else if (result != ISC_R_SUCCESS)
+                        return (result);
+        }
+
+        /*
+         * Trigger lookups for DNS nameservers.
+         */
+        if (negative_response && message->rcode == dns_rcode_noerror &&
+            fctx->type == dns_rdatatype_ds && soa_name != NULL &&
+            dns_name_equal(soa_name, qname) &&
+            !dns_name_equal(qname, dns_rootname))
+                return (DNS_R_CHASEDSSERVERS);
+
+        /*
+         * Did we find anything?
+         */
+        if (!negative_response && ns_name == NULL) {
+                /*
+                 * Nope.
+                 */
+                if (oqname != NULL) {
+                        /*
+                         * We've already got a partial CNAME/DNAME chain,
+                         * and haven't found else anything useful here, but
+                         * no error has occurred since we have an answer.
+                         */
+                        return (ISC_R_SUCCESS);
+                } else {
+                        /*
+                         * The responder is insane.
+                         */
+                        return (DNS_R_FORMERR);
+                }
+        }
+
+        /*
+         * If we found both NS and SOA, they should be the same name.
+         */
+        if (ns_name != NULL && soa_name != NULL && ns_name != soa_name)
+                return (DNS_R_FORMERR);
+
+        /*
+         * Do we have a referral?  (We only want to follow a referral if
+         * we're not following a chain.)
+         */
+        if (!negative_response && ns_name != NULL && oqname == NULL) {
+                /*
+                 * We already know ns_name is a subdomain of fctx->domain.
+                 * If ns_name is equal to fctx->domain, we're not making
+                 * progress.  We return DNS_R_FORMERR so that we'll keep
+                 * trying other servers.
+                 */
+                if (dns_name_equal(ns_name, &fctx->domain))
+                        return (DNS_R_FORMERR);
+
+                /*
+                 * If the referral name is not a parent of the query
+                 * name, consider the responder insane.
+                 */
+                if (! dns_name_issubdomain(&fctx->name, ns_name)) {
+                        FCTXTRACE("referral to non-parent");
+                        return (DNS_R_FORMERR);
+                }
+
+                /*
+                 * Mark any additional data related to this rdataset.
+                 * It's important that we do this before we change the
+                 * query domain.
+                 */
+                INSIST(ns_rdataset != NULL);
+                fctx->attributes |= FCTX_ATTR_GLUING;
+                (void)dns_rdataset_additionaldata(ns_rdataset, check_related,
+                                                  fctx);
+                fctx->attributes &= ~FCTX_ATTR_GLUING;
+                /*
+                 * NS rdatasets with 0 TTL cause problems.
+                 * dns_view_findzonecut() will not find them when we
+                 * try to follow the referral, and we'll SERVFAIL
+                 * because the best nameservers are now above QDOMAIN.
+                 * We force the TTL to 1 second to prevent this.
+                 */
+                if (ns_rdataset->ttl == 0)
+                        ns_rdataset->ttl = 1;
+                /*
+                 * Set the current query domain to the referral name.
+                 *
+                 * XXXRTH  We should check if we're in forward-only mode, and
+                 *         if so we should bail out.
+                 */
+                INSIST(dns_name_countlabels(&fctx->domain) > 0);
+                dns_name_free(&fctx->domain,
+                              fctx->res->buckets[fctx->bucketnum].mctx);
+                if (dns_rdataset_isassociated(&fctx->nameservers))
+                        dns_rdataset_disassociate(&fctx->nameservers);
+                dns_name_init(&fctx->domain, NULL);
+                result = dns_name_dup(ns_name,
+                                      fctx->res->buckets[fctx->bucketnum].mctx,
+                                      &fctx->domain);
+                if (result != ISC_R_SUCCESS)
+                        return (result);
+                fctx->attributes |= FCTX_ATTR_WANTCACHE;
+                return (DNS_R_DELEGATION);
+        }
+
+        /*
+         * Since we're not doing a referral, we don't want to cache any
+         * NS RRs we may have found.
+         */
+        if (ns_name != NULL)
+                ns_name->attributes &= ~DNS_NAMEATTR_CACHE;
+
+        if (negative_response && oqname == NULL)
+                fctx->attributes |= FCTX_ATTR_WANTNCACHE;
+
+        return (ISC_R_SUCCESS);
 }
 
 static isc_result_t
 answer_response(fetchctx_t *fctx) {
-       isc_result_t result;
-       dns_message_t *message;
-       dns_name_t *name, *qname, tname;
-       dns_rdataset_t *rdataset;
-       isc_boolean_t done, external, chaining, aa, found, want_chaining;
-       isc_boolean_t have_answer, found_cname, found_type, wanted_chaining;
-       unsigned int aflag;
-       dns_rdatatype_t type;
-       dns_fixedname_t dname, fqname;
-
-       FCTXTRACE("answer_response");
-
-       message = fctx->rmessage;
-
-       /*
-        * Examine the answer section, marking those rdatasets which are
-        * part of the answer and should be cached.
-        */
-
-       done = ISC_FALSE;
-       found_cname = ISC_FALSE;
-       found_type = ISC_FALSE;
-       chaining = ISC_FALSE;
-       have_answer = ISC_FALSE;
-       want_chaining = ISC_FALSE;
-       if ((message->flags & DNS_MESSAGEFLAG_AA) != 0)
-               aa = ISC_TRUE;
-       else
-               aa = ISC_FALSE;
-       qname = &fctx->name;
-       type = fctx->type;
-       result = dns_message_firstname(message, DNS_SECTION_ANSWER);
-       while (!done && result == ISC_R_SUCCESS) {
-               name = NULL;
-               dns_message_currentname(message, DNS_SECTION_ANSWER, &name);
-               external = ISC_TF(!dns_name_issubdomain(name, &fctx->domain));
-               if (dns_name_equal(name, qname)) {
-                       wanted_chaining = ISC_FALSE;
-                       for (rdataset = ISC_LIST_HEAD(name->list);
-                            rdataset != NULL;
-                            rdataset = ISC_LIST_NEXT(rdataset, link)) {
-                               found = ISC_FALSE;
-                               want_chaining = ISC_FALSE;
-                               aflag = 0;
-                               if (rdataset->type == type && !found_cname) {
-                                       /*
-                                        * We've found an ordinary answer.
-                                        */
-                                       found = ISC_TRUE;
-                                       found_type = ISC_TRUE;
-                                       done = ISC_TRUE;
-                                       aflag = DNS_RDATASETATTR_ANSWER;
-                               } else if (type == dns_rdatatype_any) {
-                                       /*
-                                        * We've found an answer matching
-                                        * an ANY query.  There may be
-                                        * more.
-                                        */
-                                       found = ISC_TRUE;
-                                       aflag = DNS_RDATASETATTR_ANSWER;
-                               } else if (rdataset->type == dns_rdatatype_rrsig
-                                          && rdataset->covers == type
-                                          && !found_cname) {
-                                       /*
-                                        * We've found a signature that
-                                        * covers the type we're looking for.
-                                        */
-                                       found = ISC_TRUE;
-                                       found_type = ISC_TRUE;
-                                       aflag = DNS_RDATASETATTR_ANSWERSIG;
-                               } else if (rdataset->type ==
-                                          dns_rdatatype_cname
-                                          && !found_type) {
-                                       /*
-                                        * We're looking for something else,
-                                        * but we found a CNAME.
-                                        *
-                                        * Getting a CNAME response for some
-                                        * query types is an error.
-                                        */
-                                       if (type == dns_rdatatype_rrsig ||
-                                           type == dns_rdatatype_dnskey ||
-                                           type == dns_rdatatype_nsec)
-                                               return (DNS_R_FORMERR);
-                                       found = ISC_TRUE;
-                                       found_cname = ISC_TRUE;
-                                       want_chaining = ISC_TRUE;
-                                       aflag = DNS_RDATASETATTR_ANSWER;
-                                       result = cname_target(rdataset,
-                                                             &tname);
-                                       if (result != ISC_R_SUCCESS)
-                                               return (result);
-                               } else if (rdataset->type == dns_rdatatype_rrsig
-                                          && rdataset->covers ==
-                                          dns_rdatatype_cname
-                                          && !found_type) {
-                                       /*
-                                        * We're looking for something else,
-                                        * but we found a SIG CNAME.
-                                        */
-                                       found = ISC_TRUE;
-                                       found_cname = ISC_TRUE;
-                                       aflag = DNS_RDATASETATTR_ANSWERSIG;
-                               }
-
-                               if (found) {
-                                       /*
-                                        * We've found an answer to our
-                                        * question.
-                                        */
-                                       name->attributes |=
-                                               DNS_NAMEATTR_CACHE;
-                                       rdataset->attributes |=
-                                               DNS_RDATASETATTR_CACHE;
-                                       rdataset->trust = dns_trust_answer;
-                                       if (!chaining) {
-                                               /*
-                                                * This data is "the" answer
-                                                * to our question only if
-                                                * we're not chaining (i.e.
-                                                * if we haven't followed
-                                                * a CNAME or DNAME).
-                                                */
-                                               INSIST(!external);
-                                               if (aflag ==
-                                                   DNS_RDATASETATTR_ANSWER)
-                                                       have_answer = ISC_TRUE;
-                                               name->attributes |=
-                                                       DNS_NAMEATTR_ANSWER;
-                                               rdataset->attributes |= aflag;
-                                               if (aa)
-                                                       rdataset->trust =
-                                                         dns_trust_authanswer;
-                                       } else if (external) {
-                                               /*
-                                                * This data is outside of
-                                                * our query domain, and
-                                                * may only be cached if it
-                                                * comes from a secure zone
-                                                * and validates.
-                                                */
-                                               rdataset->attributes |=
-                                                   DNS_RDATASETATTR_EXTERNAL;
-                                       }
-
-                                       /*
-                                        * Mark any additional data related
-                                        * to this rdataset.
-                                        */
-                                       (void)dns_rdataset_additionaldata(
-                                                       rdataset,
-                                                       check_related,
-                                                       fctx);
-
-                                       /*
-                                        * CNAME chaining.
-                                        */
-                                       if (want_chaining) {
-                                               wanted_chaining = ISC_TRUE;
-                                               name->attributes |=
-                                                       DNS_NAMEATTR_CHAINING;
-                                               rdataset->attributes |=
-                                                   DNS_RDATASETATTR_CHAINING;
-                                               qname = &tname;
-                                       }
-                               }
-                               /*
-                                * We could add an "else" clause here and
-                                * log that we're ignoring this rdataset.
-                                */
-                       }
-                       /*
-                        * If wanted_chaining is true, we've done
-                        * some chaining as the result of processing
-                        * this node, and thus we need to set
-                        * chaining to true.
-                        *
-                        * We don't set chaining inside of the
-                        * rdataset loop because doing that would
-                        * cause us to ignore the signatures of
-                        * CNAMEs.
-                        */
-                       if (wanted_chaining)
-                               chaining = ISC_TRUE;
-               } else {
-                       /*
-                        * Look for a DNAME (or its SIG).  Anything else is
-                        * ignored.
-                        */
-                       wanted_chaining = ISC_FALSE;
-                       for (rdataset = ISC_LIST_HEAD(name->list);
-                            rdataset != NULL;
-                            rdataset = ISC_LIST_NEXT(rdataset, link)) {
-                               isc_boolean_t found_dname = ISC_FALSE;
-                               found = ISC_FALSE;
-                               aflag = 0;
-                               if (rdataset->type == dns_rdatatype_dname) {
-                                       /*
-                                        * We're looking for something else,
-                                        * but we found a DNAME.
-                                        *
-                                        * If we're not chaining, then the
-                                        * DNAME should not be external.
-                                        */
-                                       if (!chaining && external)
-                                               return (DNS_R_FORMERR);
-                                       found = ISC_TRUE;
-                                       want_chaining = ISC_TRUE;
-                                       aflag = DNS_RDATASETATTR_ANSWER;
-                                       result = dname_target(rdataset,
-                                                             qname, name,
-                                                             &dname);
-                                       if (result == ISC_R_NOSPACE) {
-                                               /*
-                                                * We can't construct the
-                                                * DNAME target.  Do not
-                                                * try to continue.
-                                                */
-                                               want_chaining = ISC_FALSE;
-                                       } else if (result != ISC_R_SUCCESS)
-                                               return (result);
-                                       else
-                                               found_dname = ISC_TRUE;
-                               } else if (rdataset->type == dns_rdatatype_rrsig
-                                          && rdataset->covers ==
-                                          dns_rdatatype_dname) {
-                                       /*
-                                        * We've found a signature that
-                                        * covers the DNAME.
-                                        */
-                                       found = ISC_TRUE;
-                                       aflag = DNS_RDATASETATTR_ANSWERSIG;
-                               }
-
-                               if (found) {
-                                       /*
-                                        * We've found an answer to our
-                                        * question.
-                                        */
-                                       name->attributes |=
-                                               DNS_NAMEATTR_CACHE;
-                                       rdataset->attributes |=
-                                               DNS_RDATASETATTR_CACHE;
-                                       rdataset->trust = dns_trust_answer;
-                                       if (!chaining) {
-                                               /*
-                                                * This data is "the" answer
-                                                * to our question only if
-                                                * we're not chaining.
-                                                */
-                                               INSIST(!external);
-                                               if (aflag ==
-                                                   DNS_RDATASETATTR_ANSWER)
-                                                       have_answer = ISC_TRUE;
-                                               name->attributes |=
-                                                       DNS_NAMEATTR_ANSWER;
-                                               rdataset->attributes |= aflag;
-                                               if (aa)
-                                                       rdataset->trust =
-                                                         dns_trust_authanswer;
-                                       } else if (external) {
-                                               rdataset->attributes |=
-                                                   DNS_RDATASETATTR_EXTERNAL;
-                                       }
-
-                                       /*
-                                        * DNAME chaining.
-                                        */
-                                       if (found_dname) {
-                                               /*
-                                                * Copy the the dname into the
-                                                * qname fixed name.
-                                                *
-                                                * Although we check for
-                                                * failure of the copy
-                                                * operation, in practice it
-                                                * should never fail since
-                                                * we already know that the
-                                                * result fits in a fixedname.
-                                                */
-                                               dns_fixedname_init(&fqname);
-                                               result = dns_name_copy(
-                                                 dns_fixedname_name(&dname),
-                                                 dns_fixedname_name(&fqname),
-                                                 NULL);
-                                               if (result != ISC_R_SUCCESS)
-                                                       return (result);
-                                               wanted_chaining = ISC_TRUE;
-                                               name->attributes |=
-                                                       DNS_NAMEATTR_CHAINING;
-                                               rdataset->attributes |=
-                                                   DNS_RDATASETATTR_CHAINING;
-                                               qname = dns_fixedname_name(
-                                                                  &fqname);
-                                       }
-                               }
-                       }
-                       if (wanted_chaining)
-                               chaining = ISC_TRUE;
-               }
-               result = dns_message_nextname(message, DNS_SECTION_ANSWER);
-       }
-       if (result == ISC_R_NOMORE)
-               result = ISC_R_SUCCESS;
-       if (result != ISC_R_SUCCESS)
-               return (result);
-
-       /*
-        * We should have found an answer.
-        */
-       if (!have_answer)
-               return (DNS_R_FORMERR);
-
-       /*
-        * This response is now potentially cacheable.
-        */
-       fctx->attributes |= FCTX_ATTR_WANTCACHE;
-
-       /*
-        * Did chaining end before we got the final answer?
-        */
-       if (chaining) {
-               /*
-                * Yes.  This may be a negative reply, so hand off
-                * authority section processing to the noanswer code.
-                * If it isn't a noanswer response, no harm will be
-                * done.
-                */
-               return (noanswer_response(fctx, qname, ISC_FALSE));
-       }
-
-       /*
-        * We didn't end with an incomplete chain, so the rcode should be
-        * "no error".
-        */
-       if (message->rcode != dns_rcode_noerror)
-               return (DNS_R_FORMERR);
-
-       /*
-        * Examine the authority section (if there is one).
-        *
-        * We expect there to be only one owner name for all the rdatasets
-        * in this section, and we expect that it is not external.
-        */
-       done = ISC_FALSE;
-       result = dns_message_firstname(message, DNS_SECTION_AUTHORITY);
-       while (!done && result == ISC_R_SUCCESS) {
-               name = NULL;
-               dns_message_currentname(message, DNS_SECTION_AUTHORITY, &name);
-               external = ISC_TF(!dns_name_issubdomain(name, &fctx->domain));
-               if (!external) {
-                       /*
-                        * We expect to find NS or SIG NS rdatasets, and
-                        * nothing else.
-                        */
-                       for (rdataset = ISC_LIST_HEAD(name->list);
-                            rdataset != NULL;
-                            rdataset = ISC_LIST_NEXT(rdataset, link)) {
-                               if (rdataset->type == dns_rdatatype_ns ||
-                                   (rdataset->type == dns_rdatatype_rrsig &&
-                                    rdataset->covers == dns_rdatatype_ns)) {
-                                       name->attributes |=
-                                               DNS_NAMEATTR_CACHE;
-                                       rdataset->attributes |=
-                                               DNS_RDATASETATTR_CACHE;
-                                       if (aa && !chaining)
-                                               rdataset->trust =
-                                                   dns_trust_authauthority;
-                                       else
-                                               rdataset->trust =
-                                                   dns_trust_additional;
-
-                                       /*
-                                        * Mark any additional data related
-                                        * to this rdataset.
-                                        */
-                                       (void)dns_rdataset_additionaldata(
-                                                       rdataset,
-                                                       check_related,
-                                                       fctx);
-                                       done = ISC_TRUE;
-                               }
-                       }
-               }
-               result = dns_message_nextname(message, DNS_SECTION_AUTHORITY);
-       }
-       if (result == ISC_R_NOMORE)
-               result = ISC_R_SUCCESS;
-
-       return (result);
+        isc_result_t result;
+        dns_message_t *message;
+        dns_name_t *name, *qname, tname;
+        dns_rdataset_t *rdataset;
+        isc_boolean_t done, external, chaining, aa, found, want_chaining;
+        isc_boolean_t have_answer, found_cname, found_type, wanted_chaining;
+        unsigned int aflag;
+        dns_rdatatype_t type;
+        dns_fixedname_t dname, fqname;
+
+        FCTXTRACE("answer_response");
+
+        message = fctx->rmessage;
+
+        /*
+         * Examine the answer section, marking those rdatasets which are
+         * part of the answer and should be cached.
+         */
+
+        done = ISC_FALSE;
+        found_cname = ISC_FALSE;
+        found_type = ISC_FALSE;
+        chaining = ISC_FALSE;
+        have_answer = ISC_FALSE;
+        want_chaining = ISC_FALSE;
+        if ((message->flags & DNS_MESSAGEFLAG_AA) != 0)
+                aa = ISC_TRUE;
+        else
+                aa = ISC_FALSE;
+        qname = &fctx->name;
+        type = fctx->type;
+        result = dns_message_firstname(message, DNS_SECTION_ANSWER);
+        while (!done && result == ISC_R_SUCCESS) {
+                name = NULL;
+                dns_message_currentname(message, DNS_SECTION_ANSWER, &name);
+                external = ISC_TF(!dns_name_issubdomain(name, &fctx->domain));
+                if (dns_name_equal(name, qname)) {
+                        wanted_chaining = ISC_FALSE;
+                        for (rdataset = ISC_LIST_HEAD(name->list);
+                             rdataset != NULL;
+                             rdataset = ISC_LIST_NEXT(rdataset, link)) {
+                                found = ISC_FALSE;
+                                want_chaining = ISC_FALSE;
+                                aflag = 0;
+                                if (rdataset->type == type && !found_cname) {
+                                        /*
+                                         * We've found an ordinary answer.
+                                         */
+                                        found = ISC_TRUE;
+                                        found_type = ISC_TRUE;
+                                        done = ISC_TRUE;
+                                        aflag = DNS_RDATASETATTR_ANSWER;
+                                } else if (type == dns_rdatatype_any) {
+                                        /*
+                                         * We've found an answer matching
+                                         * an ANY query.  There may be
+                                         * more.
+                                         */
+                                        found = ISC_TRUE;
+                                        aflag = DNS_RDATASETATTR_ANSWER;
+                                } else if (rdataset->type == dns_rdatatype_rrsig
+                                           && rdataset->covers == type
+                                           && !found_cname) {
+                                        /*
+                                         * We've found a signature that
+                                         * covers the type we're looking for.
+                                         */
+                                        found = ISC_TRUE;
+                                        found_type = ISC_TRUE;
+                                        aflag = DNS_RDATASETATTR_ANSWERSIG;
+                                } else if (rdataset->type ==
+                                           dns_rdatatype_cname
+                                           && !found_type) {
+                                        /*
+                                         * We're looking for something else,
+                                         * but we found a CNAME.
+                                         *
+                                         * Getting a CNAME response for some
+                                         * query types is an error.
+                                         */
+                                        if (type == dns_rdatatype_rrsig ||
+                                            type == dns_rdatatype_dnskey ||
+                                            type == dns_rdatatype_nsec)
+                                                return (DNS_R_FORMERR);
+                                        found = ISC_TRUE;
+                                        found_cname = ISC_TRUE;
+                                        want_chaining = ISC_TRUE;
+                                        aflag = DNS_RDATASETATTR_ANSWER;
+                                        result = cname_target(rdataset,
+                                                              &tname);
+                                        if (result != ISC_R_SUCCESS)
+                                                return (result);
+                                } else if (rdataset->type == dns_rdatatype_rrsig
+                                           && rdataset->covers ==
+                                           dns_rdatatype_cname
+                                           && !found_type) {
+                                        /*
+                                         * We're looking for something else,
+                                         * but we found a SIG CNAME.
+                                         */
+                                        found = ISC_TRUE;
+                                        found_cname = ISC_TRUE;
+                                        aflag = DNS_RDATASETATTR_ANSWERSIG;
+                                }
+
+                                if (found) {
+                                        /*
+                                         * We've found an answer to our
+                                         * question.
+                                         */
+                                        name->attributes |=
+                                                DNS_NAMEATTR_CACHE;
+                                        rdataset->attributes |=
+                                                DNS_RDATASETATTR_CACHE;
+                                        rdataset->trust = dns_trust_answer;
+                                        if (!chaining) {
+                                                /*
+                                                 * This data is "the" answer
+                                                 * to our question only if
+                                                 * we're not chaining (i.e.
+                                                 * if we haven't followed
+                                                 * a CNAME or DNAME).
+                                                 */
+                                                INSIST(!external);
+                                                if (aflag ==
+                                                    DNS_RDATASETATTR_ANSWER)
+                                                        have_answer = ISC_TRUE;
+                                                name->attributes |=
+                                                        DNS_NAMEATTR_ANSWER;
+                                                rdataset->attributes |= aflag;
+                                                if (aa)
+                                                        rdataset->trust =
+                                                          dns_trust_authanswer;
+                                        } else if (external) {
+                                                /*
+                                                 * This data is outside of
+                                                 * our query domain, and
+                                                 * may only be cached if it
+                                                 * comes from a secure zone
+                                                 * and validates.
+                                                 */
+                                                rdataset->attributes |=
+                                                    DNS_RDATASETATTR_EXTERNAL;
+                                        }
+
+                                        /*
+                                         * Mark any additional data related
+                                         * to this rdataset.
+                                         */
+                                        (void)dns_rdataset_additionaldata(
+                                                        rdataset,
+                                                        check_related,
+                                                        fctx);
+
+                                        /*
+                                         * CNAME chaining.
+                                         */
+                                        if (want_chaining) {
+                                                wanted_chaining = ISC_TRUE;
+                                                name->attributes |=
+                                                        DNS_NAMEATTR_CHAINING;
+                                                rdataset->attributes |=
+                                                    DNS_RDATASETATTR_CHAINING;
+                                                qname = &tname;
+                                        }
+                                }
+                                /*
+                                 * We could add an "else" clause here and
+                                 * log that we're ignoring this rdataset.
+                                 */
+                        }
+                        /*
+                         * If wanted_chaining is true, we've done
+                         * some chaining as the result of processing
+                         * this node, and thus we need to set
+                         * chaining to true.
+                         *
+                         * We don't set chaining inside of the
+                         * rdataset loop because doing that would
+                         * cause us to ignore the signatures of
+                         * CNAMEs.
+                         */
+                        if (wanted_chaining)
+                                chaining = ISC_TRUE;
+                } else {
+                        /*
+                         * Look for a DNAME (or its SIG).  Anything else is
+                         * ignored.
+                         */
+                        wanted_chaining = ISC_FALSE;
+                        for (rdataset = ISC_LIST_HEAD(name->list);
+                             rdataset != NULL;
+                             rdataset = ISC_LIST_NEXT(rdataset, link)) {
+                                isc_boolean_t found_dname = ISC_FALSE;
+                                found = ISC_FALSE;
+                                aflag = 0;
+                                if (rdataset->type == dns_rdatatype_dname) {
+                                        /*
+                                         * We're looking for something else,
+                                         * but we found a DNAME.
+                                         *
+                                         * If we're not chaining, then the
+                                         * DNAME should not be external.
+                                         */
+                                        if (!chaining && external)
+                                                return (DNS_R_FORMERR);
+                                        found = ISC_TRUE;
+                                        want_chaining = ISC_TRUE;
+                                        aflag = DNS_RDATASETATTR_ANSWER;
+                                        result = dname_target(rdataset,
+                                                              qname, name,
+                                                              &dname);
+                                        if (result == ISC_R_NOSPACE) {
+                                                /*
+                                                 * We can't construct the
+                                                 * DNAME target.  Do not
+                                                 * try to continue.
+                                                 */
+                                                want_chaining = ISC_FALSE;
+                                        } else if (result != ISC_R_SUCCESS)
+                                                return (result);
+                                        else
+                                                found_dname = ISC_TRUE;
+                                } else if (rdataset->type == dns_rdatatype_rrsig
+                                           && rdataset->covers ==
+                                           dns_rdatatype_dname) {
+                                        /*
+                                         * We've found a signature that
+                                         * covers the DNAME.
+                                         */
+                                        found = ISC_TRUE;
+                                        aflag = DNS_RDATASETATTR_ANSWERSIG;
+                                }
+
+                                if (found) {
+                                        /*
+                                         * We've found an answer to our
+                                         * question.
+                                         */
+                                        name->attributes |=
+                                                DNS_NAMEATTR_CACHE;
+                                        rdataset->attributes |=
+                                                DNS_RDATASETATTR_CACHE;
+                                        rdataset->trust = dns_trust_answer;
+                                        if (!chaining) {
+                                                /*
+                                                 * This data is "the" answer
+                                                 * to our question only if
+                                                 * we're not chaining.
+                                                 */
+                                                INSIST(!external);
+                                                if (aflag ==
+                                                    DNS_RDATASETATTR_ANSWER)
+                                                        have_answer = ISC_TRUE;
+                                                name->attributes |=
+                                                        DNS_NAMEATTR_ANSWER;
+                                                rdataset->attributes |= aflag;
+                                                if (aa)
+                                                        rdataset->trust =
+                                                          dns_trust_authanswer;
+                                        } else if (external) {
+                                                rdataset->attributes |=
+                                                    DNS_RDATASETATTR_EXTERNAL;
+                                        }
+
+                                        /*
+                                         * DNAME chaining.
+                                         */
+                                        if (found_dname) {
+                                                /*
+                                                 * Copy the the dname into the
+                                                 * qname fixed name.
+                                                 *
+                                                 * Although we check for
+                                                 * failure of the copy
+                                                 * operation, in practice it
+                                                 * should never fail since
+                                                 * we already know that the
+                                                 * result fits in a fixedname.
+                                                 */
+                                                dns_fixedname_init(&fqname);
+                                                result = dns_name_copy(
+                                                  dns_fixedname_name(&dname),
+                                                  dns_fixedname_name(&fqname),
+                                                  NULL);
+                                                if (result != ISC_R_SUCCESS)
+                                                        return (result);
+                                                wanted_chaining = ISC_TRUE;
+                                                name->attributes |=
+                                                        DNS_NAMEATTR_CHAINING;
+                                                rdataset->attributes |=
+                                                    DNS_RDATASETATTR_CHAINING;
+                                                qname = dns_fixedname_name(
+                                                                   &fqname);
+                                        }
+                                }
+                        }
+                        if (wanted_chaining)
+                                chaining = ISC_TRUE;
+                }
+                result = dns_message_nextname(message, DNS_SECTION_ANSWER);
+        }
+        if (result == ISC_R_NOMORE)
+                result = ISC_R_SUCCESS;
+        if (result != ISC_R_SUCCESS)
+                return (result);
+
+        /*
+         * We should have found an answer.
+         */
+        if (!have_answer)
+                return (DNS_R_FORMERR);
+
+        /*
+         * This response is now potentially cacheable.
+         */
+        fctx->attributes |= FCTX_ATTR_WANTCACHE;
+
+        /*
+         * Did chaining end before we got the final answer?
+         */
+        if (chaining) {
+                /*
+                 * Yes.  This may be a negative reply, so hand off
+                 * authority section processing to the noanswer code.
+                 * If it isn't a noanswer response, no harm will be
+                 * done.
+                 */
+                return (noanswer_response(fctx, qname, ISC_FALSE));
+        }
+
+        /*
+         * We didn't end with an incomplete chain, so the rcode should be
+         * "no error".
+         */
+        if (message->rcode != dns_rcode_noerror)
+                return (DNS_R_FORMERR);
+
+        /*
+         * Examine the authority section (if there is one).
+         *
+         * We expect there to be only one owner name for all the rdatasets
+         * in this section, and we expect that it is not external.
+         */
+        done = ISC_FALSE;
+        result = dns_message_firstname(message, DNS_SECTION_AUTHORITY);
+        while (!done && result == ISC_R_SUCCESS) {
+                name = NULL;
+                dns_message_currentname(message, DNS_SECTION_AUTHORITY, &name);
+                external = ISC_TF(!dns_name_issubdomain(name, &fctx->domain));
+                if (!external) {
+                        /*
+                         * We expect to find NS or SIG NS rdatasets, and
+                         * nothing else.
+                         */
+                        for (rdataset = ISC_LIST_HEAD(name->list);
+                             rdataset != NULL;
+                             rdataset = ISC_LIST_NEXT(rdataset, link)) {
+                                if (rdataset->type == dns_rdatatype_ns ||
+                                    (rdataset->type == dns_rdatatype_rrsig &&
+                                     rdataset->covers == dns_rdatatype_ns)) {
+                                        name->attributes |=
+                                                DNS_NAMEATTR_CACHE;
+                                        rdataset->attributes |=
+                                                DNS_RDATASETATTR_CACHE;
+                                        if (aa && !chaining)
+                                                rdataset->trust =
+                                                    dns_trust_authauthority;
+                                        else
+                                                rdataset->trust =
+                                                    dns_trust_additional;
+
+                                        /*
+                                         * Mark any additional data related
+                                         * to this rdataset.
+                                         */
+                                        (void)dns_rdataset_additionaldata(
+                                                        rdataset,
+                                                        check_related,
+                                                        fctx);
+                                        done = ISC_TRUE;
+                                }
+                        }
+                }
+                result = dns_message_nextname(message, DNS_SECTION_AUTHORITY);
+        }
+        if (result == ISC_R_NOMORE)
+                result = ISC_R_SUCCESS;
+
+        return (result);
 }
 
 static void
 resume_dslookup(isc_task_t *task, isc_event_t *event) {
-       dns_fetchevent_t *fevent;
-       dns_resolver_t *res;
-       fetchctx_t *fctx;
-       isc_result_t result;
-       isc_boolean_t bucket_empty = ISC_FALSE;
-       isc_boolean_t locked = ISC_FALSE;
-       unsigned int bucketnum;
-       dns_rdataset_t nameservers;
-       dns_fixedname_t fixed;
-       dns_name_t *domain;
-
-       REQUIRE(event->ev_type == DNS_EVENT_FETCHDONE);
-       fevent = (dns_fetchevent_t *)event;
-       fctx = event->ev_arg;
-       REQUIRE(VALID_FCTX(fctx));
-       res = fctx->res;
-
-       UNUSED(task);
-       FCTXTRACE("resume_dslookup");
-
-       if (fevent->node != NULL)
-               dns_db_detachnode(fevent->db, &fevent->node);
-       if (fevent->db != NULL)
-               dns_db_detach(&fevent->db);
-
-       dns_rdataset_init(&nameservers);
-
-       bucketnum = fctx->bucketnum;
-       if (fevent->result == ISC_R_CANCELED) {
-               dns_resolver_destroyfetch(&fctx->nsfetch);
-               fctx_done(fctx, ISC_R_CANCELED);
-       } else if (fevent->result == ISC_R_SUCCESS) {
-
-               FCTXTRACE("resuming DS lookup");
-
-               dns_resolver_destroyfetch(&fctx->nsfetch);
-               if (dns_rdataset_isassociated(&fctx->nameservers))
-                       dns_rdataset_disassociate(&fctx->nameservers);
-               dns_rdataset_clone(fevent->rdataset, &fctx->nameservers);
-               dns_name_free(&fctx->domain,
-                             fctx->res->buckets[bucketnum].mctx);
-               dns_name_init(&fctx->domain, NULL);
-               result = dns_name_dup(&fctx->nsname,
-                                     fctx->res->buckets[bucketnum].mctx,
-                                     &fctx->domain);
-               if (result != ISC_R_SUCCESS) {
-                       fctx_done(fctx, DNS_R_SERVFAIL);
-                       goto cleanup;
-               }
-               /*
-                * Try again.
-                */
-               fctx_try(fctx);
-       } else {
-               unsigned int n;
-               dns_rdataset_t *nsrdataset = NULL;
-
-               /*
-                * Retrieve state from fctx->nsfetch before we destroy it.
-                */
-               dns_fixedname_init(&fixed);
-               domain = dns_fixedname_name(&fixed);
-               dns_name_copy(&fctx->nsfetch->private->domain, domain, NULL);
-               if (dns_name_equal(&fctx->nsname, domain)) {
-                       fctx_done(fctx, DNS_R_SERVFAIL);
-                       dns_resolver_destroyfetch(&fctx->nsfetch);
-                       goto cleanup;
-               }
-               if (dns_rdataset_isassociated(
-                   &fctx->nsfetch->private->nameservers)) {
-                       dns_rdataset_clone(
-                           &fctx->nsfetch->private->nameservers,
-                           &nameservers);
-                       nsrdataset = &nameservers;
-               } else
-                       domain = NULL;
-               dns_resolver_destroyfetch(&fctx->nsfetch);
-               n = dns_name_countlabels(&fctx->nsname);
-               dns_name_getlabelsequence(&fctx->nsname, 1, n - 1,
-                                         &fctx->nsname);
-
-               if (dns_rdataset_isassociated(fevent->rdataset))
-                       dns_rdataset_disassociate(fevent->rdataset);
-               FCTXTRACE("continuing to look for parent's NS records");
-               result = dns_resolver_createfetch(fctx->res, &fctx->nsname,
-                                                 dns_rdatatype_ns, domain,
-                                                 nsrdataset, NULL, 0, task,
-                                                 resume_dslookup, fctx,
-                                                 &fctx->nsrrset, NULL,
-                                                 &fctx->nsfetch);
-               if (result != ISC_R_SUCCESS)
-                       fctx_done(fctx, result);
-               else {
-                       LOCK(&res->buckets[bucketnum].lock);
-                       locked = ISC_TRUE;
-                       fctx->references++;
-               }
-       }
+        dns_fetchevent_t *fevent;
+        dns_resolver_t *res;
+        fetchctx_t *fctx;
+        isc_result_t result;
+        isc_boolean_t bucket_empty = ISC_FALSE;
+        isc_boolean_t locked = ISC_FALSE;
+        unsigned int bucketnum;
+        dns_rdataset_t nameservers;
+        dns_fixedname_t fixed;
+        dns_name_t *domain;
+
+        REQUIRE(event->ev_type == DNS_EVENT_FETCHDONE);
+        fevent = (dns_fetchevent_t *)event;
+        fctx = event->ev_arg;
+        REQUIRE(VALID_FCTX(fctx));
+        res = fctx->res;
+
+        UNUSED(task);
+        FCTXTRACE("resume_dslookup");
+
+        if (fevent->node != NULL)
+                dns_db_detachnode(fevent->db, &fevent->node);
+        if (fevent->db != NULL)
+                dns_db_detach(&fevent->db);
+
+        dns_rdataset_init(&nameservers);
+
+        bucketnum = fctx->bucketnum;
+        if (fevent->result == ISC_R_CANCELED) {
+                dns_resolver_destroyfetch(&fctx->nsfetch);
+                fctx_done(fctx, ISC_R_CANCELED);
+        } else if (fevent->result == ISC_R_SUCCESS) {
+
+                FCTXTRACE("resuming DS lookup");
+
+                dns_resolver_destroyfetch(&fctx->nsfetch);
+                if (dns_rdataset_isassociated(&fctx->nameservers))
+                        dns_rdataset_disassociate(&fctx->nameservers);
+                dns_rdataset_clone(fevent->rdataset, &fctx->nameservers);
+                dns_name_free(&fctx->domain,
+                              fctx->res->buckets[bucketnum].mctx);
+                dns_name_init(&fctx->domain, NULL);
+                result = dns_name_dup(&fctx->nsname,
+                                      fctx->res->buckets[bucketnum].mctx,
+                                      &fctx->domain);
+                if (result != ISC_R_SUCCESS) {
+                        fctx_done(fctx, DNS_R_SERVFAIL);
+                        goto cleanup;
+                }
+                /*
+                 * Try again.
+                 */
+                fctx_try(fctx);
+        } else {
+                unsigned int n;
+                dns_rdataset_t *nsrdataset = NULL;
+
+                /*
+                 * Retrieve state from fctx->nsfetch before we destroy it.
+                 */
+                dns_fixedname_init(&fixed);
+                domain = dns_fixedname_name(&fixed);
+                dns_name_copy(&fctx->nsfetch->private->domain, domain, NULL);
+                if (dns_name_equal(&fctx->nsname, domain)) {
+                        fctx_done(fctx, DNS_R_SERVFAIL);
+                        dns_resolver_destroyfetch(&fctx->nsfetch);
+                        goto cleanup;
+                }
+                if (dns_rdataset_isassociated(
+                    &fctx->nsfetch->private->nameservers)) {
+                        dns_rdataset_clone(
+                            &fctx->nsfetch->private->nameservers,
+                            &nameservers);
+                        nsrdataset = &nameservers;
+                } else
+                        domain = NULL;
+                dns_resolver_destroyfetch(&fctx->nsfetch);
+                n = dns_name_countlabels(&fctx->nsname);
+                dns_name_getlabelsequence(&fctx->nsname, 1, n - 1,
+                                          &fctx->nsname);
+
+                if (dns_rdataset_isassociated(fevent->rdataset))
+                        dns_rdataset_disassociate(fevent->rdataset);
+                FCTXTRACE("continuing to look for parent's NS records");
+                result = dns_resolver_createfetch(fctx->res, &fctx->nsname,
+                                                  dns_rdatatype_ns, domain,
+                                                  nsrdataset, NULL, 0, task,
+                                                  resume_dslookup, fctx,
+                                                  &fctx->nsrrset, NULL,
+                                                  &fctx->nsfetch);
+                if (result != ISC_R_SUCCESS)
+                        fctx_done(fctx, result);
+                else {
+                        LOCK(&res->buckets[bucketnum].lock);
+                        locked = ISC_TRUE;
+                        fctx->references++;
+                }
+        }
 
  cleanup:
-       if (dns_rdataset_isassociated(&nameservers))
-               dns_rdataset_disassociate(&nameservers);
-       if (dns_rdataset_isassociated(fevent->rdataset))
-               dns_rdataset_disassociate(fevent->rdataset);
-       INSIST(fevent->sigrdataset == NULL);
-       isc_event_free(&event);
-       if (!locked)
-               LOCK(&res->buckets[bucketnum].lock);
-       fctx->references--;
-       if (fctx->references == 0)
-               bucket_empty = fctx_destroy(fctx);
-       UNLOCK(&res->buckets[bucketnum].lock);
-       if (bucket_empty)
-               empty_bucket(res);
+        if (dns_rdataset_isassociated(&nameservers))
+                dns_rdataset_disassociate(&nameservers);
+        if (dns_rdataset_isassociated(fevent->rdataset))
+                dns_rdataset_disassociate(fevent->rdataset);
+        INSIST(fevent->sigrdataset == NULL);
+        isc_event_free(&event);
+        if (!locked)
+                LOCK(&res->buckets[bucketnum].lock);
+        fctx->references--;
+        if (fctx->references == 0)
+                bucket_empty = fctx_destroy(fctx);
+        UNLOCK(&res->buckets[bucketnum].lock);
+        if (bucket_empty)
+                empty_bucket(res);
 }
 
 static inline void
 checknamessection(dns_message_t *message, dns_section_t section) {
-       isc_result_t result;
-       dns_name_t *name;
-       dns_rdata_t rdata = DNS_RDATA_INIT;
-       dns_rdataset_t *rdataset;
-       
-       for (result = dns_message_firstname(message, section);
-            result == ISC_R_SUCCESS;
-            result = dns_message_nextname(message, section))
-       {
-               name = NULL;
-               dns_message_currentname(message, section, &name);
-               for (rdataset = ISC_LIST_HEAD(name->list);
-                    rdataset != NULL;
-                    rdataset = ISC_LIST_NEXT(rdataset, link)) {
-                       for (result = dns_rdataset_first(rdataset);
-                            result == ISC_R_SUCCESS;
-                            result = dns_rdataset_next(rdataset)) {
-                               dns_rdataset_current(rdataset, &rdata);
-                               if (!dns_rdata_checkowner(name, rdata.rdclass,
-                                                         rdata.type,
-                                                         ISC_FALSE) ||
-                                   !dns_rdata_checknames(&rdata, name, NULL))
-                               {
-                                       rdataset->attributes |= 
-                                               DNS_RDATASETATTR_CHECKNAMES;
-                               }
-                               dns_rdata_reset(&rdata);
-                       }
-               }
-       }
+        isc_result_t result;
+        dns_name_t *name;
+        dns_rdata_t rdata = DNS_RDATA_INIT;
+        dns_rdataset_t *rdataset;
+
+        for (result = dns_message_firstname(message, section);
+             result == ISC_R_SUCCESS;
+             result = dns_message_nextname(message, section))
+        {
+                name = NULL;
+                dns_message_currentname(message, section, &name);
+                for (rdataset = ISC_LIST_HEAD(name->list);
+                     rdataset != NULL;
+                     rdataset = ISC_LIST_NEXT(rdataset, link)) {
+                        for (result = dns_rdataset_first(rdataset);
+                             result == ISC_R_SUCCESS;
+                             result = dns_rdataset_next(rdataset)) {
+                                dns_rdataset_current(rdataset, &rdata);
+                                if (!dns_rdata_checkowner(name, rdata.rdclass,
+                                                          rdata.type,
+                                                          ISC_FALSE) ||
+                                    !dns_rdata_checknames(&rdata, name, NULL))
+                                {
+                                        rdataset->attributes |=
+                                                DNS_RDATASETATTR_CHECKNAMES;
+                                }
+                                dns_rdata_reset(&rdata);
+                        }
+                }
+        }
 }
 
 static void
 checknames(dns_message_t *message) {
 
-       checknamessection(message, DNS_SECTION_ANSWER);
-       checknamessection(message, DNS_SECTION_AUTHORITY);
-       checknamessection(message, DNS_SECTION_ADDITIONAL);
+        checknamessection(message, DNS_SECTION_ANSWER);
+        checknamessection(message, DNS_SECTION_AUTHORITY);
+        checknamessection(message, DNS_SECTION_ADDITIONAL);
 }
 
 static void
 log_packet(dns_message_t *message, int level, isc_mem_t *mctx) {
-       isc_buffer_t buffer;
-       char *buf = NULL;
-       int len = 1024;
-       isc_result_t result;
-
-       if (! isc_log_wouldlog(dns_lctx, level))
-               return;
-
-       /*
-        * Note that these are multiline debug messages.  We want a newline
-        * to appear in the log after each message.
-        */
-
-       do {
-               buf = isc_mem_get(mctx, len);
-               if (buf == NULL)
-                       break;
-               isc_buffer_init(&buffer, buf, len);
-               result = dns_message_totext(message, &dns_master_style_debug,
-                                           0, &buffer);
-               if (result == ISC_R_NOSPACE) {
-                       isc_mem_put(mctx, buf, len);
-                       len += 1024;
-               } else if (result == ISC_R_SUCCESS)
-                       isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,
-                                     DNS_LOGMODULE_RESOLVER, level,
-                                     "received packet:\n%.*s",
-                                     (int)isc_buffer_usedlength(&buffer),
-                                     buf);
-       } while (result == ISC_R_NOSPACE);
-
-       if (buf != NULL)
-               isc_mem_put(mctx, buf, len);
+        isc_buffer_t buffer;
+        char *buf = NULL;
+        int len = 1024;
+        isc_result_t result;
+
+        if (! isc_log_wouldlog(dns_lctx, level))
+                return;
+
+        /*
+         * Note that these are multiline debug messages.  We want a newline
+         * to appear in the log after each message.
+         */
+
+        do {
+                buf = isc_mem_get(mctx, len);
+                if (buf == NULL)
+                        break;
+                isc_buffer_init(&buffer, buf, len);
+                result = dns_message_totext(message, &dns_master_style_debug,
+                                            0, &buffer);
+                if (result == ISC_R_NOSPACE) {
+                        isc_mem_put(mctx, buf, len);
+                        len += 1024;
+                } else if (result == ISC_R_SUCCESS)
+                        isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,
+                                      DNS_LOGMODULE_RESOLVER, level,
+                                      "received packet:\n%.*s",
+                                      (int)isc_buffer_usedlength(&buffer),
+                                      buf);
+        } while (result == ISC_R_NOSPACE);
+
+        if (buf != NULL)
+                isc_mem_put(mctx, buf, len);
 }
 
 static void
 resquery_response(isc_task_t *task, isc_event_t *event) {
-       isc_result_t result = ISC_R_SUCCESS;
-       resquery_t *query = event->ev_arg;
-       dns_dispatchevent_t *devent = (dns_dispatchevent_t *)event;
-       isc_boolean_t keep_trying, get_nameservers, resend;
-       isc_boolean_t truncated;
-       dns_message_t *message;
-       fetchctx_t *fctx;
-       dns_name_t *fname;
-       dns_fixedname_t foundname;
-       isc_stdtime_t now;
-       isc_time_t tnow, *finish;
-       dns_adbaddrinfo_t *addrinfo;
-       unsigned int options;
-       unsigned int findoptions;
-       isc_result_t broken_server;
-
-       REQUIRE(VALID_QUERY(query));
-       fctx = query->fctx;
-       options = query->options;
-       REQUIRE(VALID_FCTX(fctx));
-       REQUIRE(event->ev_type == DNS_EVENT_DISPATCH);
-
-       QTRACE("response");
-
-       (void)isc_timer_touch(fctx->timer);
-
-       keep_trying = ISC_FALSE;
-       broken_server = ISC_R_SUCCESS;
-       get_nameservers = ISC_FALSE;
-       resend = ISC_FALSE;
-       truncated = ISC_FALSE;
-       finish = NULL;
-
-       if (fctx->res->exiting) {
-               result = ISC_R_SHUTTINGDOWN;
-               goto done;
-       }
-
-       fctx->timeouts = 0;
-
-       /*
-        * XXXRTH  We should really get the current time just once.  We
-        *         need a routine to convert from an isc_time_t to an
-        *         isc_stdtime_t.
-        */
-       TIME_NOW(&tnow);
-       finish = &tnow;
-       isc_stdtime_get(&now);
-
-       /*
-        * Did the dispatcher have a problem?
-        */
-       if (devent->result != ISC_R_SUCCESS) {
-               if (devent->result == ISC_R_EOF &&
-                   (query->options & DNS_FETCHOPT_NOEDNS0) == 0) {
-                       /*
-                        * The problem might be that they
-                        * don't understand EDNS0.  Turn it
-                        * off and try again.
-                        */
-                       options |= DNS_FETCHOPT_NOEDNS0;
-                       resend = ISC_TRUE;
-                       /*
-                        * Remember that they don't like EDNS0.
-                        */
-                       dns_adb_changeflags(fctx->adb,
-                                           query->addrinfo,
-                                           DNS_FETCHOPT_NOEDNS0,
-                                           DNS_FETCHOPT_NOEDNS0);
-               } else {
-                       /*
-                        * There's no hope for this query.
-                        */
-                       keep_trying = ISC_TRUE;
-               }
-               goto done;
-       }
-
-       message = fctx->rmessage;
-
-       if (query->tsig != NULL) {
-               result = dns_message_setquerytsig(message, query->tsig);
-               if (result != ISC_R_SUCCESS)
-                       goto done;
-       }
-
-       if (query->tsigkey) {
-               result = dns_message_settsigkey(message, query->tsigkey);
-               if (result != ISC_R_SUCCESS)
-                       goto done;
-       }
-
-       result = dns_message_parse(message, &devent->buffer, 0);
-       if (result != ISC_R_SUCCESS) {
-               switch (result) {
-               case ISC_R_UNEXPECTEDEND:
-                       if (!message->question_ok ||
-                           (message->flags & DNS_MESSAGEFLAG_TC) == 0 ||
-                           (options & DNS_FETCHOPT_TCP) != 0) {
-                               /*
-                                * Either the message ended prematurely,
-                                * and/or wasn't marked as being truncated,
-                                * and/or this is a response to a query we
-                                * sent over TCP.  In all of these cases,
-                                * something is wrong with the remote
-                                * server and we don't want to retry using
-                                * TCP.
-                                */
-                               if ((query->options & DNS_FETCHOPT_NOEDNS0)
-                                   == 0) {
-                                       /*
-                                        * The problem might be that they
-                                        * don't understand EDNS0.  Turn it
-                                        * off and try again.
-                                        */
-                                       options |= DNS_FETCHOPT_NOEDNS0;
-                                       resend = ISC_TRUE;
-                                       /*
-                                        * Remember that they don't like EDNS0.
-                                        */
-                                       dns_adb_changeflags(
-                                                       fctx->adb,
-                                                       query->addrinfo,
-                                                       DNS_FETCHOPT_NOEDNS0,
-                                                       DNS_FETCHOPT_NOEDNS0);
-                               } else {
-                                       broken_server = result;
-                                       keep_trying = ISC_TRUE;
-                               }
-                               goto done;
-                       }
-                       /*
-                        * We defer retrying via TCP for a bit so we can
-                        * check out this message further.
-                        */
-                       truncated = ISC_TRUE;
-                       break;
-               case DNS_R_FORMERR:
-                       if ((query->options & DNS_FETCHOPT_NOEDNS0) == 0) {
-                               /*
-                                * The problem might be that they
-                                * don't understand EDNS0.  Turn it
-                                * off and try again.
-                                */
-                               options |= DNS_FETCHOPT_NOEDNS0;
-                               resend = ISC_TRUE;
-                               /*
-                                * Remember that they don't like EDNS0.
-                                */
-                               dns_adb_changeflags(fctx->adb,
-                                                   query->addrinfo,
-                                                   DNS_FETCHOPT_NOEDNS0,
-                                                   DNS_FETCHOPT_NOEDNS0);
-                       } else {
-                               broken_server = DNS_R_UNEXPECTEDRCODE;
-                               keep_trying = ISC_TRUE;
-                       }
-                       goto done;
-               default:
-                       /*
-                        * Something bad has happened.
-                        */
-                       goto done;
-               }
-       }
-
-       /*
-        * Log the incoming packet.
-        */
-       log_packet(message, ISC_LOG_DEBUG(10), fctx->res->mctx);
-
-       /*
-        * If the message is signed, check the signature.  If not, this
-        * returns success anyway.
-        */
-       result = dns_message_checksig(message, fctx->res->view);
-       if (result != ISC_R_SUCCESS)
-               goto done;
-
-       /*
-        * The dispatcher should ensure we only get responses with QR set.
-        */
-       INSIST((message->flags & DNS_MESSAGEFLAG_QR) != 0);
-       /*
-        * INSIST() that the message comes from the place we sent it to,
-        * since the dispatch code should ensure this.
-        *
-        * INSIST() that the message id is correct (this should also be
-        * ensured by the dispatch code).
-        */
-
-
-       /*
-        * Deal with truncated responses by retrying using TCP.
-        */
-       if ((message->flags & DNS_MESSAGEFLAG_TC) != 0)
-               truncated = ISC_TRUE;
-
-       if (truncated) {
-               if ((options & DNS_FETCHOPT_TCP) != 0) {
-                       broken_server = DNS_R_TRUNCATEDTCP;
-                       keep_trying = ISC_TRUE;
-               } else {
-                       options |= DNS_FETCHOPT_TCP;
-                       resend = ISC_TRUE;
-               }
-               goto done;
-       }
-
-       /*
-        * Is it a query response?
-        */
-       if (message->opcode != dns_opcode_query) {
-               /* XXXRTH Log */
-               broken_server = DNS_R_UNEXPECTEDOPCODE;
-               keep_trying = ISC_TRUE;
-               goto done;
-       }
-
-       /*
-        * Is the remote server broken, or does it dislike us?
-        */
-       if (message->rcode != dns_rcode_noerror &&
-           message->rcode != dns_rcode_nxdomain) {
-               if ((message->rcode == dns_rcode_formerr ||
-                    message->rcode == dns_rcode_notimp ||
-                    message->rcode == dns_rcode_servfail) &&
-                   (query->options & DNS_FETCHOPT_NOEDNS0) == 0) {
-                       /*
-                        * It's very likely they don't like EDNS0.
-                        *
-                        * XXXRTH  We should check if the question
-                        *         we're asking requires EDNS0, and
-                        *         if so, we should bail out.
-                        */
-                       options |= DNS_FETCHOPT_NOEDNS0;
-                       resend = ISC_TRUE;
-                       /*
-                        * Remember that they don't like EDNS0.
-                        */
-                       if (message->rcode != dns_rcode_servfail)
-                               dns_adb_changeflags(fctx->adb, query->addrinfo,
-                                                   DNS_FETCHOPT_NOEDNS0,
-                                                   DNS_FETCHOPT_NOEDNS0);
-               } else if (message->rcode == dns_rcode_formerr) {
-                       if (ISFORWARDER(query->addrinfo)) {
-                               /*
-                                * This forwarder doesn't understand us,
-                                * but other forwarders might.  Keep trying.
-                                */
-                               broken_server = DNS_R_REMOTEFORMERR;
-                               keep_trying = ISC_TRUE;
-                       } else {
-                               /*
-                                * The server doesn't understand us.  Since
-                                * all servers for a zone need similar
-                                * capabilities, we assume that we will get
-                                * FORMERR from all servers, and thus we
-                                * cannot make any more progress with this
-                                * fetch.
-                                */
-                               result = DNS_R_FORMERR;
-                       }
-               } else if (message->rcode == dns_rcode_yxdomain) {
-                       /*
-                        * DNAME mapping failed because the new name
-                        * was too long.  There's no chance of success
-                        * for this fetch.
-                        */
-                       result = DNS_R_YXDOMAIN;
-               } else if (message->rcode == dns_rcode_badvers) {
-                       dns_rdataset_t *opt;
-                       unsigned int flags, mask;
-                       unsigned int version;
-
-                       resend = ISC_TRUE;
-                       opt = dns_message_getopt(message);
-                       version = (opt->ttl >> 16) & 0xff;
-                       flags = (version << DNS_FETCHOPT_EDNSVERSIONSHIFT) |
-                               DNS_FETCHOPT_EDNSVERSIONSET;
-                       mask = DNS_FETCHOPT_EDNSVERSIONMASK |
-                              DNS_FETCHOPT_EDNSVERSIONSET;
-                       switch (version) {
-                       case 0:
-                               dns_adb_changeflags(fctx->adb, query->addrinfo,
-                                                   flags, mask);
-                               break;
-                       default:
-                               broken_server = DNS_R_BADVERS;
-                               keep_trying = ISC_TRUE;
-                               break;
-                       }
-               } else {
-                       /*
-                        * XXXRTH log.
-                        */
-                       broken_server = DNS_R_UNEXPECTEDRCODE;
-                       INSIST(broken_server != ISC_R_SUCCESS);
-                       keep_trying = ISC_TRUE;
-               }
-               goto done;
-       }
-
-       /*
-        * Is the question the same as the one we asked?
-        */
-       result = same_question(fctx);
-       if (result != ISC_R_SUCCESS) {
-               /* XXXRTH Log */
-               if (result == DNS_R_FORMERR)
-                       keep_trying = ISC_TRUE;
-               goto done;
-       }
-
-       /*
-        * Is the server lame?
-        */
-       if (fctx->res->lame_ttl != 0 && !ISFORWARDER(query->addrinfo) &&
-           is_lame(fctx)) {
-               log_lame(fctx, query->addrinfo);
-               result = dns_adb_marklame(fctx->adb, query->addrinfo,
-                                         &fctx->name, fctx->type,
-                                         now + fctx->res->lame_ttl);
-               if (result != ISC_R_SUCCESS)
-                       isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,
-                                     DNS_LOGMODULE_RESOLVER, ISC_LOG_ERROR,
-                                     "could not mark server as lame: %s",
-                                     isc_result_totext(result));
-               broken_server = DNS_R_LAME;
-               keep_trying = ISC_TRUE;
-               goto done;
-       }
-
-       /*
-        * Enforce delegations only zones like NET and COM.
-        */
-       if (!ISFORWARDER(query->addrinfo) &&
-           dns_view_isdelegationonly(fctx->res->view, &fctx->domain) &&
-           !dns_name_equal(&fctx->domain, &fctx->name) &&
-           fix_mustbedelegationornxdomain(message, fctx)) {
-               char namebuf[DNS_NAME_FORMATSIZE];
-               char domainbuf[DNS_NAME_FORMATSIZE];
-               char addrbuf[ISC_SOCKADDR_FORMATSIZE];
-               char classbuf[64];
-               char typebuf[64];
-
-               dns_name_format(&fctx->name, namebuf, sizeof(namebuf));
-               dns_name_format(&fctx->domain, domainbuf, sizeof(domainbuf));
-               dns_rdatatype_format(fctx->type, typebuf, sizeof(typebuf));
-               dns_rdataclass_format(fctx->res->rdclass, classbuf,
-                                     sizeof(classbuf));
-               isc_sockaddr_format(&query->addrinfo->sockaddr, addrbuf,
-                                   sizeof(addrbuf));
-
-               isc_log_write(dns_lctx, DNS_LOGCATEGORY_DELEGATION_ONLY,
-                            DNS_LOGMODULE_RESOLVER, ISC_LOG_NOTICE,
-                            "enforced delegation-only for '%s' (%s/%s/%s) "
-                            "from %s",
-                            domainbuf, namebuf, typebuf, classbuf, addrbuf);
-       }
-
-       if ((fctx->res->options & DNS_RESOLVER_CHECKNAMES) != 0)
-               checknames(message);
-
-       /*
-        * Clear cache bits.
-        */
-       fctx->attributes &= ~(FCTX_ATTR_WANTNCACHE | FCTX_ATTR_WANTCACHE);
-
-       /*
-        * Did we get any answers?
-        */
-       if (message->counts[DNS_SECTION_ANSWER] > 0 &&
-           (message->rcode == dns_rcode_noerror ||
-            message->rcode == dns_rcode_nxdomain)) {
-               /*
-                * We've got answers.  However, if we sent
-                * a BIND 8 server an NS query, it may have
-                * incorrectly responded with a non-authoritative
-                * answer instead of a referral.  Since this
-                * answer lacks the SIGs necessary to do DNSSEC
-                * validation, we must invoke the following special
-                * kludge to treat it as a referral.
-                */
-               if (fctx->type == dns_rdatatype_ns &&
-                   (message->flags & DNS_MESSAGEFLAG_AA) == 0 &&
-                   !ISFORWARDER(query->addrinfo))
-               {
-                       result = noanswer_response(fctx, NULL, ISC_TRUE);
-                       if (result != DNS_R_DELEGATION) {
-                               /*
-                                * The answer section must have contained
-                                * something other than the NS records
-                                * we asked for.  Since AA is not set
-                                * and the server is not a forwarder,
-                                * it is technically lame and it's easier
-                                * to treat it as such than to figure out
-                                * some more elaborate course of action.
-                                */
-                               broken_server = DNS_R_LAME;
-                               keep_trying = ISC_TRUE;
-                               goto done;
-                       }
-                       goto force_referral;
-               }
-               result = answer_response(fctx);
-               if (result != ISC_R_SUCCESS) {
-                       if (result == DNS_R_FORMERR)
-                               keep_trying = ISC_TRUE;
-                       goto done;
-               }
-       } else if (message->counts[DNS_SECTION_AUTHORITY] > 0 ||
-                  message->rcode == dns_rcode_noerror ||
-                  message->rcode == dns_rcode_nxdomain) {
-               /*
-                * NXDOMAIN, NXRDATASET, or referral.
-                */
-               result = noanswer_response(fctx, NULL, ISC_FALSE);
-               if (result == DNS_R_CHASEDSSERVERS) {
-               } else if (result == DNS_R_DELEGATION) {
-               force_referral:
-                       /*
-                        * We don't have the answer, but we know a better
-                        * place to look.
-                        */
-                       get_nameservers = ISC_TRUE;
-                       keep_trying = ISC_TRUE;
-                       /*
-                        * We have a new set of name servers, and it
-                        * has not experienced any restarts yet.
-                        */
-                       fctx->restarts = 0;
-                       result = ISC_R_SUCCESS;
-               } else if (result != ISC_R_SUCCESS) {
-                       /*
-                        * Something has gone wrong.
-                        */
-                       if (result == DNS_R_FORMERR)
-                               keep_trying = ISC_TRUE;
-                       goto done;
-               }
-       } else {
-               /*
-                * The server is insane.
-                */
-               /* XXXRTH Log */
-               broken_server = DNS_R_UNEXPECTEDRCODE;
-               keep_trying = ISC_TRUE;
-               goto done;
-       }
-
-       /*
-        * Follow additional section data chains.
-        */
-       chase_additional(fctx);
-
-       /*
-        * Cache the cacheable parts of the message.  This may also cause
-        * work to be queued to the DNSSEC validator.
-        */
-       if (WANTCACHE(fctx)) {
-               result = cache_message(fctx, query->addrinfo, now);
-               if (result != ISC_R_SUCCESS)
-                       goto done;
-       }
-
-       /*
-        * Ncache the negatively cacheable parts of the message.  This may
-        * also cause work to be queued to the DNSSEC validator.
-        */
-       if (WANTNCACHE(fctx)) {
-               dns_rdatatype_t covers;
-               if (message->rcode == dns_rcode_nxdomain)
-                       covers = dns_rdatatype_any;
-               else
-                       covers = fctx->type;
-
-               /*
-                * Cache any negative cache entries in the message.
-                */
-               result = ncache_message(fctx, query->addrinfo, covers, now);
-       }
+        isc_result_t result = ISC_R_SUCCESS;
+        resquery_t *query = event->ev_arg;
+        dns_dispatchevent_t *devent = (dns_dispatchevent_t *)event;
+        isc_boolean_t keep_trying, get_nameservers, resend;
+        isc_boolean_t truncated;
+        dns_message_t *message;
+        fetchctx_t *fctx;
+        dns_name_t *fname;
+        dns_fixedname_t foundname;
+        isc_stdtime_t now;
+        isc_time_t tnow, *finish;
+        dns_adbaddrinfo_t *addrinfo;
+        unsigned int options;
+        unsigned int findoptions;
+        isc_result_t broken_server;
+
+        REQUIRE(VALID_QUERY(query));
+        fctx = query->fctx;
+        options = query->options;
+        REQUIRE(VALID_FCTX(fctx));
+        REQUIRE(event->ev_type == DNS_EVENT_DISPATCH);
+
+        QTRACE("response");
+
+        (void)isc_timer_touch(fctx->timer);
+
+        keep_trying = ISC_FALSE;
+        broken_server = ISC_R_SUCCESS;
+        get_nameservers = ISC_FALSE;
+        resend = ISC_FALSE;
+        truncated = ISC_FALSE;
+        finish = NULL;
+
+        if (fctx->res->exiting) {
+                result = ISC_R_SHUTTINGDOWN;
+                goto done;
+        }
+
+        fctx->timeouts = 0;
+
+        /*
+         * XXXRTH  We should really get the current time just once.  We
+         *         need a routine to convert from an isc_time_t to an
+         *         isc_stdtime_t.
+         */
+        TIME_NOW(&tnow);
+        finish = &tnow;
+        isc_stdtime_get(&now);
+
+        /*
+         * Did the dispatcher have a problem?
+         */
+        if (devent->result != ISC_R_SUCCESS) {
+                if (devent->result == ISC_R_EOF &&
+                    (query->options & DNS_FETCHOPT_NOEDNS0) == 0) {
+                        /*
+                         * The problem might be that they
+                         * don't understand EDNS0.  Turn it
+                         * off and try again.
+                         */
+                        options |= DNS_FETCHOPT_NOEDNS0;
+                        resend = ISC_TRUE;
+                        /*
+                         * Remember that they don't like EDNS0.
+                         */
+                        dns_adb_changeflags(fctx->adb,
+                                            query->addrinfo,
+                                            DNS_FETCHOPT_NOEDNS0,
+                                            DNS_FETCHOPT_NOEDNS0);
+                } else {
+                        /*
+                         * There's no hope for this query.
+                         */
+                        keep_trying = ISC_TRUE;
+                }
+                goto done;
+        }
+
+        message = fctx->rmessage;
+
+        if (query->tsig != NULL) {
+                result = dns_message_setquerytsig(message, query->tsig);
+                if (result != ISC_R_SUCCESS)
+                        goto done;
+        }
+
+        if (query->tsigkey) {
+                result = dns_message_settsigkey(message, query->tsigkey);
+                if (result != ISC_R_SUCCESS)
+                        goto done;
+        }
+
+        result = dns_message_parse(message, &devent->buffer, 0);
+        if (result != ISC_R_SUCCESS) {
+                switch (result) {
+                case ISC_R_UNEXPECTEDEND:
+                        if (!message->question_ok ||
+                            (message->flags & DNS_MESSAGEFLAG_TC) == 0 ||
+                            (options & DNS_FETCHOPT_TCP) != 0) {
+                                /*
+                                 * Either the message ended prematurely,
+                                 * and/or wasn't marked as being truncated,
+                                 * and/or this is a response to a query we
+                                 * sent over TCP.  In all of these cases,
+                                 * something is wrong with the remote
+                                 * server and we don't want to retry using
+                                 * TCP.
+                                 */
+                                if ((query->options & DNS_FETCHOPT_NOEDNS0)
+                                    == 0) {
+                                        /*
+                                         * The problem might be that they
+                                         * don't understand EDNS0.  Turn it
+                                         * off and try again.
+                                         */
+                                        options |= DNS_FETCHOPT_NOEDNS0;
+                                        resend = ISC_TRUE;
+                                        /*
+                                         * Remember that they don't like EDNS0.
+                                         */
+                                        dns_adb_changeflags(
+                                                        fctx->adb,
+                                                        query->addrinfo,
+                                                        DNS_FETCHOPT_NOEDNS0,
+                                                        DNS_FETCHOPT_NOEDNS0);
+                                } else {
+                                        broken_server = result;
+                                        keep_trying = ISC_TRUE;
+                                }
+                                goto done;
+                        }
+                        /*
+                         * We defer retrying via TCP for a bit so we can
+                         * check out this message further.
+                         */
+                        truncated = ISC_TRUE;
+                        break;
+                case DNS_R_FORMERR:
+                        if ((query->options & DNS_FETCHOPT_NOEDNS0) == 0) {
+                                /*
+                                 * The problem might be that they
+                                 * don't understand EDNS0.  Turn it
+                                 * off and try again.
+                                 */
+                                options |= DNS_FETCHOPT_NOEDNS0;
+                                resend = ISC_TRUE;
+                                /*
+                                 * Remember that they don't like EDNS0.
+                                 */
+                                dns_adb_changeflags(fctx->adb,
+                                                    query->addrinfo,
+                                                    DNS_FETCHOPT_NOEDNS0,
+                                                    DNS_FETCHOPT_NOEDNS0);
+                        } else {
+                                broken_server = DNS_R_UNEXPECTEDRCODE;
+                                keep_trying = ISC_TRUE;
+                        }
+                        goto done;
+                default:
+                        /*
+                         * Something bad has happened.
+                         */
+                        goto done;
+                }
+        }
+
+        /*
+         * Log the incoming packet.
+         */
+        log_packet(message, ISC_LOG_DEBUG(10), fctx->res->mctx);
+
+        /*
+         * If the message is signed, check the signature.  If not, this
+         * returns success anyway.
+         */
+        result = dns_message_checksig(message, fctx->res->view);
+        if (result != ISC_R_SUCCESS)
+                goto done;
+
+        /*
+         * The dispatcher should ensure we only get responses with QR set.
+         */
+        INSIST((message->flags & DNS_MESSAGEFLAG_QR) != 0);
+        /*
+         * INSIST() that the message comes from the place we sent it to,
+         * since the dispatch code should ensure this.
+         *
+         * INSIST() that the message id is correct (this should also be
+         * ensured by the dispatch code).
+         */
+
+
+        /*
+         * Deal with truncated responses by retrying using TCP.
+         */
+        if ((message->flags & DNS_MESSAGEFLAG_TC) != 0)
+                truncated = ISC_TRUE;
+
+        if (truncated) {
+                if ((options & DNS_FETCHOPT_TCP) != 0) {
+                        broken_server = DNS_R_TRUNCATEDTCP;
+                        keep_trying = ISC_TRUE;
+                } else {
+                        options |= DNS_FETCHOPT_TCP;
+                        resend = ISC_TRUE;
+                }
+                goto done;
+        }
+
+        /*
+         * Is it a query response?
+         */
+        if (message->opcode != dns_opcode_query) {
+                /* XXXRTH Log */
+                broken_server = DNS_R_UNEXPECTEDOPCODE;
+                keep_trying = ISC_TRUE;
+                goto done;
+        }
+
+        /*
+         * Is the remote server broken, or does it dislike us?
+         */
+        if (message->rcode != dns_rcode_noerror &&
+            message->rcode != dns_rcode_nxdomain) {
+                if ((message->rcode == dns_rcode_formerr ||
+                     message->rcode == dns_rcode_notimp ||
+                     message->rcode == dns_rcode_servfail) &&
+                    (query->options & DNS_FETCHOPT_NOEDNS0) == 0) {
+                        /*
+                         * It's very likely they don't like EDNS0.
+                         *
+                         * XXXRTH  We should check if the question
+                         *         we're asking requires EDNS0, and
+                         *         if so, we should bail out.
+                         */
+                        options |= DNS_FETCHOPT_NOEDNS0;
+                        resend = ISC_TRUE;
+                        /*
+                         * Remember that they don't like EDNS0.
+                         */
+                        if (message->rcode != dns_rcode_servfail)
+                                dns_adb_changeflags(fctx->adb, query->addrinfo,
+                                                    DNS_FETCHOPT_NOEDNS0,
+                                                    DNS_FETCHOPT_NOEDNS0);
+                } else if (message->rcode == dns_rcode_formerr) {
+                        if (ISFORWARDER(query->addrinfo)) {
+                                /*
+                                 * This forwarder doesn't understand us,
+                                 * but other forwarders might.  Keep trying.
+                                 */
+                                broken_server = DNS_R_REMOTEFORMERR;
+                                keep_trying = ISC_TRUE;
+                        } else {
+                                /*
+                                 * The server doesn't understand us.  Since
+                                 * all servers for a zone need similar
+                                 * capabilities, we assume that we will get
+                                 * FORMERR from all servers, and thus we
+                                 * cannot make any more progress with this
+                                 * fetch.
+                                 */
+                                result = DNS_R_FORMERR;
+                        }
+                } else if (message->rcode == dns_rcode_yxdomain) {
+                        /*
+                         * DNAME mapping failed because the new name
+                         * was too long.  There's no chance of success
+                         * for this fetch.
+                         */
+                        result = DNS_R_YXDOMAIN;
+                } else if (message->rcode == dns_rcode_badvers) {
+                        dns_rdataset_t *opt;
+                        unsigned int flags, mask;
+                        unsigned int version;
+
+                        resend = ISC_TRUE;
+                        opt = dns_message_getopt(message);
+                        version = (opt->ttl >> 16) & 0xff;
+                        flags = (version << DNS_FETCHOPT_EDNSVERSIONSHIFT) |
+                                DNS_FETCHOPT_EDNSVERSIONSET;
+                        mask = DNS_FETCHOPT_EDNSVERSIONMASK |
+                               DNS_FETCHOPT_EDNSVERSIONSET;
+                        switch (version) {
+                        case 0:
+                                dns_adb_changeflags(fctx->adb, query->addrinfo,
+                                                    flags, mask);
+                                break;
+                        default:
+                                broken_server = DNS_R_BADVERS;
+                                keep_trying = ISC_TRUE;
+                                break;
+                        }
+                } else {
+                        /*
+                         * XXXRTH log.
+                         */
+                        broken_server = DNS_R_UNEXPECTEDRCODE;
+                        INSIST(broken_server != ISC_R_SUCCESS);
+                        keep_trying = ISC_TRUE;
+                }
+                goto done;
+        }
+
+        /*
+         * Is the question the same as the one we asked?
+         */
+        result = same_question(fctx);
+        if (result != ISC_R_SUCCESS) {
+                /* XXXRTH Log */
+                if (result == DNS_R_FORMERR)
+                        keep_trying = ISC_TRUE;
+                goto done;
+        }
+
+        /*
+         * Is the server lame?
+         */
+        if (fctx->res->lame_ttl != 0 && !ISFORWARDER(query->addrinfo) &&
+            is_lame(fctx)) {
+                log_lame(fctx, query->addrinfo);
+                result = dns_adb_marklame(fctx->adb, query->addrinfo,
+                                          &fctx->name, fctx->type,
+                                          now + fctx->res->lame_ttl);
+                if (result != ISC_R_SUCCESS)
+                        isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,
+                                      DNS_LOGMODULE_RESOLVER, ISC_LOG_ERROR,
+                                      "could not mark server as lame: %s",
+                                      isc_result_totext(result));
+                broken_server = DNS_R_LAME;
+                keep_trying = ISC_TRUE;
+                goto done;
+        }
+
+        /*
+         * Enforce delegations only zones like NET and COM.
+         */
+        if (!ISFORWARDER(query->addrinfo) &&
+            dns_view_isdelegationonly(fctx->res->view, &fctx->domain) &&
+            !dns_name_equal(&fctx->domain, &fctx->name) &&
+            fix_mustbedelegationornxdomain(message, fctx)) {
+                char namebuf[DNS_NAME_FORMATSIZE];
+                char domainbuf[DNS_NAME_FORMATSIZE];
+                char addrbuf[ISC_SOCKADDR_FORMATSIZE];
+                char classbuf[64];
+                char typebuf[64];
+
+                dns_name_format(&fctx->name, namebuf, sizeof(namebuf));
+                dns_name_format(&fctx->domain, domainbuf, sizeof(domainbuf));
+                dns_rdatatype_format(fctx->type, typebuf, sizeof(typebuf));
+                dns_rdataclass_format(fctx->res->rdclass, classbuf,
+                                      sizeof(classbuf));
+                isc_sockaddr_format(&query->addrinfo->sockaddr, addrbuf,
+                                    sizeof(addrbuf));
+
+                isc_log_write(dns_lctx, DNS_LOGCATEGORY_DELEGATION_ONLY,
+                             DNS_LOGMODULE_RESOLVER, ISC_LOG_NOTICE,
+                             "enforced delegation-only for '%s' (%s/%s/%s) "
+                             "from %s",
+                             domainbuf, namebuf, typebuf, classbuf, addrbuf);
+        }
+
+        if ((fctx->res->options & DNS_RESOLVER_CHECKNAMES) != 0)
+                checknames(message);
+
+        /*
+         * Clear cache bits.
+         */
+        fctx->attributes &= ~(FCTX_ATTR_WANTNCACHE | FCTX_ATTR_WANTCACHE);
+
+        /*
+         * Did we get any answers?
+         */
+        if (message->counts[DNS_SECTION_ANSWER] > 0 &&
+            (message->rcode == dns_rcode_noerror ||
+             message->rcode == dns_rcode_nxdomain)) {
+                /*
+                 * We've got answers.  However, if we sent
+                 * a BIND 8 server an NS query, it may have
+                 * incorrectly responded with a non-authoritative
+                 * answer instead of a referral.  Since this
+                 * answer lacks the SIGs necessary to do DNSSEC
+                 * validation, we must invoke the following special
+                 * kludge to treat it as a referral.
+                 */
+                if (fctx->type == dns_rdatatype_ns &&
+                    (message->flags & DNS_MESSAGEFLAG_AA) == 0 &&
+                    !ISFORWARDER(query->addrinfo))
+                {
+                        result = noanswer_response(fctx, NULL, ISC_TRUE);
+                        if (result != DNS_R_DELEGATION) {
+                                /*
+                                 * The answer section must have contained
+                                 * something other than the NS records
+                                 * we asked for.  Since AA is not set
+                                 * and the server is not a forwarder,
+                                 * it is technically lame and it's easier
+                                 * to treat it as such than to figure out
+                                 * some more elaborate course of action.
+                                 */
+                                broken_server = DNS_R_LAME;
+                                keep_trying = ISC_TRUE;
+                                goto done;
+                        }
+                        goto force_referral;
+                }
+                result = answer_response(fctx);
+                if (result != ISC_R_SUCCESS) {
+                        if (result == DNS_R_FORMERR)
+                                keep_trying = ISC_TRUE;
+                        goto done;
+                }
+        } else if (message->counts[DNS_SECTION_AUTHORITY] > 0 ||
+                   message->rcode == dns_rcode_noerror ||
+                   message->rcode == dns_rcode_nxdomain) {
+                /*
+                 * NXDOMAIN, NXRDATASET, or referral.
+                 */
+                result = noanswer_response(fctx, NULL, ISC_FALSE);
+                if (result == DNS_R_CHASEDSSERVERS) {
+                } else if (result == DNS_R_DELEGATION) {
+                force_referral:
+                        /*
+                         * We don't have the answer, but we know a better
+                         * place to look.
+                         */
+                        get_nameservers = ISC_TRUE;
+                        keep_trying = ISC_TRUE;
+                        /*
+                         * We have a new set of name servers, and it
+                         * has not experienced any restarts yet.
+                         */
+                        fctx->restarts = 0;
+                        result = ISC_R_SUCCESS;
+                } else if (result != ISC_R_SUCCESS) {
+                        /*
+                         * Something has gone wrong.
+                         */
+                        if (result == DNS_R_FORMERR)
+                                keep_trying = ISC_TRUE;
+                        goto done;
+                }
+        } else {
+                /*
+                 * The server is insane.
+                 */
+                /* XXXRTH Log */
+                broken_server = DNS_R_UNEXPECTEDRCODE;
+                keep_trying = ISC_TRUE;
+                goto done;
+        }
+
+        /*
+         * Follow additional section data chains.
+         */
+        chase_additional(fctx);
+
+        /*
+         * Cache the cacheable parts of the message.  This may also cause
+         * work to be queued to the DNSSEC validator.
+         */
+        if (WANTCACHE(fctx)) {
+                result = cache_message(fctx, query->addrinfo, now);
+                if (result != ISC_R_SUCCESS)
+                        goto done;
+        }
+
+        /*
+         * Ncache the negatively cacheable parts of the message.  This may
+         * also cause work to be queued to the DNSSEC validator.
+         */
+        if (WANTNCACHE(fctx)) {
+                dns_rdatatype_t covers;
+                if (message->rcode == dns_rcode_nxdomain)
+                        covers = dns_rdatatype_any;
+                else
+                        covers = fctx->type;
+
+                /*
+                 * Cache any negative cache entries in the message.
+                 */
+                result = ncache_message(fctx, query->addrinfo, covers, now);
+        }
 
  done:
-       /*
-        * Remember the query's addrinfo, in case we need to mark the
-        * server as broken.
-        */
-       addrinfo = query->addrinfo;
-
-       /*
-        * Cancel the query.
-        *
-        * XXXRTH  Don't cancel the query if waiting for validation?
-        */
-       fctx_cancelquery(&query, &devent, finish, ISC_FALSE);
-
-       if (keep_trying) {
-               if (result == DNS_R_FORMERR)
-                       broken_server = DNS_R_FORMERR;
-               if (broken_server != ISC_R_SUCCESS) {
-                       /*
-                        * Add this server to the list of bad servers for
-                        * this fctx.
-                        */
-                       add_bad(fctx, addrinfo, broken_server);
-               }
-
-               if (get_nameservers) {
-                       dns_name_t *name;
-                       dns_fixedname_init(&foundname);
-                       fname = dns_fixedname_name(&foundname);
-                       if (result != ISC_R_SUCCESS) {
-                               fctx_done(fctx, DNS_R_SERVFAIL);
-                               return;
-                       }
-                       findoptions = 0;
-                       if (dns_rdatatype_atparent(fctx->type))
-                               findoptions |= DNS_DBFIND_NOEXACT;
-                       if ((options & DNS_FETCHOPT_UNSHARED) == 0)
-                               name = &fctx->name;
-                       else
-                               name = &fctx->domain;
-                       result = dns_view_findzonecut(fctx->res->view,
-                                                     name, fname,
-                                                     now, findoptions,
-                                                     ISC_TRUE,
-                                                     &fctx->nameservers,
-                                                     NULL);
-                       if (result != ISC_R_SUCCESS) {
-                               FCTXTRACE("couldn't find a zonecut");
-                               fctx_done(fctx, DNS_R_SERVFAIL);
-                               return;
-                       }
-                       if (!dns_name_issubdomain(fname, &fctx->domain)) {
-                               /*
-                                * The best nameservers are now above our
-                                * QDOMAIN.
-                                */
-                               FCTXTRACE("nameservers now above QDOMAIN");
-                               fctx_done(fctx, DNS_R_SERVFAIL);
-                               return;
-                       }
-                       dns_name_free(&fctx->domain,
-                                     fctx->res->buckets[fctx->bucketnum].mctx);
-                       dns_name_init(&fctx->domain, NULL);
-                       result = dns_name_dup(fname,
-                                             fctx->res->buckets[fctx->bucketnum].mctx,
-                                             &fctx->domain);
-                       if (result != ISC_R_SUCCESS) {
-                               fctx_done(fctx, DNS_R_SERVFAIL);
-                               return;
-                       }
-                       fctx_cancelqueries(fctx, ISC_TRUE);
-                       fctx_cleanupfinds(fctx);
-                       fctx_cleanupaltfinds(fctx);
-                       fctx_cleanupforwaddrs(fctx);
-                       fctx_cleanupaltaddrs(fctx);
-               }
-               /*
-                * Try again.
-                */
-               fctx_try(fctx);
-       } else if (resend) {
-               /*
-                * Resend (probably with changed options).
-                */
-               FCTXTRACE("resend");
-               result = fctx_query(fctx, addrinfo, options);
-               if (result != ISC_R_SUCCESS)
-                       fctx_done(fctx, result);
-       } else if (result == ISC_R_SUCCESS && !HAVE_ANSWER(fctx)) {
-               /*
-                * All has gone well so far, but we are waiting for the
-                * DNSSEC validator to validate the answer.
-                */
-               FCTXTRACE("wait for validator");
-               fctx_cancelqueries(fctx, ISC_TRUE);
-               /*
-                * We must not retransmit while the validator is working;
-                * it has references to the current rmessage.
-                */
-               result = fctx_stopidletimer(fctx);
-               if (result != ISC_R_SUCCESS)
-                       fctx_done(fctx, result);
-       } else if (result == DNS_R_CHASEDSSERVERS) {
-               unsigned int n;
-               add_bad(fctx, addrinfo, result);
-               fctx_cancelqueries(fctx, ISC_TRUE);
-               fctx_cleanupfinds(fctx);
-               fctx_cleanupforwaddrs(fctx);
-
-               n = dns_name_countlabels(&fctx->name);
-               dns_name_getlabelsequence(&fctx->name, 1, n - 1, &fctx->nsname);
-
-               FCTXTRACE("suspending DS lookup to find parent's NS records");
-
-               result = dns_resolver_createfetch(fctx->res, &fctx->nsname,
-                                                 dns_rdatatype_ns,
-                                                 NULL, NULL, NULL, 0, task,
-                                                 resume_dslookup, fctx,
-                                                 &fctx->nsrrset, NULL,
-                                                 &fctx->nsfetch);
-               if (result != ISC_R_SUCCESS)
-                       fctx_done(fctx, result);
-               LOCK(&fctx->res->buckets[fctx->bucketnum].lock);
-               fctx->references++;
-               UNLOCK(&fctx->res->buckets[fctx->bucketnum].lock);
-               result = fctx_stopidletimer(fctx);
-               if (result != ISC_R_SUCCESS)
-                       fctx_done(fctx, result);
-       } else {
-               /*
-                * We're done.
-                */
-               fctx_done(fctx, result);
-       }
+        /*
+         * Remember the query's addrinfo, in case we need to mark the
+         * server as broken.
+         */
+        addrinfo = query->addrinfo;
+
+        /*
+         * Cancel the query.
+         *
+         * XXXRTH  Don't cancel the query if waiting for validation?
+         */
+        fctx_cancelquery(&query, &devent, finish, ISC_FALSE);
+
+        if (keep_trying) {
+                if (result == DNS_R_FORMERR)
+                        broken_server = DNS_R_FORMERR;
+                if (broken_server != ISC_R_SUCCESS) {
+                        /*
+                         * Add this server to the list of bad servers for
+                         * this fctx.
+                         */
+                        add_bad(fctx, addrinfo, broken_server);
+                }
+
+                if (get_nameservers) {
+                        dns_name_t *name;
+                        dns_fixedname_init(&foundname);
+                        fname = dns_fixedname_name(&foundname);
+                        if (result != ISC_R_SUCCESS) {
+                                fctx_done(fctx, DNS_R_SERVFAIL);
+                                return;
+                        }
+                        findoptions = 0;
+                        if (dns_rdatatype_atparent(fctx->type))
+                                findoptions |= DNS_DBFIND_NOEXACT;
+                        if ((options & DNS_FETCHOPT_UNSHARED) == 0)
+                                name = &fctx->name;
+                        else
+                                name = &fctx->domain;
+                        result = dns_view_findzonecut(fctx->res->view,
+                                                      name, fname,
+                                                      now, findoptions,
+                                                      ISC_TRUE,
+                                                      &fctx->nameservers,
+                                                      NULL);
+                        if (result != ISC_R_SUCCESS) {
+                                FCTXTRACE("couldn't find a zonecut");
+                                fctx_done(fctx, DNS_R_SERVFAIL);
+                                return;
+                        }
+                        if (!dns_name_issubdomain(fname, &fctx->domain)) {
+                                /*
+                                 * The best nameservers are now above our
+                                 * QDOMAIN.
+                                 */
+                                FCTXTRACE("nameservers now above QDOMAIN");
+                                fctx_done(fctx, DNS_R_SERVFAIL);
+                                return;
+                        }
+                        dns_name_free(&fctx->domain,
+                                      fctx->res->buckets[fctx->bucketnum].mctx);
+                        dns_name_init(&fctx->domain, NULL);
+                        result = dns_name_dup(fname,
+                                              fctx->res->buckets[fctx->bucketnum].mctx,
+                                              &fctx->domain);
+                        if (result != ISC_R_SUCCESS) {
+                                fctx_done(fctx, DNS_R_SERVFAIL);
+                                return;
+                        }
+                        fctx_cancelqueries(fctx, ISC_TRUE);
+                        fctx_cleanupfinds(fctx);
+                        fctx_cleanupaltfinds(fctx);
+                        fctx_cleanupforwaddrs(fctx);
+                        fctx_cleanupaltaddrs(fctx);
+                }
+                /*
+                 * Try again.
+                 */
+                fctx_try(fctx);
+        } else if (resend) {
+                /*
+                 * Resend (probably with changed options).
+                 */
+                FCTXTRACE("resend");
+                result = fctx_query(fctx, addrinfo, options);
+                if (result != ISC_R_SUCCESS)
+                        fctx_done(fctx, result);
+        } else if (result == ISC_R_SUCCESS && !HAVE_ANSWER(fctx)) {
+                /*
+                 * All has gone well so far, but we are waiting for the
+                 * DNSSEC validator to validate the answer.
+                 */
+                FCTXTRACE("wait for validator");
+                fctx_cancelqueries(fctx, ISC_TRUE);
+                /*
+                 * We must not retransmit while the validator is working;
+                 * it has references to the current rmessage.
+                 */
+                result = fctx_stopidletimer(fctx);
+                if (result != ISC_R_SUCCESS)
+                        fctx_done(fctx, result);
+        } else if (result == DNS_R_CHASEDSSERVERS) {
+                unsigned int n;
+                add_bad(fctx, addrinfo, result);
+                fctx_cancelqueries(fctx, ISC_TRUE);
+                fctx_cleanupfinds(fctx);
+                fctx_cleanupforwaddrs(fctx);
+
+                n = dns_name_countlabels(&fctx->name);
+                dns_name_getlabelsequence(&fctx->name, 1, n - 1, &fctx->nsname);
+
+                FCTXTRACE("suspending DS lookup to find parent's NS records");
+
+                result = dns_resolver_createfetch(fctx->res, &fctx->nsname,
+                                                  dns_rdatatype_ns,
+                                                  NULL, NULL, NULL, 0, task,
+                                                  resume_dslookup, fctx,
+                                                  &fctx->nsrrset, NULL,
+                                                  &fctx->nsfetch);
+                if (result != ISC_R_SUCCESS)
+                        fctx_done(fctx, result);
+                LOCK(&fctx->res->buckets[fctx->bucketnum].lock);
+                fctx->references++;
+                UNLOCK(&fctx->res->buckets[fctx->bucketnum].lock);
+                result = fctx_stopidletimer(fctx);
+                if (result != ISC_R_SUCCESS)
+                        fctx_done(fctx, result);
+        } else {
+                /*
+                 * We're done.
+                 */
+                fctx_done(fctx, result);
+        }
 }
 
 
@@ -6084,1441 +6121,1514 @@ resquery_response(isc_task_t *task, isc_event_t *event) {
 
 static void
 destroy(dns_resolver_t *res) {
-       unsigned int i;
-       alternate_t *a;
-
-       REQUIRE(res->references == 0);
-       REQUIRE(!res->priming);
-       REQUIRE(res->primefetch == NULL);
-
-       RTRACE("destroy");
-
-       INSIST(res->nfctx == 0);
-
-       RES_DESTROYLOCK(&res->poollock);
-       DESTROYLOCK(&res->primelock);
-       DESTROYLOCK(&res->nlock);
-       DESTROYLOCK(&res->lock);
-       for (i = 0; i < res->nbuckets; i++) {
-               INSIST(ISC_LIST_EMPTY(res->buckets[i].fctxs));
-               isc_task_shutdown(res->buckets[i].task);
-               isc_task_detach(&res->buckets[i].task);
-               DESTROYLOCK(&res->buckets[i].lock);
-               isc_mem_detach(&res->buckets[i].mctx);
-       }
-       isc_mem_put(res->mctx, res->buckets,
-                   res->nbuckets * sizeof(fctxbucket_t));
-       if (res->dispatchv4 != NULL)
-               dns_dispatch_detach(&res->dispatchv4);
-       if (res->dispatchv6 != NULL)
-               dns_dispatch_detach(&res->dispatchv6);
-       if (res->dispatchv4pool != NULL) {
-               for (i = 0; i < res->ndisps; i++)
-                       dns_dispatch_detach(&res->dispatchv4pool[i]);
-               isc_mem_put(res->mctx, res->dispatchv4pool,
-                           res->ndisps * sizeof(dns_dispatch_t *));
-       }
-       if (res->dispatchv6pool != NULL) {
-               for (i = 0; i < res->ndisps; i++)
-                       dns_dispatch_detach(&res->dispatchv6pool[i]);
-               isc_mem_put(res->mctx, res->dispatchv6pool,
-                           res->ndisps * sizeof(dns_dispatch_t *));
-       }
-       while ((a = ISC_LIST_HEAD(res->alternates)) != NULL) {
-               ISC_LIST_UNLINK(res->alternates, a, link);
-               if (!a->isaddress)
-                       dns_name_free(&a->_u._n.name, res->mctx);
-               isc_mem_put(res->mctx, a, sizeof(*a));
-       }
-       if (res->disppooltimer != NULL)
-               isc_timer_detach(&res->disppooltimer);
-       dns_resolver_reset_algorithms(res);
-       dns_resolver_resetmustbesecure(res);
+        unsigned int i;
+        alternate_t *a;
+
+        REQUIRE(res->references == 0);
+        REQUIRE(!res->priming);
+        REQUIRE(res->primefetch == NULL);
+
+        RTRACE("destroy");
+
+        INSIST(res->nfctx == 0);
+
+#ifdef LRU_DEBUG
+        isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,
+                      DNS_LOGMODULE_RESOLVER, ISC_LOG_INFO,
+                      "destroying resolver %p: external queries "
+                      "total/NS/SOA/A/AAAA=%u/%u/%u/%u/%u",
+                      res, res->extqueries, res->extqueries_ns,
+                      res->extqueries_soa, res->extqueries_a,
+                      res->extqueries_aaaa);
+#endif
+
+        RES_DESTROYLOCK(&res->poollock);
+        DESTROYLOCK(&res->primelock);
+        DESTROYLOCK(&res->nlock);
+        DESTROYLOCK(&res->lock);
+        for (i = 0; i < res->nbuckets; i++) {
+                INSIST(ISC_LIST_EMPTY(res->buckets[i].fctxs));
+                isc_task_shutdown(res->buckets[i].task);
+                isc_task_detach(&res->buckets[i].task);
+                DESTROYLOCK(&res->buckets[i].lock);
+                isc_mem_detach(&res->buckets[i].mctx);
+        }
+        isc_mem_put(res->mctx, res->buckets,
+                    res->nbuckets * sizeof(fctxbucket_t));
+        if (res->dispatchv4 != NULL)
+                dns_dispatch_detach(&res->dispatchv4);
+        if (res->dispatchv6 != NULL)
+                dns_dispatch_detach(&res->dispatchv6);
+        if (res->dispatchv4pool != NULL) {
+                for (i = 0; i < res->ndisps; i++)
+                        dns_dispatch_detach(&res->dispatchv4pool[i]);
+                isc_mem_put(res->mctx, res->dispatchv4pool,
+                            res->ndisps * sizeof(dns_dispatch_t *));
+        }
+        if (res->dispatchv6pool != NULL) {
+                for (i = 0; i < res->ndisps; i++)
+                        dns_dispatch_detach(&res->dispatchv6pool[i]);
+                isc_mem_put(res->mctx, res->dispatchv6pool,
+                            res->ndisps * sizeof(dns_dispatch_t *));
+        }
+        while ((a = ISC_LIST_HEAD(res->alternates)) != NULL) {
+                ISC_LIST_UNLINK(res->alternates, a, link);
+                if (!a->isaddress)
+                        dns_name_free(&a->_u._n.name, res->mctx);
+                isc_mem_put(res->mctx, a, sizeof(*a));
+        }
+        if (res->disppooltimer != NULL)
+                isc_timer_detach(&res->disppooltimer);
+#ifdef LRU_DEBUG
+        if (res->dumptimer != NULL)
+                isc_timer_detach(&res->dumptimer);
+#endif
+        dns_resolver_reset_algorithms(res);
+        dns_resolver_resetmustbesecure(res);
 #if USE_ALGLOCK
-       isc_rwlock_destroy(&res->alglock);
+        isc_rwlock_destroy(&res->alglock);
 #endif
 #if USE_MBSLOCK
-       isc_rwlock_destroy(&res->mbslock);
+        isc_rwlock_destroy(&res->mbslock);
 #endif
-       isc_timer_detach(&res->spillattimer);
-       res->magic = 0;
-       isc_mem_put(res->mctx, res, sizeof(*res));
+        isc_timer_detach(&res->spillattimer);
+        res->magic = 0;
+        isc_mem_put(res->mctx, res, sizeof(*res));
 }
 
 static void
 send_shutdown_events(dns_resolver_t *res) {
-       isc_event_t *event, *next_event;
-       isc_task_t *etask;
-
-       /*
-        * Caller must be holding the resolver lock.
-        */
-
-       for (event = ISC_LIST_HEAD(res->whenshutdown);
-            event != NULL;
-            event = next_event) {
-               next_event = ISC_LIST_NEXT(event, ev_link);
-               ISC_LIST_UNLINK(res->whenshutdown, event, ev_link);
-               etask = event->ev_sender;
-               event->ev_sender = res;
-               isc_task_sendanddetach(&etask, &event);
-       }
+        isc_event_t *event, *next_event;
+        isc_task_t *etask;
+
+        /*
+         * Caller must be holding the resolver lock.
+         */
+
+        for (event = ISC_LIST_HEAD(res->whenshutdown);
+             event != NULL;
+             event = next_event) {
+                next_event = ISC_LIST_NEXT(event, ev_link);
+                ISC_LIST_UNLINK(res->whenshutdown, event, ev_link);
+                etask = event->ev_sender;
+                event->ev_sender = res;
+                isc_task_sendanddetach(&etask, &event);
+        }
 }
 
 static void
 empty_bucket(dns_resolver_t *res) {
-       RTRACE("empty_bucket");
+        RTRACE("empty_bucket");
 
-       LOCK(&res->lock);
+        LOCK(&res->lock);
 
-       INSIST(res->activebuckets > 0);
-       res->activebuckets--;
-       if (res->activebuckets == 0)
-               send_shutdown_events(res);
+        INSIST(res->activebuckets > 0);
+        res->activebuckets--;
+        if (res->activebuckets == 0)
+                send_shutdown_events(res);
 
-       UNLOCK(&res->lock);
+        UNLOCK(&res->lock);
 }
 
 static void
 spillattimer_countdown(isc_task_t *task, isc_event_t *event) {
-       dns_resolver_t *res = event->ev_arg;
-       isc_result_t result;
-       unsigned int count;
-       isc_boolean_t logit = ISC_FALSE;
-
-       REQUIRE(VALID_RESOLVER(res));
-
-       UNUSED(task);
-       
-       LOCK(&res->lock);
-       INSIST(!res->exiting);
-       if (res->spillat > res->spillatmin) {
-               res->spillat--;
-               logit = ISC_TRUE;
-       }
-       if (res->spillat <= res->spillatmin) {
-               result = isc_timer_reset(res->spillattimer,
-                                        isc_timertype_inactive, NULL,
-                                        NULL, ISC_TRUE);
-               RUNTIME_CHECK(result == ISC_R_SUCCESS);
-       }
-       count = res->spillat;
-       UNLOCK(&res->lock);
-       if (logit)
-               isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,
-                             DNS_LOGMODULE_RESOLVER, ISC_LOG_NOTICE,
-                             "clients-per-query decreased to %u", count);
-
-       isc_event_free(&event);
+        dns_resolver_t *res = event->ev_arg;
+        isc_result_t result;
+        unsigned int count;
+        isc_boolean_t logit = ISC_FALSE;
+
+        REQUIRE(VALID_RESOLVER(res));
+
+        UNUSED(task);
+
+        LOCK(&res->lock);
+        INSIST(!res->exiting);
+        if (res->spillat > res->spillatmin) {
+                res->spillat--;
+                logit = ISC_TRUE;
+        }
+        if (res->spillat <= res->spillatmin) {
+                result = isc_timer_reset(res->spillattimer,
+                                         isc_timertype_inactive, NULL,
+                                         NULL, ISC_TRUE);
+                RUNTIME_CHECK(result == ISC_R_SUCCESS);
+        }
+        count = res->spillat;
+        UNLOCK(&res->lock);
+        if (logit)
+                isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,
+                              DNS_LOGMODULE_RESOLVER, ISC_LOG_NOTICE,
+                              "clients-per-query decreased to %u", count);
+
+        isc_event_free(&event);
 }
 
 isc_result_t
 dns_resolver_create(dns_view_t *view,
-                   isc_taskmgr_t *taskmgr, unsigned int ntasks,
-                   isc_socketmgr_t *socketmgr,
-                   isc_timermgr_t *timermgr, 
-                   unsigned int options,
-                   dns_dispatchmgr_t *dispatchmgr,
-                   dns_dispatch_t *dispatchv4,
-                   dns_dispatch_t *dispatchv6,
-                   dns_resolver_t **resp)
+                    isc_taskmgr_t *taskmgr, unsigned int ntasks,
+                    isc_socketmgr_t *socketmgr,
+                    isc_timermgr_t *timermgr,
+                    unsigned int options,
+                    dns_dispatchmgr_t *dispatchmgr,
+                    dns_dispatch_t *dispatchv4,
+                    dns_dispatch_t *dispatchv6,
+                    dns_resolver_t **resp)
 {
-       dns_resolver_t *res;
-       isc_result_t result = ISC_R_SUCCESS;
-       unsigned int i, buckets_created = 0;
-       isc_task_t *task = NULL;
-       char name[16];
-
-       /*
-        * Create a resolver.
-        */
-
-       REQUIRE(DNS_VIEW_VALID(view));
-       REQUIRE(ntasks > 0);
-       REQUIRE(resp != NULL && *resp == NULL);
-       REQUIRE(dispatchmgr != NULL);
-       REQUIRE(dispatchv4 != NULL || dispatchv6 != NULL);
-
-       res = isc_mem_get(view->mctx, sizeof(*res));
-       if (res == NULL)
-               return (ISC_R_NOMEMORY);
-       RTRACE("create");
-       res->mctx = view->mctx;
-       res->rdclass = view->rdclass;
-       res->socketmgr = socketmgr;
-       res->timermgr = timermgr;
-       res->taskmgr = taskmgr;
-       res->dispatchmgr = dispatchmgr;
-       res->view = view;
-       res->options = options;
-       res->lame_ttl = 0;
-       ISC_LIST_INIT(res->alternates);
-       res->udpsize = RECV_BUFFER_SIZE;
-       res->algorithms = NULL;
-       res->mustbesecure = NULL;
-       res->spillatmin = res->spillat = 10;
-       res->spillatmax = 100;
-       res->spillattimer = NULL;
-       res->zero_no_soa_ttl = ISC_FALSE;
-       res->ndisps = 0;
-       res->nextdisp = 0; /* meaningless at this point, but init it */
-       res->dispatchv4pool = NULL;
-       res->dispatchv6pool = NULL;
-       res->disppooltimer = NULL;
-
-       res->nbuckets = ntasks;
-       res->activebuckets = ntasks;
-       res->buckets = isc_mem_get(view->mctx,
-                                  ntasks * sizeof(fctxbucket_t));
-       if (res->buckets == NULL) {
-               result = ISC_R_NOMEMORY;
-               goto cleanup_res;
-       }
-       for (i = 0; i < ntasks; i++) {
-               result = isc_mutex_init(&res->buckets[i].lock);
-               if (result != ISC_R_SUCCESS)
-                       goto cleanup_buckets;
-               res->buckets[i].task = NULL;
-               result = isc_task_create(taskmgr, 0, &res->buckets[i].task);
-               if (result != ISC_R_SUCCESS) {
-                       DESTROYLOCK(&res->buckets[i].lock);
-                       goto cleanup_buckets;
-               }
-               res->buckets[i].mctx = NULL;
-               result = isc_mem_create(0, 0, &res->buckets[i].mctx);
-               if (result != ISC_R_SUCCESS) {
-                       isc_task_detach(&res->buckets[i].task);
-                       DESTROYLOCK(&res->buckets[i].lock);
-                       goto cleanup_buckets;
-               }
-               snprintf(name, sizeof(name), "res%u", i);
-               isc_task_setname(res->buckets[i].task, name, res);
-               ISC_LIST_INIT(res->buckets[i].fctxs);
-               res->buckets[i].exiting = ISC_FALSE;
-               buckets_created++;
-       }
-
-       res->dispatchv4 = NULL;
-       if (dispatchv4 != NULL)
-                       dns_dispatch_attach(dispatchv4, &res->dispatchv4);
-
-       res->dispatchv6 = NULL;
-       if (dispatchv6 != NULL)
-               dns_dispatch_attach(dispatchv6, &res->dispatchv6);
-
-       res->references = 1;
-       res->exiting = ISC_FALSE;
-       res->frozen = ISC_FALSE;
-       ISC_LIST_INIT(res->whenshutdown);
-       res->priming = ISC_FALSE;
-       res->primefetch = NULL;
-       res->nfctx = 0;
-
-       result = isc_mutex_init(&res->lock);
-       if (result != ISC_R_SUCCESS)
-               goto cleanup_dispatches;
-
-       result = isc_mutex_init(&res->nlock);
-       if (result != ISC_R_SUCCESS)
-               goto cleanup_lock;
-
-       result = isc_mutex_init(&res->primelock);
-       if (result != ISC_R_SUCCESS)
-               goto cleanup_nlock;
-
-       result = RES_INITLOCK(&res->poollock);
-       if (result != ISC_R_SUCCESS)
-               goto cleanup_primelock;
-
-       task = NULL;
-       result = isc_task_create(taskmgr, 0, &task);
-       if (result != ISC_R_SUCCESS)
-               goto cleanup_poollock;
-
-       result = isc_timer_create(timermgr, isc_timertype_inactive, NULL, NULL,
-                                 task, spillattimer_countdown, res,
-                                 &res->spillattimer);
-       isc_task_detach(&task);
-       if (result != ISC_R_SUCCESS)
-               goto cleanup_poollock;
+        dns_resolver_t *res;
+        isc_result_t result = ISC_R_SUCCESS;
+        unsigned int i, buckets_created = 0;
+        isc_task_t *task = NULL;
+        char name[16];
+
+        /*
+         * Create a resolver.
+         */
+
+        REQUIRE(DNS_VIEW_VALID(view));
+        REQUIRE(ntasks > 0);
+        REQUIRE(resp != NULL && *resp == NULL);
+        REQUIRE(dispatchmgr != NULL);
+        REQUIRE(dispatchv4 != NULL || dispatchv6 != NULL);
+
+        res = isc_mem_get(view->mctx, sizeof(*res));
+        if (res == NULL)
+                return (ISC_R_NOMEMORY);
+        RTRACE("create");
+        res->mctx = view->mctx;
+        res->rdclass = view->rdclass;
+        res->socketmgr = socketmgr;
+        res->timermgr = timermgr;
+        res->taskmgr = taskmgr;
+        res->dispatchmgr = dispatchmgr;
+        res->view = view;
+        res->options = options;
+        res->lame_ttl = 0;
+        ISC_LIST_INIT(res->alternates);
+        res->udpsize = RECV_BUFFER_SIZE;
+        res->algorithms = NULL;
+        res->mustbesecure = NULL;
+        res->spillatmin = res->spillat = 10;
+        res->spillatmax = 100;
+        res->spillattimer = NULL;
+        res->zero_no_soa_ttl = ISC_FALSE;
+        res->ndisps = 0;
+        res->nextdisp = 0; /* meaningless at this point, but init it */
+        res->dispatchv4pool = NULL;
+        res->dispatchv6pool = NULL;
+        res->disppooltimer = NULL;
+#ifdef LRU_DEBUG
+        res->dumptimer = NULL;
+        res->extqueries = 0;
+        res->extqueries_ns = 0;
+        res->extqueries_soa = 0;
+        res->extqueries_a = 0;
+        res->extqueries_aaaa = 0;
+#endif
+
+        res->nbuckets = ntasks;
+        res->activebuckets = ntasks;
+        res->buckets = isc_mem_get(view->mctx,
+                                   ntasks * sizeof(fctxbucket_t));
+        if (res->buckets == NULL) {
+                result = ISC_R_NOMEMORY;
+                goto cleanup_res;
+        }
+        for (i = 0; i < ntasks; i++) {
+                result = isc_mutex_init(&res->buckets[i].lock);
+                if (result != ISC_R_SUCCESS)
+                        goto cleanup_buckets;
+                res->buckets[i].task = NULL;
+                result = isc_task_create(taskmgr, 0, &res->buckets[i].task);
+                if (result != ISC_R_SUCCESS) {
+                        DESTROYLOCK(&res->buckets[i].lock);
+                        goto cleanup_buckets;
+                }
+                res->buckets[i].mctx = NULL;
+                result = isc_mem_create(0, 0, &res->buckets[i].mctx);
+                if (result != ISC_R_SUCCESS) {
+                        isc_task_detach(&res->buckets[i].task);
+                        DESTROYLOCK(&res->buckets[i].lock);
+                        goto cleanup_buckets;
+                }
+                snprintf(name, sizeof(name), "res%u", i);
+                isc_task_setname(res->buckets[i].task, name, res);
+                ISC_LIST_INIT(res->buckets[i].fctxs);
+                res->buckets[i].exiting = ISC_FALSE;
+                buckets_created++;
+        }
+
+        res->dispatchv4 = NULL;
+        if (dispatchv4 != NULL)
+                        dns_dispatch_attach(dispatchv4, &res->dispatchv4);
+
+        res->dispatchv6 = NULL;
+        if (dispatchv6 != NULL)
+                dns_dispatch_attach(dispatchv6, &res->dispatchv6);
+
+        res->references = 1;
+        res->exiting = ISC_FALSE;
+        res->frozen = ISC_FALSE;
+        ISC_LIST_INIT(res->whenshutdown);
+        res->priming = ISC_FALSE;
+        res->primefetch = NULL;
+        res->nfctx = 0;
+
+        result = isc_mutex_init(&res->lock);
+        if (result != ISC_R_SUCCESS)
+                goto cleanup_dispatches;
+
+        result = isc_mutex_init(&res->nlock);
+        if (result != ISC_R_SUCCESS)
+                goto cleanup_lock;
+
+        result = isc_mutex_init(&res->primelock);
+        if (result != ISC_R_SUCCESS)
+                goto cleanup_nlock;
+
+        result = RES_INITLOCK(&res->poollock);
+        if (result != ISC_R_SUCCESS)
+                goto cleanup_primelock;
+
+        task = NULL;
+        result = isc_task_create(taskmgr, 0, &task);
+        if (result != ISC_R_SUCCESS)
+                goto cleanup_poollock;
+
+        result = isc_timer_create(timermgr, isc_timertype_inactive, NULL, NULL,
+                                  task, spillattimer_countdown, res,
+                                  &res->spillattimer);
+
+#ifdef LRU_DEBUG
+        {
+                isc_interval_t interval;
+
+                interval.seconds = DUMP_INTERVAL;
+                interval.nanoseconds = 0;
+                RUNTIME_CHECK(isc_time_nowplusinterval(&res->dump_time,
+                                                       &interval) ==
+                              ISC_R_SUCCESS);
+
+                result = isc_timer_create(timermgr, isc_timertype_once,
+                                          &res->dump_time, NULL, task,
+                                          timer_dump, res, &res->dumptimer);
+        }
+#endif
+        isc_task_detach(&task);
+        if (result != ISC_R_SUCCESS)
+                goto cleanup_poollock;
 
 #if USE_ALGLOCK
-       result = isc_rwlock_init(&res->alglock, 0, 0);
-       if (result != ISC_R_SUCCESS)
-               goto cleanup_spillattimer;
+        result = isc_rwlock_init(&res->alglock, 0, 0);
+        if (result != ISC_R_SUCCESS)
+                goto cleanup_spillattimer;
 #endif
 #if USE_MBSLOCK
-       result = isc_rwlock_init(&res->mbslock, 0, 0);
-       if (result != ISC_R_SUCCESS)
-               goto cleanup_alglock;
+        result = isc_rwlock_init(&res->mbslock, 0, 0);
+        if (result != ISC_R_SUCCESS)
+                goto cleanup_alglock;
 #endif
 
-       res->magic = RES_MAGIC;
+        res->magic = RES_MAGIC;
 
-       *resp = res;
+        *resp = res;
 
-       return (ISC_R_SUCCESS);
+        return (ISC_R_SUCCESS);
 
 #if USE_MBSLOCK
  cleanup_alglock:
 #if USE_ALGLOCK
-       isc_rwlock_destroy(&res->alglock);
+        isc_rwlock_destroy(&res->alglock);
 #endif
 #endif
 #if USE_ALGLOCK || USE_MBSLOCK
  cleanup_spillattimer:
-       isc_timer_detach(&res->spillattimer);
+        isc_timer_detach(&res->spillattimer);
 #endif
 
  cleanup_poollock:
-       RES_DESTROYLOCK(&res->poollock);
+        RES_DESTROYLOCK(&res->poollock);
 
  cleanup_primelock:
-       DESTROYLOCK(&res->primelock);
+        DESTROYLOCK(&res->primelock);
 
  cleanup_nlock:
-       DESTROYLOCK(&res->nlock);
+        DESTROYLOCK(&res->nlock);
 
  cleanup_lock:
-       DESTROYLOCK(&res->lock);
+        DESTROYLOCK(&res->lock);
 
  cleanup_dispatches:
-       if (res->dispatchv6 != NULL)
-               dns_dispatch_detach(&res->dispatchv6);
-       if (res->dispatchv4 != NULL)
-               dns_dispatch_detach(&res->dispatchv4);
+        if (res->dispatchv6 != NULL)
+                dns_dispatch_detach(&res->dispatchv6);
+        if (res->dispatchv4 != NULL)
+                dns_dispatch_detach(&res->dispatchv4);
 
  cleanup_buckets:
-       for (i = 0; i < buckets_created; i++) {
-               isc_mem_detach(&res->buckets[i].mctx);
-               DESTROYLOCK(&res->buckets[i].lock);
-               isc_task_shutdown(res->buckets[i].task);
-               isc_task_detach(&res->buckets[i].task);
-       }
-       isc_mem_put(view->mctx, res->buckets,
-                   res->nbuckets * sizeof(fctxbucket_t));
+        for (i = 0; i < buckets_created; i++) {
+                isc_mem_detach(&res->buckets[i].mctx);
+                DESTROYLOCK(&res->buckets[i].lock);
+                isc_task_shutdown(res->buckets[i].task);
+                isc_task_detach(&res->buckets[i].task);
+        }
+        isc_mem_put(view->mctx, res->buckets,
+                    res->nbuckets * sizeof(fctxbucket_t));
 
  cleanup_res:
-       isc_mem_put(view->mctx, res, sizeof(*res));
+        isc_mem_put(view->mctx, res, sizeof(*res));
 
-       return (result);
+        return (result);
 }
 
 static void
 prime_done(isc_task_t *task, isc_event_t *event) {
-       dns_resolver_t *res;
-       dns_fetchevent_t *fevent;
-       dns_fetch_t *fetch;
-       dns_db_t *db = NULL;
-
-       REQUIRE(event->ev_type == DNS_EVENT_FETCHDONE);
-       fevent = (dns_fetchevent_t *)event;
-       res = event->ev_arg;
-       REQUIRE(VALID_RESOLVER(res));
-
-       UNUSED(task);
-
-       LOCK(&res->lock);
-
-       INSIST(res->priming);
-       res->priming = ISC_FALSE;
-       LOCK(&res->primelock);
-       fetch = res->primefetch;
-       res->primefetch = NULL;
-       UNLOCK(&res->primelock);
-
-       UNLOCK(&res->lock);
-       
-       if (fevent->result == ISC_R_SUCCESS &&
-           res->view->cache != NULL && res->view->hints != NULL) {
-               dns_cache_attachdb(res->view->cache, &db);
-               dns_root_checkhints(res->view, res->view->hints, db);
-               dns_db_detach(&db);
-       }
-
-       if (fevent->node != NULL)
-               dns_db_detachnode(fevent->db, &fevent->node);
-       if (fevent->db != NULL)
-               dns_db_detach(&fevent->db);
-       if (dns_rdataset_isassociated(fevent->rdataset))
-               dns_rdataset_disassociate(fevent->rdataset);
-       INSIST(fevent->sigrdataset == NULL);
-
-       isc_mem_put(res->mctx, fevent->rdataset, sizeof(*fevent->rdataset));
-
-       isc_event_free(&event);
-       dns_resolver_destroyfetch(&fetch);
+        dns_resolver_t *res;
+        dns_fetchevent_t *fevent;
+        dns_fetch_t *fetch;
+        dns_db_t *db = NULL;
+
+        REQUIRE(event->ev_type == DNS_EVENT_FETCHDONE);
+        fevent = (dns_fetchevent_t *)event;
+        res = event->ev_arg;
+        REQUIRE(VALID_RESOLVER(res));
+
+        UNUSED(task);
+
+        LOCK(&res->lock);
+
+        INSIST(res->priming);
+        res->priming = ISC_FALSE;
+        LOCK(&res->primelock);
+        fetch = res->primefetch;
+        res->primefetch = NULL;
+        UNLOCK(&res->primelock);
+
+        UNLOCK(&res->lock);
+
+        if (fevent->result == ISC_R_SUCCESS &&
+            res->view->cache != NULL && res->view->hints != NULL) {
+                dns_cache_attachdb(res->view->cache, &db);
+                dns_root_checkhints(res->view, res->view->hints, db);
+                dns_db_detach(&db);
+        }
+
+        if (fevent->node != NULL)
+                dns_db_detachnode(fevent->db, &fevent->node);
+        if (fevent->db != NULL)
+                dns_db_detach(&fevent->db);
+        if (dns_rdataset_isassociated(fevent->rdataset))
+                dns_rdataset_disassociate(fevent->rdataset);
+        INSIST(fevent->sigrdataset == NULL);
+
+        isc_mem_put(res->mctx, fevent->rdataset, sizeof(*fevent->rdataset));
+
+        isc_event_free(&event);
+        dns_resolver_destroyfetch(&fetch);
 }
 
 void
 dns_resolver_prime(dns_resolver_t *res) {
-       isc_boolean_t want_priming = ISC_FALSE;
-       dns_rdataset_t *rdataset;
-       isc_result_t result;
-
-       REQUIRE(VALID_RESOLVER(res));
-       REQUIRE(res->frozen);
-
-       RTRACE("dns_resolver_prime");
-
-       LOCK(&res->lock);
-
-       if (!res->exiting && !res->priming) {
-               INSIST(res->primefetch == NULL);
-               res->priming = ISC_TRUE;
-               want_priming = ISC_TRUE;
-       }
-
-       UNLOCK(&res->lock);
-
-       if (want_priming) {
-               /*
-                * To avoid any possible recursive locking problems, we
-                * start the priming fetch like any other fetch, and holding
-                * no resolver locks.  No one else will try to start it
-                * because we're the ones who set res->priming to true.
-                * Any other callers of dns_resolver_prime() while we're
-                * running will see that res->priming is already true and
-                * do nothing.
-                */
-               RTRACE("priming");
-               rdataset = isc_mem_get(res->mctx, sizeof(*rdataset));
-               if (rdataset == NULL) {
-                       LOCK(&res->lock);
-                       INSIST(res->priming);
-                       INSIST(res->primefetch == NULL);
-                       res->priming = ISC_FALSE;
-                       UNLOCK(&res->lock);
-                       return;
-               }
-               dns_rdataset_init(rdataset);
-               LOCK(&res->primelock);
-               result = dns_resolver_createfetch(res, dns_rootname,
-                                                 dns_rdatatype_ns,
-                                                 NULL, NULL, NULL, 0,
-                                                 res->buckets[0].task,
-                                                 prime_done,
-                                                 res, rdataset, NULL,
-                                                 &res->primefetch);
-               UNLOCK(&res->primelock);
-               if (result != ISC_R_SUCCESS) {
-                       LOCK(&res->lock);
-                       INSIST(res->priming);
-                       res->priming = ISC_FALSE;
-                       UNLOCK(&res->lock);
-               }
-       }
+        isc_boolean_t want_priming = ISC_FALSE;
+        dns_rdataset_t *rdataset;
+        isc_result_t result;
+
+        REQUIRE(VALID_RESOLVER(res));
+        REQUIRE(res->frozen);
+
+        RTRACE("dns_resolver_prime");
+
+        LOCK(&res->lock);
+
+        if (!res->exiting && !res->priming) {
+                INSIST(res->primefetch == NULL);
+                res->priming = ISC_TRUE;
+                want_priming = ISC_TRUE;
+        }
+
+        UNLOCK(&res->lock);
+
+        if (want_priming) {
+                /*
+                 * To avoid any possible recursive locking problems, we
+                 * start the priming fetch like any other fetch, and holding
+                 * no resolver locks.  No one else will try to start it
+                 * because we're the ones who set res->priming to true.
+                 * Any other callers of dns_resolver_prime() while we're
+                 * running will see that res->priming is already true and
+                 * do nothing.
+                 */
+                RTRACE("priming");
+                rdataset = isc_mem_get(res->mctx, sizeof(*rdataset));
+                if (rdataset == NULL) {
+                        LOCK(&res->lock);
+                        INSIST(res->priming);
+                        INSIST(res->primefetch == NULL);
+                        res->priming = ISC_FALSE;
+                        UNLOCK(&res->lock);
+                        return;
+                }
+                dns_rdataset_init(rdataset);
+                LOCK(&res->primelock);
+                result = dns_resolver_createfetch(res, dns_rootname,
+                                                  dns_rdatatype_ns,
+                                                  NULL, NULL, NULL, 0,
+                                                  res->buckets[0].task,
+                                                  prime_done,
+                                                  res, rdataset, NULL,
+                                                  &res->primefetch);
+                UNLOCK(&res->primelock);
+                if (result != ISC_R_SUCCESS) {
+                        LOCK(&res->lock);
+                        INSIST(res->priming);
+                        res->priming = ISC_FALSE;
+                        UNLOCK(&res->lock);
+                }
+        }
 }
 
 void
 dns_resolver_freeze(dns_resolver_t *res) {
 
-       /*
-        * Freeze resolver.
-        */
+        /*
+         * Freeze resolver.
+         */
 
-       REQUIRE(VALID_RESOLVER(res));
-       REQUIRE(!res->frozen);
+        REQUIRE(VALID_RESOLVER(res));
+        REQUIRE(!res->frozen);
 
-       res->frozen = ISC_TRUE;
+        res->frozen = ISC_TRUE;
 }
 
 void
 dns_resolver_attach(dns_resolver_t *source, dns_resolver_t **targetp) {
-       REQUIRE(VALID_RESOLVER(source));
-       REQUIRE(targetp != NULL && *targetp == NULL);
+        REQUIRE(VALID_RESOLVER(source));
+        REQUIRE(targetp != NULL && *targetp == NULL);
 
-       RRTRACE(source, "attach");
-       LOCK(&source->lock);
-       REQUIRE(!source->exiting);
+        RRTRACE(source, "attach");
+        LOCK(&source->lock);
+        REQUIRE(!source->exiting);
 
-       INSIST(source->references > 0);
-       source->references++;
-       INSIST(source->references != 0);
-       UNLOCK(&source->lock);
+        INSIST(source->references > 0);
+        source->references++;
+        INSIST(source->references != 0);
+        UNLOCK(&source->lock);
 
-       *targetp = source;
+        *targetp = source;
 }
 
 void
 dns_resolver_whenshutdown(dns_resolver_t *res, isc_task_t *task,
-                         isc_event_t **eventp)
+                          isc_event_t **eventp)
 {
-       isc_task_t *clone;
-       isc_event_t *event;
-
-       REQUIRE(VALID_RESOLVER(res));
-       REQUIRE(eventp != NULL);
-
-       event = *eventp;
-       *eventp = NULL;
-
-       LOCK(&res->lock);
-
-       if (res->exiting && res->activebuckets == 0) {
-               /*
-                * We're already shutdown.  Send the event.
-                */
-               event->ev_sender = res;
-               isc_task_send(task, &event);
-       } else {
-               clone = NULL;
-               isc_task_attach(task, &clone);
-               event->ev_sender = clone;
-               ISC_LIST_APPEND(res->whenshutdown, event, ev_link);
-       }
-
-       UNLOCK(&res->lock);
+        isc_task_t *clone;
+        isc_event_t *event;
+
+        REQUIRE(VALID_RESOLVER(res));
+        REQUIRE(eventp != NULL);
+
+        event = *eventp;
+        *eventp = NULL;
+
+        LOCK(&res->lock);
+
+        if (res->exiting && res->activebuckets == 0) {
+                /*
+                 * We're already shutdown.  Send the event.
+                 */
+                event->ev_sender = res;
+                isc_task_send(task, &event);
+        } else {
+                clone = NULL;
+                isc_task_attach(task, &clone);
+                event->ev_sender = clone;
+                ISC_LIST_APPEND(res->whenshutdown, event, ev_link);
+        }
+
+        UNLOCK(&res->lock);
 }
 
 void
 dns_resolver_shutdown(dns_resolver_t *res) {
-       unsigned int i;
-       fetchctx_t *fctx;
-       isc_socket_t *sock;
-       isc_result_t result;
-
-       REQUIRE(VALID_RESOLVER(res));
-
-       RTRACE("shutdown");
-
-       LOCK(&res->lock);
-
-       if (!res->exiting) {
-               RTRACE("exiting");
-               res->exiting = ISC_TRUE;
-
-               for (i = 0; i < res->nbuckets; i++) {
-                       LOCK(&res->buckets[i].lock);
-                       for (fctx = ISC_LIST_HEAD(res->buckets[i].fctxs);
-                            fctx != NULL;
-                            fctx = ISC_LIST_NEXT(fctx, link))
-                               fctx_shutdown(fctx);
-                       if (res->dispatchv4 != NULL) {
-                               sock = dns_dispatch_getsocket(res->dispatchv4);
-                               isc_socket_cancel(sock, res->buckets[i].task,
-                                                 ISC_SOCKCANCEL_ALL);
-                       }
-                       if (res->dispatchv6 != NULL) {
-                               sock = dns_dispatch_getsocket(res->dispatchv6);
-                               isc_socket_cancel(sock, res->buckets[i].task,
-                                                 ISC_SOCKCANCEL_ALL);
-                       }
-                       res->buckets[i].exiting = ISC_TRUE;
-                       if (ISC_LIST_EMPTY(res->buckets[i].fctxs)) {
-                               INSIST(res->activebuckets > 0);
-                               res->activebuckets--;
-                       }
-                       UNLOCK(&res->buckets[i].lock);
-               }
-               if (res->activebuckets == 0)
-                       send_shutdown_events(res);
-               result = isc_timer_reset(res->spillattimer,
-                                        isc_timertype_inactive, NULL,
-                                        NULL, ISC_TRUE);
-               RUNTIME_CHECK(result == ISC_R_SUCCESS);
-       }
-
-       UNLOCK(&res->lock);
+        unsigned int i;
+        fetchctx_t *fctx;
+        isc_socket_t *sock;
+        isc_result_t result;
+
+        REQUIRE(VALID_RESOLVER(res));
+
+        RTRACE("shutdown");
+
+        LOCK(&res->lock);
+
+        if (!res->exiting) {
+                RTRACE("exiting");
+                res->exiting = ISC_TRUE;
+
+                for (i = 0; i < res->nbuckets; i++) {
+                        LOCK(&res->buckets[i].lock);
+                        for (fctx = ISC_LIST_HEAD(res->buckets[i].fctxs);
+                             fctx != NULL;
+                             fctx = ISC_LIST_NEXT(fctx, link))
+                                fctx_shutdown(fctx);
+                        if (res->dispatchv4 != NULL) {
+                                sock = dns_dispatch_getsocket(res->dispatchv4);
+                                isc_socket_cancel(sock, res->buckets[i].task,
+                                                  ISC_SOCKCANCEL_ALL);
+                        }
+                        if (res->dispatchv6 != NULL) {
+                                sock = dns_dispatch_getsocket(res->dispatchv6);
+                                isc_socket_cancel(sock, res->buckets[i].task,
+                                                  ISC_SOCKCANCEL_ALL);
+                        }
+                        res->buckets[i].exiting = ISC_TRUE;
+                        if (ISC_LIST_EMPTY(res->buckets[i].fctxs)) {
+                                INSIST(res->activebuckets > 0);
+                                res->activebuckets--;
+                        }
+                        UNLOCK(&res->buckets[i].lock);
+                }
+                if (res->activebuckets == 0)
+                        send_shutdown_events(res);
+                result = isc_timer_reset(res->spillattimer,
+                                         isc_timertype_inactive, NULL,
+                                         NULL, ISC_TRUE);
+                RUNTIME_CHECK(result == ISC_R_SUCCESS);
+        }
+
+        UNLOCK(&res->lock);
 }
 
 void
 dns_resolver_detach(dns_resolver_t **resp) {
-       dns_resolver_t *res;
-       isc_boolean_t need_destroy = ISC_FALSE;
+        dns_resolver_t *res;
+        isc_boolean_t need_destroy = ISC_FALSE;
 
-       REQUIRE(resp != NULL);
-       res = *resp;
-       REQUIRE(VALID_RESOLVER(res));
+        REQUIRE(resp != NULL);
+        res = *resp;
+        REQUIRE(VALID_RESOLVER(res));
 
-       RTRACE("detach");
+        RTRACE("detach");
 
-       LOCK(&res->lock);
+        LOCK(&res->lock);
 
-       INSIST(res->references > 0);
-       res->references--;
-       if (res->references == 0) {
-               INSIST(res->exiting && res->activebuckets == 0);
-               need_destroy = ISC_TRUE;
-       }
+        INSIST(res->references > 0);
+        res->references--;
+        if (res->references == 0) {
+                INSIST(res->exiting && res->activebuckets == 0);
+                need_destroy = ISC_TRUE;
+        }
 
-       UNLOCK(&res->lock);
+        UNLOCK(&res->lock);
 
-       if (need_destroy)
-               destroy(res);
+        if (need_destroy)
+                destroy(res);
 
-       *resp = NULL;
+        *resp = NULL;
 }
 
 static inline isc_boolean_t
 fctx_match(fetchctx_t *fctx, dns_name_t *name, dns_rdatatype_t type,
-          unsigned int options)
+           unsigned int options)
 {
-       if (fctx->type != type || fctx->options != options)
-               return (ISC_FALSE);
-       return (dns_name_equal(&fctx->name, name));
+        if (fctx->type != type || fctx->options != options)
+                return (ISC_FALSE);
+        return (dns_name_equal(&fctx->name, name));
 }
 
 static inline void
 log_fetch(dns_name_t *name, dns_rdatatype_t type) {
-       char namebuf[DNS_NAME_FORMATSIZE];
-       char typebuf[DNS_RDATATYPE_FORMATSIZE];
-       int level = ISC_LOG_DEBUG(1);
+        char namebuf[DNS_NAME_FORMATSIZE];
+        char typebuf[DNS_RDATATYPE_FORMATSIZE];
+        int level = ISC_LOG_DEBUG(1);
 
-       if (! isc_log_wouldlog(dns_lctx, level))
-               return;
+        if (! isc_log_wouldlog(dns_lctx, level))
+                return;
 
-       dns_name_format(name, namebuf, sizeof(namebuf));
-       dns_rdatatype_format(type, typebuf, sizeof(typebuf));
+        dns_name_format(name, namebuf, sizeof(namebuf));
+        dns_rdatatype_format(type, typebuf, sizeof(typebuf));
 
-       isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,
-                     DNS_LOGMODULE_RESOLVER, level,
-                     "createfetch: %s %s", namebuf, typebuf);
+        isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,
+                      DNS_LOGMODULE_RESOLVER, level,
+                      "createfetch: %s %s", namebuf, typebuf);
 }
 
 isc_result_t
 dns_resolver_createfetch(dns_resolver_t *res, dns_name_t *name,
-                        dns_rdatatype_t type,
-                        dns_name_t *domain, dns_rdataset_t *nameservers,
-                        dns_forwarders_t *forwarders,
-                        unsigned int options, isc_task_t *task,
-                        isc_taskaction_t action, void *arg,
-                        dns_rdataset_t *rdataset,
-                        dns_rdataset_t *sigrdataset,
-                        dns_fetch_t **fetchp)
+                         dns_rdatatype_t type,
+                         dns_name_t *domain, dns_rdataset_t *nameservers,
+                         dns_forwarders_t *forwarders,
+                         unsigned int options, isc_task_t *task,
+                         isc_taskaction_t action, void *arg,
+                         dns_rdataset_t *rdataset,
+                         dns_rdataset_t *sigrdataset,
+                         dns_fetch_t **fetchp)
 {
-       return (dns_resolver_createfetch2(res, name, type, domain,
-                                         nameservers, forwarders, NULL, 0,
-                                         options, task, action, arg,
-                                         rdataset, sigrdataset, fetchp));
+        return (dns_resolver_createfetch2(res, name, type, domain,
+                                          nameservers, forwarders, NULL, 0,
+                                          options, task, action, arg,
+                                          rdataset, sigrdataset, fetchp));
 }
 
 isc_result_t
 dns_resolver_createfetch2(dns_resolver_t *res, dns_name_t *name,
-                         dns_rdatatype_t type,
-                         dns_name_t *domain, dns_rdataset_t *nameservers,
-                         dns_forwarders_t *forwarders,
-                         isc_sockaddr_t *client, dns_messageid_t id,
-                         unsigned int options, isc_task_t *task,
-                         isc_taskaction_t action, void *arg,
-                         dns_rdataset_t *rdataset,
-                         dns_rdataset_t *sigrdataset,
-                         dns_fetch_t **fetchp)
+                          dns_rdatatype_t type,
+                          dns_name_t *domain, dns_rdataset_t *nameservers,
+                          dns_forwarders_t *forwarders,
+                          isc_sockaddr_t *client, dns_messageid_t id,
+                          unsigned int options, isc_task_t *task,
+                          isc_taskaction_t action, void *arg,
+                          dns_rdataset_t *rdataset,
+                          dns_rdataset_t *sigrdataset,
+                          dns_fetch_t **fetchp)
 {
-       dns_fetch_t *fetch;
-       fetchctx_t *fctx = NULL;
-       isc_result_t result = ISC_R_SUCCESS;
-       unsigned int bucketnum;
-       isc_boolean_t new_fctx = ISC_FALSE;
-       isc_event_t *event;
-       unsigned int count = 0;
-       unsigned int spillat;
-
-       UNUSED(forwarders);
-
-       REQUIRE(VALID_RESOLVER(res));
-       REQUIRE(res->frozen);
-       /* XXXRTH  Check for meta type */
-       if (domain != NULL) {
-               REQUIRE(DNS_RDATASET_VALID(nameservers));
-               REQUIRE(nameservers->type == dns_rdatatype_ns);
-       } else
-               REQUIRE(nameservers == NULL);
-       REQUIRE(forwarders == NULL);
-       REQUIRE(!dns_rdataset_isassociated(rdataset));
-       REQUIRE(sigrdataset == NULL ||
-               !dns_rdataset_isassociated(sigrdataset));
-       REQUIRE(fetchp != NULL && *fetchp == NULL);
-
-       log_fetch(name, type);
-
-       /*
-        * XXXRTH  use a mempool?
-        */
-       fetch = isc_mem_get(res->mctx, sizeof(*fetch));
-       if (fetch == NULL)
-               return (ISC_R_NOMEMORY);
-
-       bucketnum = dns_name_fullhash(name, ISC_FALSE) % res->nbuckets;
-
-       LOCK(&res->lock);
-       spillat = res->spillat;
-       UNLOCK(&res->lock);
-       LOCK(&res->buckets[bucketnum].lock);
-
-       if (res->buckets[bucketnum].exiting) {
-               result = ISC_R_SHUTTINGDOWN;
-               goto unlock;
-       }
-
-       if ((options & DNS_FETCHOPT_UNSHARED) == 0) {
-               for (fctx = ISC_LIST_HEAD(res->buckets[bucketnum].fctxs);
-                    fctx != NULL;
-                    fctx = ISC_LIST_NEXT(fctx, link)) {
-                       if (fctx_match(fctx, name, type, options))
-                               break;
-               }
-       }
-       
-       /*
-        * Is this a duplicate?
-        */
-       if (fctx != NULL && client != NULL) {
-               dns_fetchevent_t *fevent;
-               for (fevent = ISC_LIST_HEAD(fctx->events);
-                    fevent != NULL;
-                    fevent = ISC_LIST_NEXT(fevent, ev_link)) {
-                       if (fevent->client != NULL && fevent->id == id &&
-                           isc_sockaddr_equal(fevent->client, client)) {
-                               result = DNS_R_DUPLICATE;
-                               goto unlock;
-                       }
-                       count++;
-               }
-       }
-       if (count >= res->spillatmin && res->spillatmin != 0) {
-               if (count >= spillat)
-                       fctx->spilled = ISC_TRUE;
-               if (fctx->spilled) {
-                       result = DNS_R_DROP;
-                       goto unlock;
-               }
-       }
-
-       /*
-        * If we didn't have a fetch, would attach to a done fetch, this
-        * fetch has already cloned its results, or if the fetch has gone
-        * "idle" (no one was interested in it), we need to start a new
-        * fetch instead of joining with the existing one.
-        */
-       if (fctx == NULL ||
-           fctx->state == fetchstate_done ||
-           fctx->cloned ||
-           ISC_LIST_EMPTY(fctx->events)) {
-               fctx = NULL;
-               result = fctx_create(res, name, type, domain, nameservers,
-                                    options, bucketnum, &fctx);
-               if (result != ISC_R_SUCCESS)
-                       goto unlock;
-               new_fctx = ISC_TRUE;
-       }
-
-       result = fctx_join(fctx, task, client, id, action, arg,
-                          rdataset, sigrdataset, fetch);
-       if (new_fctx) {
-               if (result == ISC_R_SUCCESS) {
-                       /*
-                        * Launch this fctx.
-                        */
-                       event = &fctx->control_event;
-                       ISC_EVENT_INIT(event, sizeof(*event), 0, NULL,
-                                      DNS_EVENT_FETCHCONTROL,
-                                      fctx_start, fctx, NULL,
-                                      NULL, NULL);
-                       isc_task_send(res->buckets[bucketnum].task, &event);
-               } else {
-                       /*
-                        * We don't care about the result of fctx_destroy()
-                        * since we know we're not exiting.
-                        */
-                       (void)fctx_destroy(fctx);
-               }
-       }
+        dns_fetch_t *fetch;
+        fetchctx_t *fctx = NULL;
+        isc_result_t result = ISC_R_SUCCESS;
+        unsigned int bucketnum;
+        isc_boolean_t new_fctx = ISC_FALSE;
+        isc_event_t *event;
+        unsigned int count = 0;
+        unsigned int spillat;
+
+        UNUSED(forwarders);
+
+        REQUIRE(VALID_RESOLVER(res));
+        REQUIRE(res->frozen);
+        /* XXXRTH  Check for meta type */
+        if (domain != NULL) {
+                REQUIRE(DNS_RDATASET_VALID(nameservers));
+                REQUIRE(nameservers->type == dns_rdatatype_ns);
+        } else
+                REQUIRE(nameservers == NULL);
+        REQUIRE(forwarders == NULL);
+        REQUIRE(!dns_rdataset_isassociated(rdataset));
+        REQUIRE(sigrdataset == NULL ||
+                !dns_rdataset_isassociated(sigrdataset));
+        REQUIRE(fetchp != NULL && *fetchp == NULL);
+
+        log_fetch(name, type);
+
+        /*
+         * XXXRTH  use a mempool?
+         */
+        fetch = isc_mem_get(res->mctx, sizeof(*fetch));
+        if (fetch == NULL)
+                return (ISC_R_NOMEMORY);
+
+        bucketnum = dns_name_fullhash(name, ISC_FALSE) % res->nbuckets;
+
+        LOCK(&res->lock);
+        spillat = res->spillat;
+        UNLOCK(&res->lock);
+        LOCK(&res->buckets[bucketnum].lock);
+
+        if (res->buckets[bucketnum].exiting) {
+                result = ISC_R_SHUTTINGDOWN;
+                goto unlock;
+        }
+
+        if ((options & DNS_FETCHOPT_UNSHARED) == 0) {
+                for (fctx = ISC_LIST_HEAD(res->buckets[bucketnum].fctxs);
+                     fctx != NULL;
+                     fctx = ISC_LIST_NEXT(fctx, link)) {
+                        if (fctx_match(fctx, name, type, options))
+                                break;
+                }
+        }
+
+        /*
+         * Is this a duplicate?
+         */
+        if (fctx != NULL && client != NULL) {
+                dns_fetchevent_t *fevent;
+                for (fevent = ISC_LIST_HEAD(fctx->events);
+                     fevent != NULL;
+                     fevent = ISC_LIST_NEXT(fevent, ev_link)) {
+                        if (fevent->client != NULL && fevent->id == id &&
+                            isc_sockaddr_equal(fevent->client, client)) {
+                                result = DNS_R_DUPLICATE;
+                                goto unlock;
+                        }
+                        count++;
+                }
+        }
+        if (count >= res->spillatmin && res->spillatmin != 0) {
+                if (count >= spillat)
+                        fctx->spilled = ISC_TRUE;
+                if (fctx->spilled) {
+                        result = DNS_R_DROP;
+                        goto unlock;
+                }
+        }
+
+        /*
+         * If we didn't have a fetch, would attach to a done fetch, this
+         * fetch has already cloned its results, or if the fetch has gone
+         * "idle" (no one was interested in it), we need to start a new
+         * fetch instead of joining with the existing one.
+         */
+        if (fctx == NULL ||
+            fctx->state == fetchstate_done ||
+            fctx->cloned ||
+            ISC_LIST_EMPTY(fctx->events)) {
+                fctx = NULL;
+                result = fctx_create(res, name, type, domain, nameservers,
+                                     options, bucketnum, &fctx);
+                if (result != ISC_R_SUCCESS)
+                        goto unlock;
+                new_fctx = ISC_TRUE;
+        }
+
+        result = fctx_join(fctx, task, client, id, action, arg,
+                           rdataset, sigrdataset, fetch);
+        if (new_fctx) {
+                if (result == ISC_R_SUCCESS) {
+                        /*
+                         * Launch this fctx.
+                         */
+                        event = &fctx->control_event;
+                        ISC_EVENT_INIT(event, sizeof(*event), 0, NULL,
+                                       DNS_EVENT_FETCHCONTROL,
+                                       fctx_start, fctx, NULL,
+                                       NULL, NULL);
+                        isc_task_send(res->buckets[bucketnum].task, &event);
+                } else {
+                        /*
+                         * We don't care about the result of fctx_destroy()
+                         * since we know we're not exiting.
+                         */
+                        (void)fctx_destroy(fctx);
+                }
+        }
 
  unlock:
-       UNLOCK(&res->buckets[bucketnum].lock);
+        UNLOCK(&res->buckets[bucketnum].lock);
 
-       if (result == ISC_R_SUCCESS) {
-               FTRACE("created");
-               *fetchp = fetch;
-       } else
-               isc_mem_put(res->mctx, fetch, sizeof(*fetch));
+        if (result == ISC_R_SUCCESS) {
+                FTRACE("created");
+                *fetchp = fetch;
+        } else
+                isc_mem_put(res->mctx, fetch, sizeof(*fetch));
 
-       return (result);
+        return (result);
 }
 
 void
 dns_resolver_cancelfetch(dns_fetch_t *fetch) {
-       fetchctx_t *fctx;
-       dns_resolver_t *res;
-       dns_fetchevent_t *event, *next_event;
-       isc_task_t *etask;
-
-       REQUIRE(DNS_FETCH_VALID(fetch));
-       fctx = fetch->private;
-       REQUIRE(VALID_FCTX(fctx));
-       res = fctx->res;
-
-       FTRACE("cancelfetch");
-
-       LOCK(&res->buckets[fctx->bucketnum].lock);
-
-       /*
-        * Find the completion event for this fetch (as opposed
-        * to those for other fetches that have joined the same
-        * fctx) and send it with result = ISC_R_CANCELED.
-        */
-       event = NULL;
-       if (fctx->state != fetchstate_done) {
-               for (event = ISC_LIST_HEAD(fctx->events);
-                    event != NULL;
-                    event = next_event) {
-                       next_event = ISC_LIST_NEXT(event, ev_link);
-                       if (event->fetch == fetch) {
-                               ISC_LIST_UNLINK(fctx->events, event, ev_link);
-                               break;
-                       }
-               }
-       }
-       if (event != NULL) {
-               etask = event->ev_sender;
-               event->ev_sender = fctx;
-               event->result = ISC_R_CANCELED;
-               isc_task_sendanddetach(&etask, ISC_EVENT_PTR(&event));
-       }
-       /*
-        * The fctx continues running even if no fetches remain;
-        * the answer is still cached.
-        */
-
-       UNLOCK(&res->buckets[fctx->bucketnum].lock);
+        fetchctx_t *fctx;
+        dns_resolver_t *res;
+        dns_fetchevent_t *event, *next_event;
+        isc_task_t *etask;
+
+        REQUIRE(DNS_FETCH_VALID(fetch));
+        fctx = fetch->private;
+        REQUIRE(VALID_FCTX(fctx));
+        res = fctx->res;
+
+        FTRACE("cancelfetch");
+
+        LOCK(&res->buckets[fctx->bucketnum].lock);
+
+        /*
+         * Find the completion event for this fetch (as opposed
+         * to those for other fetches that have joined the same
+         * fctx) and send it with result = ISC_R_CANCELED.
+         */
+        event = NULL;
+        if (fctx->state != fetchstate_done) {
+                for (event = ISC_LIST_HEAD(fctx->events);
+                     event != NULL;
+                     event = next_event) {
+                        next_event = ISC_LIST_NEXT(event, ev_link);
+                        if (event->fetch == fetch) {
+                                ISC_LIST_UNLINK(fctx->events, event, ev_link);
+                                break;
+                        }
+                }
+        }
+        if (event != NULL) {
+                etask = event->ev_sender;
+                event->ev_sender = fctx;
+                event->result = ISC_R_CANCELED;
+                isc_task_sendanddetach(&etask, ISC_EVENT_PTR(&event));
+        }
+        /*
+         * The fctx continues running even if no fetches remain;
+         * the answer is still cached.
+         */
+
+        UNLOCK(&res->buckets[fctx->bucketnum].lock);
 }
 
 void
 dns_resolver_destroyfetch(dns_fetch_t **fetchp) {
-       dns_fetch_t *fetch;
-       dns_resolver_t *res;
-       dns_fetchevent_t *event, *next_event;
-       fetchctx_t *fctx;
-       unsigned int bucketnum;
-       isc_boolean_t bucket_empty = ISC_FALSE;
-
-       REQUIRE(fetchp != NULL);
-       fetch = *fetchp;
-       REQUIRE(DNS_FETCH_VALID(fetch));
-       fctx = fetch->private;
-       REQUIRE(VALID_FCTX(fctx));
-       res = fctx->res;
-
-       FTRACE("destroyfetch");
-
-       bucketnum = fctx->bucketnum;
-       LOCK(&res->buckets[bucketnum].lock);
-
-       /*
-        * Sanity check: the caller should have gotten its event before
-        * trying to destroy the fetch.
-        */
-       event = NULL;
-       if (fctx->state != fetchstate_done) {
-               for (event = ISC_LIST_HEAD(fctx->events);
-                    event != NULL;
-                    event = next_event) {
-                       next_event = ISC_LIST_NEXT(event, ev_link);
-                       RUNTIME_CHECK(event->fetch != fetch);
-               }
-       }
-
-       INSIST(fctx->references > 0);
-       fctx->references--;
-       if (fctx->references == 0) {
-               /*
-                * No one cares about the result of this fetch anymore.
-                */
-               if (fctx->pending == 0 && fctx->nqueries == 0 &&
-                   ISC_LIST_EMPTY(fctx->validators) &&
-                   SHUTTINGDOWN(fctx)) {
-                       /*
-                        * This fctx is already shutdown; we were just
-                        * waiting for the last reference to go away.
-                        */
-                       bucket_empty = fctx_destroy(fctx);
-               } else {
-                       /*
-                        * Initiate shutdown.
-                        */
-                       fctx_shutdown(fctx);
-               }
-       }
-
-       UNLOCK(&res->buckets[bucketnum].lock);
-
-       isc_mem_put(res->mctx, fetch, sizeof(*fetch));
-       *fetchp = NULL;
-
-       if (bucket_empty)
-               empty_bucket(res);
+        dns_fetch_t *fetch;
+        dns_resolver_t *res;
+        dns_fetchevent_t *event, *next_event;
+        fetchctx_t *fctx;
+        unsigned int bucketnum;
+        isc_boolean_t bucket_empty = ISC_FALSE;
+
+        REQUIRE(fetchp != NULL);
+        fetch = *fetchp;
+        REQUIRE(DNS_FETCH_VALID(fetch));
+        fctx = fetch->private;
+        REQUIRE(VALID_FCTX(fctx));
+        res = fctx->res;
+
+        FTRACE("destroyfetch");
+
+        bucketnum = fctx->bucketnum;
+        LOCK(&res->buckets[bucketnum].lock);
+
+        /*
+         * Sanity check: the caller should have gotten its event before
+         * trying to destroy the fetch.
+         */
+        event = NULL;
+        if (fctx->state != fetchstate_done) {
+                for (event = ISC_LIST_HEAD(fctx->events);
+                     event != NULL;
+                     event = next_event) {
+                        next_event = ISC_LIST_NEXT(event, ev_link);
+                        RUNTIME_CHECK(event->fetch != fetch);
+                }
+        }
+
+        INSIST(fctx->references > 0);
+        fctx->references--;
+        if (fctx->references == 0) {
+                /*
+                 * No one cares about the result of this fetch anymore.
+                 */
+                if (fctx->pending == 0 && fctx->nqueries == 0 &&
+                    ISC_LIST_EMPTY(fctx->validators) &&
+                    SHUTTINGDOWN(fctx)) {
+                        /*
+                         * This fctx is already shutdown; we were just
+                         * waiting for the last reference to go away.
+                         */
+                        bucket_empty = fctx_destroy(fctx);
+                } else {
+                        /*
+                         * Initiate shutdown.
+                         */
+                        fctx_shutdown(fctx);
+                }
+        }
+
+        UNLOCK(&res->buckets[bucketnum].lock);
+
+        isc_mem_put(res->mctx, fetch, sizeof(*fetch));
+        *fetchp = NULL;
+
+        if (bucket_empty)
+                empty_bucket(res);
 }
 
 dns_dispatchmgr_t *
 dns_resolver_dispatchmgr(dns_resolver_t *resolver) {
-       REQUIRE(VALID_RESOLVER(resolver));
-       return (resolver->dispatchmgr);
+        REQUIRE(VALID_RESOLVER(resolver));
+        return (resolver->dispatchmgr);
 }
 
 dns_dispatch_t *
 dns_resolver_dispatchv4(dns_resolver_t *resolver) {
-       REQUIRE(VALID_RESOLVER(resolver));
-       return (resolver->dispatchv4);
+        REQUIRE(VALID_RESOLVER(resolver));
+        return (resolver->dispatchv4);
 }
 
 dns_dispatch_t *
 dns_resolver_dispatchv6(dns_resolver_t *resolver) {
-       REQUIRE(VALID_RESOLVER(resolver));
-       return (resolver->dispatchv6);
+        REQUIRE(VALID_RESOLVER(resolver));
+        return (resolver->dispatchv6);
 }
 
 isc_socketmgr_t *
 dns_resolver_socketmgr(dns_resolver_t *resolver) {
-       REQUIRE(VALID_RESOLVER(resolver));
-       return (resolver->socketmgr);
+        REQUIRE(VALID_RESOLVER(resolver));
+        return (resolver->socketmgr);
 }
 
 isc_taskmgr_t *
 dns_resolver_taskmgr(dns_resolver_t *resolver) {
-       REQUIRE(VALID_RESOLVER(resolver));
-       return (resolver->taskmgr);
+        REQUIRE(VALID_RESOLVER(resolver));
+        return (resolver->taskmgr);
 }
 
 isc_uint32_t
 dns_resolver_getlamettl(dns_resolver_t *resolver) {
-       REQUIRE(VALID_RESOLVER(resolver));
-       return (resolver->lame_ttl);
+        REQUIRE(VALID_RESOLVER(resolver));
+        return (resolver->lame_ttl);
 }
 
 void
 dns_resolver_setlamettl(dns_resolver_t *resolver, isc_uint32_t lame_ttl) {
-       REQUIRE(VALID_RESOLVER(resolver));
-       resolver->lame_ttl = lame_ttl;
+        REQUIRE(VALID_RESOLVER(resolver));
+        resolver->lame_ttl = lame_ttl;
 }
 
 unsigned int
 dns_resolver_nrunning(dns_resolver_t *resolver) {
-       unsigned int n;
-       LOCK(&resolver->nlock);
-       n = resolver->nfctx;
-       UNLOCK(&resolver->nlock);
-       return (n);
+        unsigned int n;
+        LOCK(&resolver->nlock);
+        n = resolver->nfctx;
+        UNLOCK(&resolver->nlock);
+        return (n);
 }
 
 isc_result_t
 dns_resolver_addalternate(dns_resolver_t *resolver, isc_sockaddr_t *alt,
-                         dns_name_t *name, in_port_t port) {
-       alternate_t *a;
-       isc_result_t result;
-
-       REQUIRE(VALID_RESOLVER(resolver));
-       REQUIRE(!resolver->frozen);
-       REQUIRE((alt == NULL) ^ (name == NULL));
-
-       a = isc_mem_get(resolver->mctx, sizeof(*a));
-       if (a == NULL)
-               return (ISC_R_NOMEMORY);
-       if (alt != NULL) {
-               a->isaddress = ISC_TRUE;
-               a->_u.addr = *alt;
-       } else {
-               a->isaddress = ISC_FALSE;
-               a->_u._n.port = port;
-               dns_name_init(&a->_u._n.name, NULL);
-               result = dns_name_dup(name, resolver->mctx, &a->_u._n.name);
-               if (result != ISC_R_SUCCESS) {
-                       isc_mem_put(resolver->mctx, a, sizeof(*a));
-                       return (result);
-               }
-       }
-       ISC_LINK_INIT(a, link);
-       ISC_LIST_APPEND(resolver->alternates, a, link);
-
-       return (ISC_R_SUCCESS);
+                          dns_name_t *name, in_port_t port) {
+        alternate_t *a;
+        isc_result_t result;
+
+        REQUIRE(VALID_RESOLVER(resolver));
+        REQUIRE(!resolver->frozen);
+        REQUIRE((alt == NULL) ^ (name == NULL));
+
+        a = isc_mem_get(resolver->mctx, sizeof(*a));
+        if (a == NULL)
+                return (ISC_R_NOMEMORY);
+        if (alt != NULL) {
+                a->isaddress = ISC_TRUE;
+                a->_u.addr = *alt;
+        } else {
+                a->isaddress = ISC_FALSE;
+                a->_u._n.port = port;
+                dns_name_init(&a->_u._n.name, NULL);
+                result = dns_name_dup(name, resolver->mctx, &a->_u._n.name);
+                if (result != ISC_R_SUCCESS) {
+                        isc_mem_put(resolver->mctx, a, sizeof(*a));
+                        return (result);
+                }
+        }
+        ISC_LINK_INIT(a, link);
+        ISC_LIST_APPEND(resolver->alternates, a, link);
+
+        return (ISC_R_SUCCESS);
 }
 
 void
 dns_resolver_setudpsize(dns_resolver_t *resolver, isc_uint16_t udpsize) {
-       REQUIRE(VALID_RESOLVER(resolver));
-       resolver->udpsize = udpsize;
+        REQUIRE(VALID_RESOLVER(resolver));
+        resolver->udpsize = udpsize;
 }
 
 isc_uint16_t
 dns_resolver_getudpsize(dns_resolver_t *resolver) {
-       REQUIRE(VALID_RESOLVER(resolver));
-       return (resolver->udpsize);
+        REQUIRE(VALID_RESOLVER(resolver));
+        return (resolver->udpsize);
 }
 
 static void
 free_algorithm(void *node, void *arg) {
-       unsigned char *algorithms = node;
-       isc_mem_t *mctx = arg;
+        unsigned char *algorithms = node;
+        isc_mem_t *mctx = arg;
 
-       isc_mem_put(mctx, algorithms, *algorithms);
+        isc_mem_put(mctx, algorithms, *algorithms);
 }
+
 void
 dns_resolver_reset_algorithms(dns_resolver_t *resolver) {
 
-       REQUIRE(VALID_RESOLVER(resolver));
+        REQUIRE(VALID_RESOLVER(resolver));
 
 #if USE_ALGLOCK
-       RWLOCK(&resolver->alglock, isc_rwlocktype_write);
+        RWLOCK(&resolver->alglock, isc_rwlocktype_write);
 #endif
-       if (resolver->algorithms != NULL)
-               dns_rbt_destroy(&resolver->algorithms);
+        if (resolver->algorithms != NULL)
+                dns_rbt_destroy(&resolver->algorithms);
 #if USE_ALGLOCK
-       RWUNLOCK(&resolver->alglock, isc_rwlocktype_write);
+        RWUNLOCK(&resolver->alglock, isc_rwlocktype_write);
 #endif
 }
 
 isc_result_t
 dns_resolver_disable_algorithm(dns_resolver_t *resolver, dns_name_t *name,
-                              unsigned int alg)
+                               unsigned int alg)
 {
-       unsigned int len, mask;
-       unsigned char *new;
-       unsigned char *algorithms;
-       isc_result_t result;
-       dns_rbtnode_t *node = NULL;
+        unsigned int len, mask;
+        unsigned char *new;
+        unsigned char *algorithms;
+        isc_result_t result;
+        dns_rbtnode_t *node = NULL;
 
-       REQUIRE(VALID_RESOLVER(resolver));
-       if (alg > 255)
-               return (ISC_R_RANGE);
+        REQUIRE(VALID_RESOLVER(resolver));
+        if (alg > 255)
+                return (ISC_R_RANGE);
 
 #if USE_ALGLOCK
-       RWLOCK(&resolver->alglock, isc_rwlocktype_write);
+        RWLOCK(&resolver->alglock, isc_rwlocktype_write);
 #endif
-       if (resolver->algorithms == NULL) {
-               result = dns_rbt_create(resolver->mctx, free_algorithm,
-                                       resolver->mctx, &resolver->algorithms);
-               if (result != ISC_R_SUCCESS)
-                       goto cleanup;
-       }
-
-       len = alg/8 + 2;
-       mask = 1 << (alg%8);
-
-       result = dns_rbt_addnode(resolver->algorithms, name, &node);
-       
-       if (result == ISC_R_SUCCESS || result == ISC_R_EXISTS) {
-               algorithms = node->data;
-               if (algorithms == NULL || len > *algorithms) {
-                       new = isc_mem_get(resolver->mctx, len);
-                       if (new == NULL) {
-                               result = ISC_R_NOMEMORY;
-                               goto cleanup;
-                       }
-                       memset(new, 0, len);
-                       if (algorithms != NULL)
-                               memcpy(new, algorithms, *algorithms);
-                       new[len-1] |= mask;
-                       *new = len;
-                       node->data = new;
-                       if (algorithms != NULL)
-                               isc_mem_put(resolver->mctx, algorithms, 
-                                           *algorithms);
-               } else
-                       algorithms[len-1] |= mask;
-       }
-       result = ISC_R_SUCCESS;
+        if (resolver->algorithms == NULL) {
+                result = dns_rbt_create(resolver->mctx, free_algorithm,
+                                        resolver->mctx, &resolver->algorithms);
+                if (result != ISC_R_SUCCESS)
+                        goto cleanup;
+        }
+
+        len = alg/8 + 2;
+        mask = 1 << (alg%8);
+
+        result = dns_rbt_addnode(resolver->algorithms, name, &node);
+
+        if (result == ISC_R_SUCCESS || result == ISC_R_EXISTS) {
+                algorithms = node->data;
+                if (algorithms == NULL || len > *algorithms) {
+                        new = isc_mem_get(resolver->mctx, len);
+                        if (new == NULL) {
+                                result = ISC_R_NOMEMORY;
+                                goto cleanup;
+                        }
+                        memset(new, 0, len);
+                        if (algorithms != NULL)
+                                memcpy(new, algorithms, *algorithms);
+                        new[len-1] |= mask;
+                        *new = len;
+                        node->data = new;
+                        if (algorithms != NULL)
+                                isc_mem_put(resolver->mctx, algorithms,
+                                            *algorithms);
+                } else
+                        algorithms[len-1] |= mask;
+        }
+        result = ISC_R_SUCCESS;
  cleanup:
 #if USE_ALGLOCK
-       RWUNLOCK(&resolver->alglock, isc_rwlocktype_write);
+        RWUNLOCK(&resolver->alglock, isc_rwlocktype_write);
 #endif
-       return (result);
+        return (result);
 }
 
 isc_boolean_t
 dns_resolver_algorithm_supported(dns_resolver_t *resolver, dns_name_t *name,
-                                unsigned int alg)
+                                 unsigned int alg)
 {
-       unsigned int len, mask;
-       unsigned char *algorithms;
-       void *data = NULL;
-       isc_result_t result;
-       isc_boolean_t found = ISC_FALSE;
+        unsigned int len, mask;
+        unsigned char *algorithms;
+        void *data = NULL;
+        isc_result_t result;
+        isc_boolean_t found = ISC_FALSE;
 
-       REQUIRE(VALID_RESOLVER(resolver));
+        REQUIRE(VALID_RESOLVER(resolver));
 
 #if USE_ALGLOCK
-       RWLOCK(&resolver->alglock, isc_rwlocktype_read);
+        RWLOCK(&resolver->alglock, isc_rwlocktype_read);
 #endif
-       if (resolver->algorithms == NULL)
-               goto unlock;
-       result = dns_rbt_findname(resolver->algorithms, name, 0, NULL, &data);
-       if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
-               len = alg/8 + 2;
-               mask = 1 << (alg%8);
-               algorithms = data;
-               if (len <= *algorithms && (algorithms[len-1] & mask) != 0)
-                       found = ISC_TRUE;
-       }
+        if (resolver->algorithms == NULL)
+                goto unlock;
+        result = dns_rbt_findname(resolver->algorithms, name, 0, NULL, &data);
+        if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
+                len = alg/8 + 2;
+                mask = 1 << (alg%8);
+                algorithms = data;
+                if (len <= *algorithms && (algorithms[len-1] & mask) != 0)
+                        found = ISC_TRUE;
+        }
  unlock:
 #if USE_ALGLOCK
-       RWUNLOCK(&resolver->alglock, isc_rwlocktype_read);
+        RWUNLOCK(&resolver->alglock, isc_rwlocktype_read);
 #endif
-       if (found)
-               return (ISC_FALSE);
-       return (dst_algorithm_supported(alg));
+        if (found)
+                return (ISC_FALSE);
+        return (dst_algorithm_supported(alg));
 }
 
 isc_boolean_t
 dns_resolver_digest_supported(dns_resolver_t *resolver, unsigned int digest) {
 
-       UNUSED(resolver);
-       return (dns_ds_digest_supported(digest));
+        UNUSED(resolver);
+        return (dns_ds_digest_supported(digest));
 }
 
 void
 dns_resolver_resetmustbesecure(dns_resolver_t *resolver) {
 
-       REQUIRE(VALID_RESOLVER(resolver));
+        REQUIRE(VALID_RESOLVER(resolver));
 
 #if USE_MBSLOCK
-       RWLOCK(&resolver->mbslock, isc_rwlocktype_write);
+        RWLOCK(&resolver->mbslock, isc_rwlocktype_write);
 #endif
-       if (resolver->mustbesecure != NULL)
-               dns_rbt_destroy(&resolver->mustbesecure);
+        if (resolver->mustbesecure != NULL)
+                dns_rbt_destroy(&resolver->mustbesecure);
 #if USE_MBSLOCK
-       RWUNLOCK(&resolver->mbslock, isc_rwlocktype_write);
+        RWUNLOCK(&resolver->mbslock, isc_rwlocktype_write);
 #endif
 }
+
 static isc_boolean_t yes = ISC_TRUE, no = ISC_FALSE;
 
 isc_result_t
 dns_resolver_setmustbesecure(dns_resolver_t *resolver, dns_name_t *name,
                              isc_boolean_t value)
 {
-       isc_result_t result;
+        isc_result_t result;
 
-       REQUIRE(VALID_RESOLVER(resolver));
+        REQUIRE(VALID_RESOLVER(resolver));
 
 #if USE_MBSLOCK
-       RWLOCK(&resolver->mbslock, isc_rwlocktype_write);
+        RWLOCK(&resolver->mbslock, isc_rwlocktype_write);
 #endif
-       if (resolver->mustbesecure == NULL) {
-               result = dns_rbt_create(resolver->mctx, NULL, NULL,
-                                       &resolver->mustbesecure);
-               if (result != ISC_R_SUCCESS)
-                       goto cleanup;
-       }
-       result = dns_rbt_addname(resolver->mustbesecure, name, 
-                                value ? &yes : &no);
+        if (resolver->mustbesecure == NULL) {
+                result = dns_rbt_create(resolver->mctx, NULL, NULL,
+                                        &resolver->mustbesecure);
+                if (result != ISC_R_SUCCESS)
+                        goto cleanup;
+        }
+        result = dns_rbt_addname(resolver->mustbesecure, name,
+                                 value ? &yes : &no);
  cleanup:
 #if USE_MBSLOCK
-       RWUNLOCK(&resolver->mbslock, isc_rwlocktype_write);
+        RWUNLOCK(&resolver->mbslock, isc_rwlocktype_write);
 #endif
-       return (result);
+        return (result);
 }
 
 isc_boolean_t
 dns_resolver_getmustbesecure(dns_resolver_t *resolver, dns_name_t *name) {
-       void *data = NULL;
-       isc_boolean_t value = ISC_FALSE;
-       isc_result_t result;
+        void *data = NULL;
+        isc_boolean_t value = ISC_FALSE;
+        isc_result_t result;
 
-       REQUIRE(VALID_RESOLVER(resolver));
+        REQUIRE(VALID_RESOLVER(resolver));
 
 #if USE_MBSLOCK
-       RWLOCK(&resolver->mbslock, isc_rwlocktype_read);
+        RWLOCK(&resolver->mbslock, isc_rwlocktype_read);
 #endif
-       if (resolver->mustbesecure == NULL)
-               goto unlock;
-       result = dns_rbt_findname(resolver->mustbesecure, name, 0, NULL, &data);
-       if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH)
-               value = *(isc_boolean_t*)data;
+        if (resolver->mustbesecure == NULL)
+                goto unlock;
+        result = dns_rbt_findname(resolver->mustbesecure, name, 0, NULL, &data);
+        if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH)
+                value = *(isc_boolean_t*)data;
  unlock:
 #if USE_MBSLOCK
-       RWUNLOCK(&resolver->mbslock, isc_rwlocktype_read);
+        RWUNLOCK(&resolver->mbslock, isc_rwlocktype_read);
 #endif
-       return (value);
+        return (value);
 }
 
 void
 dns_resolver_getclientsperquery(dns_resolver_t *resolver, isc_uint32_t *cur,
-                               isc_uint32_t *min, isc_uint32_t *max)
+                                isc_uint32_t *min, isc_uint32_t *max)
 {
-       REQUIRE(VALID_RESOLVER(resolver));
-
-       LOCK(&resolver->lock);
-       if (cur != NULL)
-               *cur = resolver->spillat;
-       if (min != NULL)
-               *min = resolver->spillatmin;
-       if (max != NULL)
-               *max = resolver->spillatmax;
-       UNLOCK(&resolver->lock);
+        REQUIRE(VALID_RESOLVER(resolver));
+
+        LOCK(&resolver->lock);
+        if (cur != NULL)
+                *cur = resolver->spillat;
+        if (min != NULL)
+                *min = resolver->spillatmin;
+        if (max != NULL)
+                *max = resolver->spillatmax;
+        UNLOCK(&resolver->lock);
 }
 
 void
 dns_resolver_setclientsperquery(dns_resolver_t *resolver, isc_uint32_t min,
-                               isc_uint32_t max)
+                                isc_uint32_t max)
 {
-       REQUIRE(VALID_RESOLVER(resolver));
+        REQUIRE(VALID_RESOLVER(resolver));
 
-       LOCK(&resolver->lock);
-       resolver->spillatmin = resolver->spillat = min;
-       resolver->spillatmax = max;
-       UNLOCK(&resolver->lock);
+        LOCK(&resolver->lock);
+        resolver->spillatmin = resolver->spillat = min;
+        resolver->spillatmax = max;
+        UNLOCK(&resolver->lock);
 }
 
 isc_boolean_t
 dns_resolver_getzeronosoattl(dns_resolver_t *resolver) {
-       REQUIRE(VALID_RESOLVER(resolver));
+        REQUIRE(VALID_RESOLVER(resolver));
 
-       return (resolver->zero_no_soa_ttl);
+        return (resolver->zero_no_soa_ttl);
 }
 
 void
 dns_resolver_setzeronosoattl(dns_resolver_t *resolver, isc_boolean_t state) {
-       REQUIRE(VALID_RESOLVER(resolver));
+        REQUIRE(VALID_RESOLVER(resolver));
 
-       resolver->zero_no_soa_ttl = state;
+        resolver->zero_no_soa_ttl = state;
 }
 
 unsigned int
 dns_resolver_getoptions(dns_resolver_t *resolver) {
-       REQUIRE(VALID_RESOLVER(resolver));
-       
-       return (resolver->options);
+        REQUIRE(VALID_RESOLVER(resolver));
+
+        return (resolver->options);
 }
 
 static void
 disppooltimer_update(isc_task_t *task, isc_event_t *event) {
-       dns_resolver_t *res = event->ev_arg;
-       isc_sockaddr_t addr4, addr6;
-       dns_dispatch_t *disp4 = NULL, *disp6 = NULL;
-       isc_result_t result;
-       unsigned int nxt;
-       unsigned int attrs_base, attrs, attrmask;
-
-       REQUIRE(VALID_RESOLVER(res));
-       REQUIRE((res->options & DNS_RESOLVER_USEDISPATCHPOOL4) != 0 ||
-               (res->options & DNS_RESOLVER_USEDISPATCHPOOL6) != 0);
-
-       UNUSED(task);
-       isc_event_free(&event);
-       
-       LOCK(&res->lock);
-       nxt = res->nextdisp++;
-       if (res->nextdisp == res->ndisps)
-               res->nextdisp = 0;
-       UNLOCK(&res->lock);
-
-       attrs_base = 0;
-       attrs_base |= DNS_DISPATCHATTR_UDP;
-       attrs_base |= DNS_DISPATCHATTR_RANDOMPORT;
-
-       attrmask = 0;
-       attrmask |= DNS_DISPATCHATTR_UDP;
-       attrmask |= DNS_DISPATCHATTR_TCP;
-       attrmask |= DNS_DISPATCHATTR_IPV4;
-       attrmask |= DNS_DISPATCHATTR_IPV6;
-
-       RES_LOCK(&res->poollock, isc_rwlocktype_read);
-       if ((res->options & DNS_RESOLVER_USEDISPATCHPOOL4) != 0) {
-               result = dns_dispatch_getlocaladdress(res->dispatchv4pool[nxt],
-                                                     &addr4);
-               INSIST(result == ISC_R_SUCCESS);
-       }
-       if ((res->options & DNS_RESOLVER_USEDISPATCHPOOL6) != 0) {
-               result = dns_dispatch_getlocaladdress(res->dispatchv6pool[nxt],
-                                                     &addr6);
-               INSIST(result == ISC_R_SUCCESS);
-       }
-       RES_UNLOCK(&res->poollock, isc_rwlocktype_read);
-
-       if ((res->options & DNS_RESOLVER_USEDISPATCHPOOL4) != 0) {
-               attrs = attrs_base;
-               attrs |= DNS_DISPATCHATTR_IPV4;
-
-               result = dns_dispatch_getudp(res->dispatchmgr,
-                                            res->socketmgr,
-                                            res->taskmgr, &addr4,
-                                            4096, 1000, 32768, 16411,
-                                            16433, attrs, attrmask,
-                                            &disp4);
-               if (result != ISC_R_SUCCESS) {
-                       isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,
-                                     DNS_LOGMODULE_RESOLVER, ISC_LOG_ERROR,
-                                     "could not update an IPv4 random query "
-                                     "port: %s",
-                                     isc_result_totext(result));
-                       /* keep the old one */
-               }
-
-               /*
-                * We don't try to ensure the new dispatch is unique (see the
-                * comments in dns_resolver_createdispatchpool()).
-                */
-       }
-       if ((res->options & DNS_RESOLVER_USEDISPATCHPOOL6) != 0) {
-               attrs = attrs_base;
-               attrs |= DNS_DISPATCHATTR_IPV6;
-
-               result = dns_dispatch_getudp(res->dispatchmgr,
-                                            res->socketmgr,
-                                            res->taskmgr, &addr6,
-                                            4096, 1000, 32768, 16411,
-                                            16433, attrs, attrmask,
-                                            &disp6);
-               if (result != ISC_R_SUCCESS) {
-                       isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,
-                                     DNS_LOGMODULE_RESOLVER, ISC_LOG_ERROR,
-                                     "could not update an IPv6 random query "
-                                     "port: %s",
-                                     isc_result_totext(result));
-               }
-       }
-
-       RES_LOCK(&res->poollock, isc_rwlocktype_write);
-       if (disp4 != NULL) {
-               dns_dispatch_detach(&res->dispatchv4pool[nxt]);
-               res->dispatchv4pool[nxt] = disp4;
-       }
-       if (disp6 != NULL) {
-               dns_dispatch_detach(&res->dispatchv6pool[nxt]);
-               res->dispatchv6pool[nxt] = disp6;
-       }
-       RES_UNLOCK(&res->poollock, isc_rwlocktype_write);
-
-       return;
+        dns_resolver_t *res = event->ev_arg;
+        isc_sockaddr_t addr4, addr6;
+        dns_dispatch_t *disp4 = NULL, *disp6 = NULL;
+        isc_result_t result;
+        unsigned int nxt;
+        unsigned int attrs_base, attrs, attrmask;
+
+        REQUIRE(VALID_RESOLVER(res));
+        REQUIRE((res->options & DNS_RESOLVER_USEDISPATCHPOOL4) != 0 ||
+                (res->options & DNS_RESOLVER_USEDISPATCHPOOL6) != 0);
+
+        UNUSED(task);
+        isc_event_free(&event);
+
+        LOCK(&res->lock);
+        nxt = res->nextdisp++;
+        if (res->nextdisp == res->ndisps)
+                res->nextdisp = 0;
+        UNLOCK(&res->lock);
+
+        attrs_base = 0;
+        attrs_base |= DNS_DISPATCHATTR_UDP;
+        attrs_base |= DNS_DISPATCHATTR_RANDOMPORT;
+
+        attrmask = 0;
+        attrmask |= DNS_DISPATCHATTR_UDP;
+        attrmask |= DNS_DISPATCHATTR_TCP;
+        attrmask |= DNS_DISPATCHATTR_IPV4;
+        attrmask |= DNS_DISPATCHATTR_IPV6;
+
+        RES_LOCK(&res->poollock, isc_rwlocktype_read);
+        if ((res->options & DNS_RESOLVER_USEDISPATCHPOOL4) != 0) {
+                result = dns_dispatch_getlocaladdress(res->dispatchv4pool[nxt],
+                                                      &addr4);
+                INSIST(result == ISC_R_SUCCESS);
+        }
+        if ((res->options & DNS_RESOLVER_USEDISPATCHPOOL6) != 0) {
+                result = dns_dispatch_getlocaladdress(res->dispatchv6pool[nxt],
+                                                      &addr6);
+                INSIST(result == ISC_R_SUCCESS);
+        }
+        RES_UNLOCK(&res->poollock, isc_rwlocktype_read);
+
+        if ((res->options & DNS_RESOLVER_USEDISPATCHPOOL4) != 0) {
+                attrs = attrs_base;
+                attrs |= DNS_DISPATCHATTR_IPV4;
+
+                result = dns_dispatch_getudp(res->dispatchmgr,
+                                             res->socketmgr,
+                                             res->taskmgr, &addr4,
+                                             4096, 1000, 32768, 16411,
+                                             16433, attrs, attrmask,
+                                             &disp4);
+                if (result != ISC_R_SUCCESS) {
+                        isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,
+                                      DNS_LOGMODULE_RESOLVER, ISC_LOG_ERROR,
+                                      "could not update an IPv4 random query "
+                                      "port: %s",
+                                      isc_result_totext(result));
+                        /* keep the old one */
+                }
+
+                /*
+                 * We don't try to ensure the new dispatch is unique (see the
+                 * comments in dns_resolver_createdispatchpool()).
+                 */
+        }
+        if ((res->options & DNS_RESOLVER_USEDISPATCHPOOL6) != 0) {
+                attrs = attrs_base;
+                attrs |= DNS_DISPATCHATTR_IPV6;
+
+                result = dns_dispatch_getudp(res->dispatchmgr,
+                                             res->socketmgr,
+                                             res->taskmgr, &addr6,
+                                             4096, 1000, 32768, 16411,
+                                             16433, attrs, attrmask,
+                                             &disp6);
+                if (result != ISC_R_SUCCESS) {
+                        isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,
+                                      DNS_LOGMODULE_RESOLVER, ISC_LOG_ERROR,
+                                      "could not update an IPv6 random query "
+                                      "port: %s",
+                                      isc_result_totext(result));
+                }
+        }
+
+        RES_LOCK(&res->poollock, isc_rwlocktype_write);
+        if (disp4 != NULL) {
+                dns_dispatch_detach(&res->dispatchv4pool[nxt]);
+                res->dispatchv4pool[nxt] = disp4;
+        }
+        if (disp6 != NULL) {
+                dns_dispatch_detach(&res->dispatchv6pool[nxt]);
+                res->dispatchv6pool[nxt] = disp6;
+        }
+        RES_UNLOCK(&res->poollock, isc_rwlocktype_write);
+
+        return;
 }
 
 isc_result_t
 dns_resolver_createdispatchpool(dns_resolver_t *res, unsigned int ndisps,
-                               unsigned int tick)
+                                unsigned int tick)
 {
-       unsigned int i;
-       isc_result_t result = ISC_R_SUCCESS;
-       unsigned int attrs_base, attrs, attrmask;
-       isc_sockaddr_t addr4, addr6;
-       dns_dispatch_t *disp;
-       isc_task_t *task;
-       isc_interval_t interval;
-
-       REQUIRE(VALID_RESOLVER(res));
-       REQUIRE(!res->frozen);  /* meaning we don't have to lock res */
-       REQUIRE(ndisps > 0);
-       REQUIRE((res->options & DNS_RESOLVER_USEDISPATCHPOOL4) != 0 ||
-               (res->options & DNS_RESOLVER_USEDISPATCHPOOL6) != 0);
-
-       attrs_base = 0;
-       attrs_base |= DNS_DISPATCHATTR_UDP;
-       attrs_base |= DNS_DISPATCHATTR_RANDOMPORT;
-
-       attrmask = 0;
-       attrmask |= DNS_DISPATCHATTR_UDP;
-       attrmask |= DNS_DISPATCHATTR_TCP;
-       attrmask |= DNS_DISPATCHATTR_IPV4;
-       attrmask |= DNS_DISPATCHATTR_IPV6;
-
-       if ((res->options & DNS_RESOLVER_USEDISPATCHPOOL4) != 0) {
-               INSIST(res->dispatchv4 != NULL);
-               result = dns_dispatch_getlocaladdress(res->dispatchv4, &addr4);
-               INSIST(result == ISC_R_SUCCESS &&
-                      isc_sockaddr_getport(&addr4) == 0);
-               res->dispatchv4pool = isc_mem_get(res->mctx,
-                                                 sizeof(dns_dispatch_t *) *
-                                                 ndisps);
-               if (res->dispatchv4pool == NULL)
-                       return (ISC_R_NOMEMORY);
-               for (i = 0; i < ndisps; i++)
-                       res->dispatchv4pool[i] = NULL;
-       }
-       if ((res->options & DNS_RESOLVER_USEDISPATCHPOOL6) != 0) {
-               INSIST(res->dispatchv6 != NULL);
-               result = dns_dispatch_getlocaladdress(res->dispatchv6, &addr6);
-               INSIST(result == ISC_R_SUCCESS &&
-                      isc_sockaddr_getport(&addr6) == 0);
-               res->dispatchv6pool = isc_mem_get(res->mctx,
-                                                 sizeof(dns_dispatch_t *) *
-                                                 ndisps);
-               if (res->dispatchv6pool == NULL) {
-                       isc_mem_put(res->mctx, res->dispatchv4pool,
-                                   sizeof(dns_dispatch_t *) * ndisps);
-                       res->dispatchv4pool = NULL;
-                       return (ISC_R_NOMEMORY);
-               }
-               for (i = 0; i < ndisps; i++)
-                       res->dispatchv6pool[i] = NULL;
-       }
-
-       for (i = 0; i < ndisps; i++) {
-               if ((res->options & DNS_RESOLVER_USEDISPATCHPOOL4) != 0) {
-                       attrs = attrs_base;
-                       attrs |= DNS_DISPATCHATTR_IPV4;
-
-                       disp = NULL;
-                       result = dns_dispatch_getudp(res->dispatchmgr,
-                                                    res->socketmgr,
-                                                    res->taskmgr, &addr4,
-                                                    4096, 1000, 32768, 16411,
-                                                    16433, attrs, attrmask,
-                                                    &disp);
-                       if (result != ISC_R_SUCCESS)
-                               goto cleanup;
-                       res->dispatchv4pool[i] = disp;
-
-                       /*
-                        * It might be better to ensure all ports are
-                        * different, but in practice it's probably okay to
-                        * assume dns_dispatch_getudp() made reasonable
-                        * choices.
-                        */
-               }
-               if ((res->options & DNS_RESOLVER_USEDISPATCHPOOL6) != 0) {
-                       attrs = attrs_base;
-                       attrs |= DNS_DISPATCHATTR_IPV6;
-
-                       disp = NULL;
-                       result = dns_dispatch_getudp(res->dispatchmgr,
-                                                    res->socketmgr,
-                                                    res->taskmgr, &addr6,
-                                                    4096, 1000, 32768, 16411,
-                                                    16433, attrs, attrmask,
-                                                    &disp);
-                       if (result != ISC_R_SUCCESS)
-                               goto cleanup;
-
-                       res->dispatchv6pool[i] = disp;
-               }
-       }
-
-       /* start update timer */
-       if (tick != 0) { 
-               task = NULL;
-               result = isc_task_create(res->taskmgr, 0, &task);
-               if (result != ISC_R_SUCCESS)
-                       goto cleanup;
-               isc_interval_set(&interval, tick, 0);
-               result = isc_timer_create(res->timermgr, isc_timertype_ticker,
-                                         NULL, &interval, task,
-                                         disppooltimer_update,
-                                         res, &res->disppooltimer);
-               isc_task_detach(&task);
-               if (result != ISC_R_SUCCESS)
-                       goto cleanup;
-       }
-
-       res->ndisps = ndisps;
-       res->nextdisp = 0;
-
-       return (result);
+        unsigned int i;
+        isc_result_t result = ISC_R_SUCCESS;
+        unsigned int attrs_base, attrs, attrmask;
+        isc_sockaddr_t addr4, addr6;
+        dns_dispatch_t *disp;
+        isc_task_t *task;
+        isc_interval_t interval;
+
+        REQUIRE(VALID_RESOLVER(res));
+        REQUIRE(!res->frozen);  /* meaning we don't have to lock res */
+        REQUIRE(ndisps > 0);
+        REQUIRE((res->options & DNS_RESOLVER_USEDISPATCHPOOL4) != 0 ||
+                (res->options & DNS_RESOLVER_USEDISPATCHPOOL6) != 0);
+
+        attrs_base = 0;
+        attrs_base |= DNS_DISPATCHATTR_UDP;
+        attrs_base |= DNS_DISPATCHATTR_RANDOMPORT;
+
+        attrmask = 0;
+        attrmask |= DNS_DISPATCHATTR_UDP;
+        attrmask |= DNS_DISPATCHATTR_TCP;
+        attrmask |= DNS_DISPATCHATTR_IPV4;
+        attrmask |= DNS_DISPATCHATTR_IPV6;
+
+        if ((res->options & DNS_RESOLVER_USEDISPATCHPOOL4) != 0) {
+                INSIST(res->dispatchv4 != NULL);
+                result = dns_dispatch_getlocaladdress(res->dispatchv4, &addr4);
+                INSIST(result == ISC_R_SUCCESS &&
+                       isc_sockaddr_getport(&addr4) == 0);
+                res->dispatchv4pool = isc_mem_get(res->mctx,
+                                                  sizeof(dns_dispatch_t *) *
+                                                  ndisps);
+                if (res->dispatchv4pool == NULL)
+                        return (ISC_R_NOMEMORY);
+                for (i = 0; i < ndisps; i++)
+                        res->dispatchv4pool[i] = NULL;
+        }
+        if ((res->options & DNS_RESOLVER_USEDISPATCHPOOL6) != 0) {
+                INSIST(res->dispatchv6 != NULL);
+                result = dns_dispatch_getlocaladdress(res->dispatchv6, &addr6);
+                INSIST(result == ISC_R_SUCCESS &&
+                       isc_sockaddr_getport(&addr6) == 0);
+                res->dispatchv6pool = isc_mem_get(res->mctx,
+                                                  sizeof(dns_dispatch_t *) *
+                                                  ndisps);
+                if (res->dispatchv6pool == NULL) {
+                        isc_mem_put(res->mctx, res->dispatchv4pool,
+                                    sizeof(dns_dispatch_t *) * ndisps);
+                        res->dispatchv4pool = NULL;
+                        return (ISC_R_NOMEMORY);
+                }
+                for (i = 0; i < ndisps; i++)
+                        res->dispatchv6pool[i] = NULL;
+        }
+
+        for (i = 0; i < ndisps; i++) {
+                if ((res->options & DNS_RESOLVER_USEDISPATCHPOOL4) != 0) {
+                        attrs = attrs_base;
+                        attrs |= DNS_DISPATCHATTR_IPV4;
+
+                        disp = NULL;
+                        result = dns_dispatch_getudp(res->dispatchmgr,
+                                                     res->socketmgr,
+                                                     res->taskmgr, &addr4,
+                                                     4096, 1000, 32768, 16411,
+                                                     16433, attrs, attrmask,
+                                                     &disp);
+                        if (result != ISC_R_SUCCESS)
+                                goto cleanup;
+                        res->dispatchv4pool[i] = disp;
+
+                        /*
+                         * It might be better to ensure all ports are
+                         * different, but in practice it's probably okay to
+                         * assume dns_dispatch_getudp() made reasonable
+                         * choices.
+                         */
+                }
+                if ((res->options & DNS_RESOLVER_USEDISPATCHPOOL6) != 0) {
+                        attrs = attrs_base;
+                        attrs |= DNS_DISPATCHATTR_IPV6;
+
+                        disp = NULL;
+                        result = dns_dispatch_getudp(res->dispatchmgr,
+                                                     res->socketmgr,
+                                                     res->taskmgr, &addr6,
+                                                     4096, 1000, 32768, 16411,
+                                                     16433, attrs, attrmask,
+                                                     &disp);
+                        if (result != ISC_R_SUCCESS)
+                                goto cleanup;
+
+                        res->dispatchv6pool[i] = disp;
+                }
+        }
+
+        /* start update timer */
+        if (tick != 0) {
+                task = NULL;
+                result = isc_task_create(res->taskmgr, 0, &task);
+                if (result != ISC_R_SUCCESS)
+                        goto cleanup;
+                isc_interval_set(&interval, tick, 0);
+                result = isc_timer_create(res->timermgr, isc_timertype_ticker,
+                                          NULL, &interval, task,
+                                          disppooltimer_update,
+                                          res, &res->disppooltimer);
+                isc_task_detach(&task);
+                if (result != ISC_R_SUCCESS)
+                        goto cleanup;
+        }
+
+        res->ndisps = ndisps;
+        res->nextdisp = 0;
+
+        return (result);
 
   cleanup:
-       if (res->dispatchv4pool != NULL) {
-               for (i = 0; i < ndisps; i++)
-                       if (res->dispatchv4pool[i] != NULL)
-                               dns_dispatch_detach(&res->dispatchv4pool[i]);
-               isc_mem_put(res->mctx, res->dispatchv4pool,
-                           sizeof(dns_dispatch_t *) * ndisps);
-       }
-       if (res->dispatchv6pool != NULL) {
-               for (i = 0; i < ndisps; i++)
-                       if (res->dispatchv6pool[i] != NULL)
-                               dns_dispatch_detach(&res->dispatchv6pool[i]);
-               isc_mem_put(res->mctx, res->dispatchv6pool,
-                           sizeof(dns_dispatch_t *) * ndisps);
-       }
-
-       return (result);
+        if (res->dispatchv4pool != NULL) {
+                for (i = 0; i < ndisps; i++)
+                        if (res->dispatchv4pool[i] != NULL)
+                                dns_dispatch_detach(&res->dispatchv4pool[i]);
+                isc_mem_put(res->mctx, res->dispatchv4pool,
+                            sizeof(dns_dispatch_t *) * ndisps);
+        }
+        if (res->dispatchv6pool != NULL) {
+                for (i = 0; i < ndisps; i++)
+                        if (res->dispatchv6pool[i] != NULL)
+                                dns_dispatch_detach(&res->dispatchv6pool[i]);
+                isc_mem_put(res->mctx, res->dispatchv6pool,
+                            sizeof(dns_dispatch_t *) * ndisps);
+        }
+
+        return (result);
 }
+
+#ifdef LRU_DEBUG
+static void
+timer_dump(isc_task_t *task, isc_event_t *ev) {
+        dns_resolver_t *res;
+        isc_interval_t interval;
+        isc_time_t nexttime;
+
+        UNUSED(task);
+
+        res = ev->ev_arg;
+        INSIST(VALID_RESOLVER(res));
+
+        if (res->extqueries > 0) {
+                isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,
+                              DNS_LOGMODULE_RESOLVER, ISC_LOG_INFO,
+                              "resolver dump %p: external queries "
+                              "total/NS/SOA/A/AAAA=%u/%u/%u/%u/%u",
+                              res, res->extqueries, res->extqueries_ns,
+                              res->extqueries_soa, res->extqueries_a,
+                              res->extqueries_aaaa);
+        }
+
+        interval.seconds = DUMP_INTERVAL;
+        interval.nanoseconds = 0;
+
+        RUNTIME_CHECK(isc_time_add(&res->dump_time, &interval, &nexttime) ==
+                      ISC_R_SUCCESS); /* XXX: this is not always true */
+        res->dump_time = nexttime;
+        (void)isc_timer_reset(res->dumptimer, isc_timertype_once,
+                              &res->dump_time, NULL, ISC_FALSE);
+
+        isc_event_free(&ev);
+}
+#endif
index 70ce078d9b89c5c27e67a3c0593381df02122287..91d78c06d468bcdb6b0a466e2631717dafbe79bd 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: heap.c,v 1.36 2007/06/19 23:47:17 tbox Exp $ */
+/* $Id: heap.c,v 1.37 2007/10/19 17:15:53 explorer Exp $ */
 
 /*! \file
  * Heap implementation of priority queues adapted from the following:
@@ -208,9 +208,13 @@ isc_heap_delete(isc_heap_t *heap, unsigned int index) {
        REQUIRE(index >= 1 && index <= heap->last);
 
        if (index == heap->last) {
+               heap->array[heap->last] = NULL;
                heap->last--;
        } else {
-               elt = heap->array[heap->last--];
+               elt = heap->array[heap->last];
+               heap->array[heap->last] = NULL;
+               heap->last--;
+
                less = heap->compare(elt, heap->array[index]);
                heap->array[index] = elt;
                if (less)
@@ -239,9 +243,11 @@ isc_heap_decreased(isc_heap_t *heap, unsigned int index) {
 void *
 isc_heap_element(isc_heap_t *heap, unsigned int index) {
        REQUIRE(VALID_HEAP(heap));
-       REQUIRE(index >= 1 && index <= heap->last);
+       REQUIRE(index >= 1);
 
-       return (heap->array[index]);
+       if (index <= heap->last)
+               return (heap->array[index]);
+       return (NULL);
 }
 
 void