]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
2993. [func] Dynamically grow adb hash tables. [RT #21186]
authorMark Andrews <marka@isc.org>
Tue, 21 Dec 2010 03:11:42 +0000 (03:11 +0000)
committerMark Andrews <marka@isc.org>
Tue, 21 Dec 2010 03:11:42 +0000 (03:11 +0000)
CHANGES
lib/dns/adb.c
lib/dns/include/dns/events.h

diff --git a/CHANGES b/CHANGES
index b62f0c23d8dabd83cda94f2834a9c2ee3b1fdb13..ae6e90ae26e00c4ba629d923e34d57e04d856a41 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,5 @@
+2993.  [func]          Dynamically grow adb hash tables. [RT #21186]
+
 2992.  [contrib]       contrib/check-secure-delegation.pl:  A simple tool
                        for looking at a secure delegation. [RT #22059]
 
index 34f5a91c99a60139d8d09e6acc8b508982691172..96fd9eb8807813c4aa424ea78b21ecfb521de16d 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: adb.c,v 1.252 2010/12/16 09:51:29 jinmei Exp $ */
+/* $Id: adb.c,v 1.253 2010/12/21 03:11:42 marka Exp $ */
 
 /*! \file
  *
 #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 */
-
 /*!
  * For type 3 negative cache entries, we will remember that the address is
  * broken for this long.  XXXMLG This is also used for actual addresses, too.
@@ -139,30 +132,37 @@ struct dns_adb {
         *
         * XXXRTH  Have a per-bucket structure that contains all of these?
         */
-       dns_adbnamelist_t               names[NBUCKETS];
-       dns_adbnamelist_t               deadnames[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];
+       unsigned int                    nnames;
+       isc_mutex_t                     namescntlock;
+       unsigned int                    namescnt;
+       dns_adbnamelist_t               *names;
+       dns_adbnamelist_t               *deadnames;
+       isc_mutex_t                     *namelocks;
+       isc_boolean_t                   *name_sd;
+       unsigned int                    *name_refcnt;
 
        /*!
-        * Bucketized locks for entries.
+        * Bucketized locks and lists for entries.
         *
         * XXXRTH  Have a per-bucket structure that contains all of these?
         */
-       dns_adbentrylist_t              entries[NBUCKETS];
-       dns_adbentrylist_t              deadentries[NBUCKETS];
-       isc_mutex_t                     entrylocks[NBUCKETS];
-       isc_boolean_t                   entry_sd[NBUCKETS]; /*%< shutting down */
-       unsigned int                    entry_refcnt[NBUCKETS];
+       unsigned int                    nentries;
+       isc_mutex_t                     entriescntlock;
+       unsigned int                    entriescnt;
+       dns_adbentrylist_t              *entries;
+       dns_adbentrylist_t              *deadentries;
+       isc_mutex_t                     *entrylocks;
+       isc_boolean_t                   *entry_sd; /*%< shutting down */
+       unsigned int                    *entry_refcnt;
 
        isc_event_t                     cevent;
        isc_boolean_t                   cevent_sent;
        isc_boolean_t                   shutting_down;
        isc_eventlist_t                 whenshutdown;
+       isc_event_t                     growentries;
+       isc_boolean_t                   growentries_sent;
+       isc_event_t                     grownames;
+       isc_boolean_t                   grownames_sent;
 };
 
 /*
@@ -483,6 +483,322 @@ ttlclamp(dns_ttl_t ttl) {
        return (ttl);
 }
 
+/*
+ * Hashing is most efficient if the number of buckets is prime.
+ * The sequence below is the closest previous primes to 2^n and
+ * 1.5 * 2^n, for values of n from 10 to 28.  (The tables will
+ * no longer grow beyond 2^28 entries.)
+ */
+static const unsigned nbuckets[] = { 1021, 1531, 2039, 3067, 4093, 6143,
+                                    8191, 12281, 16381, 24571, 32749,
+                                    49193, 65521, 98299, 131071, 199603,
+                                    262139, 393209, 524287, 768431, 1048573, 
+                                    1572853, 2097143, 3145721, 4194301,
+                                    6291449, 8388593, 12582893, 16777213,
+                                    25165813, 33554393, 50331599, 67108859, 
+                                    100663291, 134217689, 201326557,
+                                    268535431, 0 };
+
+static void
+grow_entries(isc_task_t *task, isc_event_t *ev) {
+       dns_adb_t *adb;
+       dns_adbentry_t *e;
+       dns_adbentrylist_t *newdeadentries = NULL;
+       dns_adbentrylist_t *newentries = NULL;
+       isc_boolean_t *newentry_sd = NULL;
+       isc_mutex_t *newentrylocks = NULL;
+       isc_result_t result;
+       unsigned int *newentry_refcnt = NULL;
+       unsigned int i, n, bucket;
+       
+       adb = ev->ev_arg;
+       INSIST(DNS_ADB_VALID(adb));
+
+       isc_event_free(&ev);
+
+       isc_task_beginexclusive(task);
+
+       i = 0;
+       while (nbuckets[i] != 0 && adb->nentries >= nbuckets[i])
+               i++;
+       if (nbuckets[i] != 0)
+               n = nbuckets[i];
+       else
+               goto done;
+
+       DP(ISC_LOG_INFO, "adb: grow_entries to %u starting", n);
+
+       /*
+        * Are we shutting down?
+        */
+       for (i = 0; i < adb->nentries; i++)
+               if (adb->entry_sd[i])
+                       goto cleanup;
+
+       /*
+        * Grab all the resources we need.
+        */
+       newentries = isc_mem_get(adb->mctx, sizeof(*newentries) * n);
+       newdeadentries = isc_mem_get(adb->mctx, sizeof(*newdeadentries) * n);
+       newentrylocks = isc_mem_get(adb->mctx, sizeof(*newentrylocks) * n);
+       newentry_sd = isc_mem_get(adb->mctx, sizeof(*newentry_sd) * n);
+       newentry_refcnt = isc_mem_get(adb->mctx, sizeof(*newentry_refcnt) * n);
+       if (newentries == NULL || newdeadentries == NULL ||
+           newentrylocks == NULL || newentry_sd == NULL ||
+           newentry_refcnt == NULL)
+               goto cleanup;
+
+       /*
+        * Initialise the new resources.
+        */
+       result = isc_mutexblock_init(newentrylocks, n);
+       if (result != ISC_R_SUCCESS)
+               goto cleanup;
+
+       for (i = 0; i < n; i++) {
+               ISC_LIST_INIT(newentries[i]);
+               ISC_LIST_INIT(newdeadentries[i]);
+               newentry_sd[i] = ISC_FALSE;
+               newentry_refcnt[i] = 0;
+               adb->irefcnt++;
+       }
+
+       /*
+        * Move entries to new arrays.
+        */
+       for (i = 0; i < adb->nentries; i++) {
+               e = ISC_LIST_HEAD(adb->entries[i]);
+               while (e != NULL) {
+                       ISC_LIST_UNLINK(adb->entries[i], e, plink);
+                       bucket = isc_sockaddr_hash(&e->sockaddr, ISC_TRUE) % n;
+                       e->lock_bucket = bucket;
+                       ISC_LIST_APPEND(newentries[bucket], e, plink);
+                       INSIST(adb->entry_refcnt[i] > 0);
+                       adb->entry_refcnt[i]--;
+                       newentry_refcnt[bucket]++;
+                       e = ISC_LIST_HEAD(adb->entries[i]);
+               }
+               e = ISC_LIST_HEAD(adb->deadentries[i]);
+               while (e != NULL) {
+                       ISC_LIST_UNLINK(adb->deadentries[i], e, plink);
+                       bucket = isc_sockaddr_hash(&e->sockaddr, ISC_TRUE) % n;
+                       e->lock_bucket = bucket;
+                       ISC_LIST_APPEND(newdeadentries[bucket], e, plink);
+                       INSIST(adb->entry_refcnt[i] > 0);
+                       adb->entry_refcnt[i]--;
+                       newentry_refcnt[bucket]++;
+                       e = ISC_LIST_HEAD(adb->deadentries[i]);
+               }
+               INSIST(adb->entry_refcnt[i] == 0);
+               adb->irefcnt--;
+       }
+
+       /*
+        * Cleanup old resources.
+        */
+       DESTROYMUTEXBLOCK(adb->entrylocks, adb->nentries);
+       isc_mem_put(adb->mctx, adb->entries,
+                   sizeof(*adb->entries) * adb->nentries);
+       isc_mem_put(adb->mctx, adb->deadentries,
+                   sizeof(*adb->deadentries) * adb->nentries);
+       isc_mem_put(adb->mctx, adb->entrylocks,
+                   sizeof(*adb->entrylocks) * adb->nentries);
+       isc_mem_put(adb->mctx, adb->entry_sd,
+                   sizeof(*adb->entry_sd) * adb->nentries);
+       isc_mem_put(adb->mctx, adb->entry_refcnt,
+                   sizeof(*adb->entry_refcnt) * adb->nentries);
+
+       /*
+        * Install new resources.
+        */
+       adb->entries = newentries;
+       adb->deadentries = newdeadentries;
+       adb->entrylocks = newentrylocks;
+       adb->entry_sd = newentry_sd;
+       adb->entry_refcnt = newentry_refcnt;
+       adb->nentries = n;
+
+       /*
+        * Only on success do we set adb->growentries_sent to ISC_FALSE.
+        * This will prevent us being continuously being called on error.
+        */
+       adb->growentries_sent = ISC_FALSE;
+       goto done;
+
+ cleanup:
+       if (newentries != NULL)
+               isc_mem_put(adb->mctx, newentries,
+                           sizeof(*newentries) * n);
+       if (newdeadentries != NULL)
+               isc_mem_put(adb->mctx, newdeadentries,
+                           sizeof(*newdeadentries) * n);
+       if (newentrylocks != NULL)
+               isc_mem_put(adb->mctx, newentrylocks,
+                           sizeof(*newentrylocks) * n);
+       if (newentry_sd != NULL)
+               isc_mem_put(adb->mctx, newentry_sd,
+                           sizeof(*newentry_sd) * n);
+       if (newentry_refcnt != NULL)
+               isc_mem_put(adb->mctx, newentry_refcnt,
+                            sizeof(*newentry_refcnt) * n);
+ done:
+       isc_task_endexclusive(task);
+
+        LOCK(&adb->lock);
+        if (dec_adb_irefcnt(adb))
+                check_exit(adb);
+        UNLOCK(&adb->lock);
+       DP(ISC_LOG_INFO, "adb: grow_entries finished");
+}
+
+static void
+grow_names(isc_task_t *task, isc_event_t *ev) {
+       dns_adb_t *adb;
+       dns_adbname_t *name;
+       dns_adbnamelist_t *newdeadnames = NULL;
+       dns_adbnamelist_t *newnames = NULL;
+       isc_boolean_t *newname_sd = NULL;
+       isc_mutex_t *newnamelocks = NULL;
+       isc_result_t result;
+       unsigned int *newname_refcnt = NULL;
+       unsigned int i, n, bucket;
+       
+       adb = ev->ev_arg;
+       INSIST(DNS_ADB_VALID(adb));
+
+       isc_event_free(&ev);
+
+       isc_task_beginexclusive(task);
+
+       i = 0;
+       while (nbuckets[i] != 0 && adb->nnames >= nbuckets[i])
+               i++;
+       if (nbuckets[i] != 0)
+               n = nbuckets[i];
+       else
+               goto done;
+
+       DP(ISC_LOG_INFO, "adb: grow_names to %u starting", n);
+
+       /*
+        * Are we shutting down?
+        */
+       for (i = 0; i < adb->nnames; i++)
+               if (adb->name_sd[i])
+                       goto cleanup;
+
+       /*
+        * Grab all the resources we need.
+        */
+       newnames = isc_mem_get(adb->mctx, sizeof(*newnames) * n);
+       newdeadnames = isc_mem_get(adb->mctx, sizeof(*newdeadnames) * n);
+       newnamelocks = isc_mem_get(adb->mctx, sizeof(*newnamelocks) * n);
+       newname_sd = isc_mem_get(adb->mctx, sizeof(*newname_sd) * n);
+       newname_refcnt = isc_mem_get(adb->mctx, sizeof(*newname_refcnt) * n);
+       if (newnames == NULL || newdeadnames == NULL ||
+           newnamelocks == NULL || newname_sd == NULL ||
+           newname_refcnt == NULL)
+               goto cleanup;
+
+       /*
+        * Initialise the new resources.
+        */
+       result = isc_mutexblock_init(newnamelocks, n);
+       if (result != ISC_R_SUCCESS)
+               goto cleanup;
+
+       for (i = 0; i < n; i++) {
+               ISC_LIST_INIT(newnames[i]);
+               ISC_LIST_INIT(newdeadnames[i]);
+               newname_sd[i] = ISC_FALSE;
+               newname_refcnt[i] = 0;
+               adb->irefcnt++;
+       }
+
+       /*
+        * Move names to new arrays.
+        */
+       for (i = 0; i < adb->nnames; i++) {
+               name = ISC_LIST_HEAD(adb->names[i]);
+               while (name != NULL) {
+                       ISC_LIST_UNLINK(adb->names[i], name, plink);
+                       bucket = dns_name_fullhash(&name->name, ISC_TRUE) % n;
+                       name->lock_bucket = bucket;
+                       ISC_LIST_APPEND(newnames[bucket], name, plink);
+                       INSIST(adb->name_refcnt[i] > 0);
+                       adb->name_refcnt[i]--;
+                       newname_refcnt[bucket]++;
+                       name = ISC_LIST_HEAD(adb->names[i]);
+               }
+               name = ISC_LIST_HEAD(adb->deadnames[i]);
+               while (name != NULL) {
+                       ISC_LIST_UNLINK(adb->deadnames[i], name, plink);
+                       bucket = dns_name_fullhash(&name->name, ISC_TRUE) % n;
+                       name->lock_bucket = bucket;
+                       ISC_LIST_APPEND(newdeadnames[bucket], name, plink);
+                       INSIST(adb->name_refcnt[i] > 0);
+                       adb->name_refcnt[i]--;
+                       newname_refcnt[bucket]++;
+                       name = ISC_LIST_HEAD(adb->deadnames[i]);
+               }
+               INSIST(adb->name_refcnt[i] == 0);
+               adb->irefcnt--;
+       }
+
+       /*
+        * Cleanup old resources.
+        */
+       DESTROYMUTEXBLOCK(adb->namelocks, adb->nnames);
+       isc_mem_put(adb->mctx, adb->names,
+                   sizeof(*adb->names) * adb->nnames);
+       isc_mem_put(adb->mctx, adb->deadnames,
+                   sizeof(*adb->deadnames) * adb->nnames);
+       isc_mem_put(adb->mctx, adb->namelocks,
+                   sizeof(*adb->namelocks) * adb->nnames);
+       isc_mem_put(adb->mctx, adb->name_sd,
+                   sizeof(*adb->name_sd) * adb->nnames);
+       isc_mem_put(adb->mctx, adb->name_refcnt,
+                   sizeof(*adb->name_refcnt) * adb->nnames);
+
+       /*
+        * Install new resources.
+        */
+       adb->names = newnames;
+       adb->deadnames = newdeadnames;
+       adb->namelocks = newnamelocks;
+       adb->name_sd = newname_sd;
+       adb->name_refcnt = newname_refcnt;
+       adb->nnames = n;
+
+       /*
+        * Only on success do we set adb->grownames_sent to ISC_FALSE.
+        * This will prevent us being continuously being called on error.
+        */
+       adb->grownames_sent = ISC_FALSE;
+       goto done;
+
+ cleanup:
+       if (newnames != NULL)
+               isc_mem_put(adb->mctx, newnames, sizeof(*newnames) * n);
+       if (newdeadnames != NULL)
+               isc_mem_put(adb->mctx, newdeadnames, sizeof(*newdeadnames) * n);
+       if (newnamelocks != NULL)
+               isc_mem_put(adb->mctx, newnamelocks, sizeof(*newnamelocks) * n);
+       if (newname_sd != NULL)
+               isc_mem_put(adb->mctx, newname_sd, sizeof(*newname_sd) * n);
+       if (newname_refcnt != NULL)
+               isc_mem_put(adb->mctx, newname_refcnt,
+                            sizeof(*newname_refcnt) * n);
+ done:
+       isc_task_endexclusive(task);
+
+        LOCK(&adb->lock);
+        if (dec_adb_irefcnt(adb))
+                check_exit(adb);
+        UNLOCK(&adb->lock);
+       DP(ISC_LOG_INFO, "adb: grow_names finished");
+}
+
 /*
  * Requires the adbname bucket be locked and that no entry buckets be locked.
  *
@@ -836,12 +1152,12 @@ violate_locking_hierarchy(isc_mutex_t *have, isc_mutex_t *want) {
  */
 static isc_boolean_t
 shutdown_names(dns_adb_t *adb) {
-       int bucket;
+       unsigned int bucket;
        isc_boolean_t result = ISC_FALSE;
        dns_adbname_t *name;
        dns_adbname_t *next_name;
 
-       for (bucket = 0; bucket < NBUCKETS; bucket++) {
+       for (bucket = 0; bucket < adb->nnames; bucket++) {
                LOCK(&adb->namelocks[bucket]);
                adb->name_sd[bucket] = ISC_TRUE;
 
@@ -881,12 +1197,12 @@ shutdown_names(dns_adb_t *adb) {
  */
 static isc_boolean_t
 shutdown_entries(dns_adb_t *adb) {
-       int bucket;
+       unsigned int bucket;
        isc_boolean_t result = ISC_FALSE;
        dns_adbentry_t *entry;
        dns_adbentry_t *next_entry;
 
-       for (bucket = 0; bucket < NBUCKETS; bucket++) {
+       for (bucket = 0; bucket < adb->nentries; bucket++) {
                LOCK(&adb->entrylocks[bucket]);
                adb->entry_sd[bucket] = ISC_TRUE;
 
@@ -1306,6 +1622,16 @@ new_adbname(dns_adb_t *adb, dns_name_t *dnsname) {
        ISC_LIST_INIT(name->finds);
        ISC_LINK_INIT(name, plink);
 
+       LOCK(&adb->namescntlock);
+       adb->namescnt++;
+       if (!adb->grownames_sent && adb->namescnt > (adb->nnames * 8)) {
+                isc_event_t *event = &adb->grownames;
+               inc_adb_irefcnt(adb);
+                isc_task_send(adb->task, &event);
+               adb->grownames_sent = ISC_TRUE;
+       }
+       UNLOCK(&adb->namescntlock);
+       
        return (name);
 }
 
@@ -1329,6 +1655,9 @@ free_adbname(dns_adb_t *adb, dns_adbname_t **name) {
        dns_name_free(&n->name, adb->mctx);
 
        isc_mempool_put(adb->nmp, n);
+       LOCK(&adb->namescntlock);
+       adb->namescnt--;
+       UNLOCK(&adb->namescntlock);
 }
 
 static inline dns_adbnamehook_t *
@@ -1417,6 +1746,16 @@ new_adbentry(dns_adb_t *adb) {
        e->expires = 0;
        ISC_LIST_INIT(e->lameinfo);
        ISC_LINK_INIT(e, plink);
+       LOCK(&adb->entriescntlock);
+       adb->entriescnt++;
+       if (!adb->growentries_sent &&
+           adb->entriescnt > (adb->nentries * 8)) {
+                isc_event_t *event = &adb->growentries;
+               inc_adb_irefcnt(adb);
+                isc_task_send(adb->task, &event);
+               adb->growentries_sent = ISC_TRUE;
+       }
+       UNLOCK(&adb->entriescntlock);
 
        return (e);
 }
@@ -1444,6 +1783,9 @@ free_adbentry(dns_adb_t *adb, dns_adbentry_t **entry) {
        }
 
        isc_mempool_put(adb->emp, e);
+       LOCK(&adb->entriescntlock);
+       adb->entriescnt--;
+       UNLOCK(&adb->entriescntlock);
 }
 
 static inline dns_adbfind_t *
@@ -1597,7 +1939,7 @@ find_name_and_lock(dns_adb_t *adb, dns_name_t *name,
        dns_adbname_t *adbname;
        int bucket;
 
-       bucket = dns_name_fullhash(name, ISC_FALSE) % NBUCKETS;
+       bucket = dns_name_fullhash(name, ISC_FALSE) % adb->nnames;
 
        if (*bucketp == DNS_ADB_INVALIDBUCKET) {
                LOCK(&adb->namelocks[bucket]);
@@ -1639,7 +1981,7 @@ find_entry_and_lock(dns_adb_t *adb, isc_sockaddr_t *addr, int *bucketp,
        dns_adbentry_t *entry, *entry_next;
        int bucket;
 
-       bucket = isc_sockaddr_hash(addr, ISC_TRUE) % NBUCKETS;
+       bucket = isc_sockaddr_hash(addr, ISC_TRUE) % adb->nentries;
 
        if (*bucketp == DNS_ADB_INVALIDBUCKET) {
                LOCK(&adb->entrylocks[bucket]);
@@ -1992,13 +2334,36 @@ destroy(dns_adb_t *adb) {
        isc_mempool_destroy(&adb->aimp);
        isc_mempool_destroy(&adb->afmp);
 
-       DESTROYMUTEXBLOCK(adb->entrylocks, NBUCKETS);
-       DESTROYMUTEXBLOCK(adb->namelocks, NBUCKETS);
+       DESTROYMUTEXBLOCK(adb->entrylocks, adb->nentries);
+       isc_mem_put(adb->mctx, adb->entries,
+                   sizeof(*adb->entries) * adb->nentries);
+       isc_mem_put(adb->mctx, adb->deadentries,
+                   sizeof(*adb->deadentries) * adb->nentries);
+       isc_mem_put(adb->mctx, adb->entrylocks,
+                   sizeof(*adb->entrylocks) * adb->nentries);
+       isc_mem_put(adb->mctx, adb->entry_sd,
+                   sizeof(*adb->entry_sd) * adb->nentries);
+       isc_mem_put(adb->mctx, adb->entry_refcnt,
+                   sizeof(*adb->entry_refcnt) * adb->nentries);
+
+       DESTROYMUTEXBLOCK(adb->namelocks, adb->nnames);
+       isc_mem_put(adb->mctx, adb->names,
+                   sizeof(*adb->names) * adb->nnames);
+       isc_mem_put(adb->mctx, adb->deadnames,
+                   sizeof(*adb->deadnames) * adb->nnames);
+       isc_mem_put(adb->mctx, adb->namelocks,
+                   sizeof(*adb->namelocks) * adb->nnames);
+       isc_mem_put(adb->mctx, adb->name_sd,
+                   sizeof(*adb->name_sd) * adb->nnames);
+       isc_mem_put(adb->mctx, adb->name_refcnt,
+                   sizeof(*adb->name_refcnt) * adb->nnames);
 
        DESTROYLOCK(&adb->reflock);
        DESTROYLOCK(&adb->lock);
        DESTROYLOCK(&adb->mplock);
        DESTROYLOCK(&adb->overmemlock);
+       DESTROYLOCK(&adb->entriescntlock);
+       DESTROYLOCK(&adb->namescntlock);
 
        isc_mem_putanddetach(&adb->mctx, adb, sizeof(dns_adb_t));
 }
@@ -2014,7 +2379,7 @@ dns_adb_create(isc_mem_t *mem, dns_view_t *view, isc_timermgr_t *timermgr,
 {
        dns_adb_t *adb;
        isc_result_t result;
-       int i;
+       unsigned int i;
 
        REQUIRE(mem != NULL);
        REQUIRE(view != NULL);
@@ -2054,6 +2419,30 @@ dns_adb_create(isc_mem_t *mem, dns_view_t *view, isc_timermgr_t *timermgr,
        adb->shutting_down = ISC_FALSE;
        ISC_LIST_INIT(adb->whenshutdown);
 
+       adb->nentries = nbuckets[0];
+       adb->entriescnt = 0;
+       adb->entries = NULL;
+       adb->deadentries = NULL;
+       adb->entry_sd = NULL;
+       adb->entry_refcnt = NULL;
+       adb->entrylocks = NULL;
+       ISC_EVENT_INIT(&adb->growentries, sizeof(adb->growentries), 0, NULL,
+                      DNS_EVENT_ADBGROWENTRIES, grow_entries, adb,
+                      adb, NULL, NULL);
+       adb->growentries_sent = ISC_FALSE;
+
+       adb->nnames = nbuckets[0];
+       adb->namescnt = 0;
+       adb->names = NULL;
+       adb->deadnames = NULL;
+       adb->name_sd = NULL;
+       adb->name_refcnt = NULL;
+       adb->namelocks = NULL;
+       ISC_EVENT_INIT(&adb->grownames, sizeof(adb->grownames), 0, NULL,
+                      DNS_EVENT_ADBGROWNAMES, grow_names, adb,
+                      adb, NULL, NULL);
+       adb->grownames_sent = ISC_FALSE;
+
        isc_mem_attach(mem, &adb->mctx);
 
        result = isc_mutex_init(&adb->lock);
@@ -2072,28 +2461,68 @@ dns_adb_create(isc_mem_t *mem, dns_view_t *view, isc_timermgr_t *timermgr,
        if (result != ISC_R_SUCCESS)
                goto fail0e;
 
+       result = isc_mutex_init(&adb->entriescntlock);
+       if (result != ISC_R_SUCCESS)
+               goto fail0f;
+
+       result = isc_mutex_init(&adb->namescntlock);
+       if (result != ISC_R_SUCCESS)
+               goto fail0g;
+
+#define ALLOCENTRY(adb, el) \
+       do { \
+               (adb)->el = isc_mem_get((adb)->mctx, \
+                                    sizeof(*(adb)->el) * (adb)->nentries); \
+               if ((adb)->el == NULL) { \
+                       result = ISC_R_NOMEMORY; \
+                       goto fail1; \
+               }\
+       } while (0)
+       ALLOCENTRY(adb, entries);
+       ALLOCENTRY(adb, deadentries);
+       ALLOCENTRY(adb, entrylocks);
+       ALLOCENTRY(adb, entry_sd);
+       ALLOCENTRY(adb, entry_refcnt);
+#undef ALLOCENTRY
+
+#define ALLOCNAME(adb, el) \
+       do { \
+               (adb)->el = isc_mem_get((adb)->mctx, \
+                                    sizeof(*(adb)->el) * (adb)->nnames); \
+               if ((adb)->el == NULL) { \
+                       result = ISC_R_NOMEMORY; \
+                       goto fail1; \
+               }\
+       } while (0)
+       ALLOCNAME(adb, names);
+       ALLOCNAME(adb, deadnames);
+       ALLOCNAME(adb, namelocks);
+       ALLOCNAME(adb, name_sd);
+       ALLOCNAME(adb, name_refcnt);
+#undef ALLOCNAME
+
        /*
         * Initialize the bucket locks for names and elements.
         * May as well initialize the list heads, too.
         */
-       result = isc_mutexblock_init(adb->namelocks, NBUCKETS);
+       result = isc_mutexblock_init(adb->namelocks, adb->nnames);
        if (result != ISC_R_SUCCESS)
                goto fail1;
-       for (i = 0; i < NBUCKETS; i++) {
+       for (i = 0; i < adb->nnames; i++) {
                ISC_LIST_INIT(adb->names[i]);
                ISC_LIST_INIT(adb->deadnames[i]);
                adb->name_sd[i] = ISC_FALSE;
                adb->name_refcnt[i] = 0;
                adb->irefcnt++;
        }
-       for (i = 0; i < NBUCKETS; i++) {
+       for (i = 0; i < adb->nentries; i++) {
                ISC_LIST_INIT(adb->entries[i]);
                ISC_LIST_INIT(adb->deadentries[i]);
                adb->entry_sd[i] = ISC_FALSE;
                adb->entry_refcnt[i] = 0;
                adb->irefcnt++;
        }
-       result = isc_mutexblock_init(adb->entrylocks, NBUCKETS);
+       result = isc_mutexblock_init(adb->entrylocks, adb->nentries);
        if (result != ISC_R_SUCCESS)
                goto fail2;
 
@@ -2140,12 +2569,42 @@ dns_adb_create(isc_mem_t *mem, dns_view_t *view, isc_timermgr_t *timermgr,
                isc_task_detach(&adb->task);
 
        /* clean up entrylocks */
-       DESTROYMUTEXBLOCK(adb->entrylocks, NBUCKETS);
+       DESTROYMUTEXBLOCK(adb->entrylocks, adb->nentries);
 
  fail2: /* clean up namelocks */
-       DESTROYMUTEXBLOCK(adb->namelocks, NBUCKETS);
+       DESTROYMUTEXBLOCK(adb->namelocks, adb->nnames);
 
  fail1: /* clean up only allocated memory */
+       if (adb->entries != NULL)
+               isc_mem_put(adb->mctx, adb->entries,
+                           sizeof(*adb->entries) * adb->nentries);
+       if (adb->deadentries != NULL)
+               isc_mem_put(adb->mctx, adb->deadentries,
+                           sizeof(*adb->deadentries) * adb->nentries);
+       if (adb->entrylocks != NULL)
+               isc_mem_put(adb->mctx, adb->entrylocks,
+                           sizeof(*adb->entrylocks) * adb->nentries);
+       if (adb->entry_sd != NULL)
+               isc_mem_put(adb->mctx, adb->entry_sd,
+                           sizeof(*adb->entry_sd) * adb->nentries);
+       if (adb->entry_refcnt != NULL)
+               isc_mem_put(adb->mctx, adb->entry_refcnt,
+                           sizeof(*adb->entry_refcnt) * adb->nentries);
+       if (adb->names != NULL)
+               isc_mem_put(adb->mctx, adb->names,
+                           sizeof(*adb->names) * adb->nnames);
+       if (adb->deadnames != NULL)
+               isc_mem_put(adb->mctx, adb->deadnames,
+                           sizeof(*adb->deadnames) * adb->nnames);
+       if (adb->namelocks != NULL)
+               isc_mem_put(adb->mctx, adb->namelocks,
+                           sizeof(*adb->namelocks) * adb->nnames);
+       if (adb->name_sd != NULL)
+               isc_mem_put(adb->mctx, adb->name_sd,
+                           sizeof(*adb->name_sd) * adb->nnames);
+       if (adb->name_refcnt != NULL)
+               isc_mem_put(adb->mctx, adb->name_refcnt,
+                           sizeof(*adb->name_refcnt) * adb->nnames);
        if (adb->nmp != NULL)
                isc_mempool_destroy(&adb->nmp);
        if (adb->nhmp != NULL)
@@ -2161,6 +2620,10 @@ dns_adb_create(isc_mem_t *mem, dns_view_t *view, isc_timermgr_t *timermgr,
        if (adb->afmp != NULL)
                isc_mempool_destroy(&adb->afmp);
 
+       DESTROYLOCK(&adb->namescntlock);
+ fail0g:
+       DESTROYLOCK(&adb->entriescntlock);
+ fail0f:
        DESTROYLOCK(&adb->overmemlock);
  fail0e:
        DESTROYLOCK(&adb->reflock);
@@ -2728,7 +3191,7 @@ dns_adb_cancelfind(dns_adbfind_t *find) {
 
 void
 dns_adb_dump(dns_adb_t *adb, FILE *f) {
-       int i;
+       unsigned int i;
        isc_stdtime_t now;
 
        REQUIRE(DNS_ADB_VALID(adb));
@@ -2744,9 +3207,9 @@ dns_adb_dump(dns_adb_t *adb, FILE *f) {
        LOCK(&adb->lock);
        isc_stdtime_get(&now);
 
-       for (i = 0; i < NBUCKETS; i++)
+       for (i = 0; i < adb->nnames; i++)
                RUNTIME_CHECK(cleanup_names(adb, i, now) == ISC_FALSE);
-       for (i = 0; i < NBUCKETS; i++)
+       for (i = 0; i < adb->nentries; i++)
                RUNTIME_CHECK(cleanup_entries(adb, i, now) == ISC_FALSE);
 
        dump_adb(adb, f, ISC_FALSE, now);
@@ -2762,7 +3225,7 @@ dump_ttl(FILE *f, const char *legend, isc_stdtime_t value, isc_stdtime_t now) {
 
 static void
 dump_adb(dns_adb_t *adb, FILE *f, isc_boolean_t debug, isc_stdtime_t now) {
-       int i;
+       unsigned int i;
        dns_adbname_t *name;
        dns_adbentry_t *entry;
 
@@ -2772,15 +3235,15 @@ dump_adb(dns_adb_t *adb, FILE *f, isc_boolean_t debug, isc_stdtime_t now) {
                        adb, adb->erefcnt, adb->irefcnt,
                        isc_mempool_getallocated(adb->nhmp));
 
-       for (i = 0; i < NBUCKETS; i++)
+       for (i = 0; i < adb->nnames; i++)
                LOCK(&adb->namelocks[i]);
-       for (i = 0; i < NBUCKETS; i++)
+       for (i = 0; i < adb->nentries; i++)
                LOCK(&adb->entrylocks[i]);
 
        /*
         * Dump the names
         */
-       for (i = 0; i < NBUCKETS; i++) {
+       for (i = 0; i < adb->nnames; i++) {
                name = ISC_LIST_HEAD(adb->names[i]);
                if (name == NULL)
                        continue;
@@ -2824,7 +3287,7 @@ dump_adb(dns_adb_t *adb, FILE *f, isc_boolean_t debug, isc_stdtime_t now) {
 
        fprintf(f, ";\n; Unassociated entries\n;\n");
 
-       for (i = 0; i < NBUCKETS; i++) {
+       for (i = 0; i < adb->nentries; i++) {
                entry = ISC_LIST_HEAD(adb->entries[i]);
                while (entry != NULL) {
                        if (entry->refcnt == 0)
@@ -2836,9 +3299,9 @@ dump_adb(dns_adb_t *adb, FILE *f, isc_boolean_t debug, isc_stdtime_t now) {
        /*
         * Unlock everything
         */
-       for (i = 0; i < NBUCKETS; i++)
+       for (i = 0; i < adb->nentries; i++)
                UNLOCK(&adb->entrylocks[i]);
-       for (i = 0; i < NBUCKETS; i++)
+       for (i = 0; i < adb->nnames; i++)
                UNLOCK(&adb->namelocks[i]);
 }
 
@@ -3567,9 +4030,9 @@ dns_adb_flush(dns_adb_t *adb) {
        /*
         * Call our cleanup routines.
         */
-       for (i = 0; i < NBUCKETS; i++)
+       for (i = 0; i < adb->nnames; i++)
                RUNTIME_CHECK(cleanup_names(adb, i, INT_MAX) == ISC_FALSE);
-       for (i = 0; i < NBUCKETS; i++)
+       for (i = 0; i < adb->nentries; i++)
                RUNTIME_CHECK(cleanup_entries(adb, i, INT_MAX) == ISC_FALSE);
 
 #ifdef DUMP_ADB_AFTER_CLEANING
@@ -3588,7 +4051,7 @@ dns_adb_flushname(dns_adb_t *adb, dns_name_t *name) {
        INSIST(DNS_ADB_VALID(adb));
 
        LOCK(&adb->lock);
-       bucket = dns_name_hash(name, ISC_FALSE) % NBUCKETS;
+       bucket = dns_name_hash(name, ISC_FALSE) % adb->nnames;
        LOCK(&adb->namelocks[bucket]);
        adbname = ISC_LIST_HEAD(adb->names[bucket]);
        while (adbname != NULL) {
index 9b6d1636e9beaeae3933e63ea049f1ea7cbc725f..48b78b6dfb3141cf092c302533ab9c8e7cecc144 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: events.h,v 1.55 2010/05/10 23:50:55 tbox Exp $ */
+/* $Id: events.h,v 1.56 2010/12/21 03:11:42 marka Exp $ */
 
 #ifndef DNS_EVENTS_H
 #define DNS_EVENTS_H 1
@@ -72,6 +72,8 @@
 #define DNS_EVENT_MANAGEKEYS                   (ISC_EVENTCLASS_DNS + 42)
 #define DNS_EVENT_CLIENTRESDONE                        (ISC_EVENTCLASS_DNS + 43)
 #define DNS_EVENT_CLIENTREQDONE                        (ISC_EVENTCLASS_DNS + 44)
+#define DNS_EVENT_ADBGROWENTRIES               (ISC_EVENTCLASS_DNS + 45)
+#define DNS_EVENT_ADBGROWNAMES                 (ISC_EVENTCLASS_DNS + 46)
 
 #define DNS_EVENT_FIRSTEVENT                   (ISC_EVENTCLASS_DNS + 0)
 #define DNS_EVENT_LASTEVENT                    (ISC_EVENTCLASS_DNS + 65535)