]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
2881. [bug] Reduce the amount of time the rbtdb write lock
authorMark Andrews <marka@isc.org>
Mon, 10 May 2010 01:39:03 +0000 (01:39 +0000)
committerMark Andrews <marka@isc.org>
Mon, 10 May 2010 01:39:03 +0000 (01:39 +0000)
                        is held when closing a version. [RT #21198]

CHANGES
lib/dns/include/dns/events.h
lib/dns/rbtdb.c

diff --git a/CHANGES b/CHANGES
index 37fd484e0b1a08fa61af00709788194633239a1d..d70340ce78a1446a8d5ab4f8f78c664993e4ac66 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,6 @@
+2881.  [bug]           Reduce the amount of time the rbtdb write lock
+                       is held when closing a version. [RT #21198]
+
 2880.  [cleanup]       Make the output of dnssec-keygen and dnssec-revoke
                        consistent. [RT #21078]
 
index c92f44be0203e4005ce9aea8582a5b5e735c6bfe..ca9257913d9fb58b1794ef939bef72d89cfe9420 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: events.h,v 1.53 2009/09/01 00:22:26 jinmei Exp $ */
+/* $Id: events.h,v 1.54 2010/05/10 01:39:03 marka Exp $ */
 
 #ifndef DNS_EVENTS_H
 #define DNS_EVENTS_H 1
@@ -58,7 +58,7 @@
 #define DNS_EVENT_MASTERNEXTZONE               (ISC_EVENTCLASS_DNS + 28)
 #define DNS_EVENT_IOREADY                      (ISC_EVENTCLASS_DNS + 29)
 #define DNS_EVENT_LOOKUPDONE                   (ISC_EVENTCLASS_DNS + 30)
-/* #define DNS_EVENT_unused                    (ISC_EVENTCLASS_DNS + 31) */
+#define DNS_EVENT_RBTDEADNODES                 (ISC_EVENTCLASS_DNS + 31)
 #define DNS_EVENT_DISPATCHCONTROL              (ISC_EVENTCLASS_DNS + 32)
 #define DNS_EVENT_REQUESTCONTROL               (ISC_EVENTCLASS_DNS + 33)
 #define DNS_EVENT_DUMPQUANTUM                  (ISC_EVENTCLASS_DNS + 34)
index f7f27531cd664f509ee49adeb6368cc291581708..f453ad1fc2d4cc75f86f0d00ee94d54dd7424ef5 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: rbtdb.c,v 1.300 2010/02/26 00:18:06 marka Exp $ */
+/* $Id: rbtdb.c,v 1.301 2010/05/10 01:39:03 marka Exp $ */
 
 /*! \file */
 
@@ -2109,6 +2109,34 @@ setnsec3parameters(dns_db_t *db, rbtdb_version_t *version) {
 }
 #endif
 
+static void
+cleanup_dead_nodes_callback(isc_task_t *task, isc_event_t *event) {
+       dns_rbtdb_t *rbtdb = event->ev_arg;
+       isc_boolean_t again = ISC_FALSE;
+       unsigned int locknum;
+       unsigned int refs;
+
+       RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_write);
+       for (locknum = 0; locknum < rbtdb->node_lock_count; locknum++) {
+               NODE_LOCK(&rbtdb->node_locks[locknum].lock,
+                         isc_rwlocktype_write);
+               cleanup_dead_nodes(rbtdb, locknum);
+               if (ISC_LIST_HEAD(rbtdb->deadnodes[locknum]) != NULL)
+                       again = ISC_TRUE;
+               NODE_UNLOCK(&rbtdb->node_locks[locknum].lock,
+                           isc_rwlocktype_write);
+       }
+       RBTDB_UNLOCK(&rbtdb->lock, isc_rwlocktype_write);
+       if (again)
+               isc_task_send(task, &event);
+       else {
+               isc_event_free(&event);
+               isc_refcount_decrement(&rbtdb->references, &refs);
+               if (refs == 0)
+                       maybe_free_rbtdb(rbtdb);
+       }
+}
+
 static void
 closeversion(dns_db_t *db, dns_dbversion_t **versionp, isc_boolean_t commit) {
        dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
@@ -2309,15 +2337,28 @@ closeversion(dns_db_t *db, dns_dbversion_t **versionp, isc_boolean_t commit) {
        }
 
        if (!EMPTY(cleanup_list)) {
-               /*
-                * We acquire a tree write lock here in order to make sure
-                * that stale nodes will be removed in decrement_reference().
-                * If we didn't have the lock, those nodes could miss the
-                * chance to be removed until the server stops.  The write lock
-                * is expensive, but this event should be rare enough to justify
-                * the cost.
-                */
-               RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_write);
+               isc_event_t *event = NULL;
+               isc_rwlocktype_t tlock = isc_rwlocktype_none;
+
+               if (rbtdb->task != NULL)
+                       event = isc_event_allocate(rbtdb->common.mctx, NULL,
+                                                  DNS_EVENT_RBTDEADNODES,
+                                                  cleanup_dead_nodes_callback,
+                                                  rbtdb, sizeof(isc_event_t));
+               if (event == NULL) {
+                       /*
+                        * We acquire a tree write lock here in order to make
+                        * sure that stale nodes will be removed in
+                        * decrement_reference().  If we didn't have the lock,
+                        * those nodes could miss the chance to be removed
+                        * until the server stops.  The write lock is
+                        * expensive, but this event should be rare enough
+                        * to justify the cost.
+                        */
+                       RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_write);
+                       tlock = isc_rwlocktype_write;
+               }
+
                for (changed = HEAD(cleanup_list);
                     changed != NULL;
                     changed = next_changed) {
@@ -2332,20 +2373,25 @@ closeversion(dns_db_t *db, dns_dbversion_t **versionp, isc_boolean_t commit) {
                         * This is a good opportunity to purge any dead nodes,
                         * so use it.
                         */
-                       cleanup_dead_nodes(rbtdb, rbtnode->locknum);
+                       if (event == NULL)
+                               cleanup_dead_nodes(rbtdb, rbtnode->locknum);
 
                        if (rollback)
                                rollback_node(rbtnode, serial);
                        decrement_reference(rbtdb, rbtnode, least_serial,
-                                           isc_rwlocktype_write,
-                                           isc_rwlocktype_write, ISC_FALSE);
+                                           isc_rwlocktype_write, tlock,
+                                           ISC_FALSE);
 
                        NODE_UNLOCK(lock, isc_rwlocktype_write);
 
                        isc_mem_put(rbtdb->common.mctx, changed,
                                    sizeof(*changed));
                }
-               RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_write);
+               if (event != NULL) {
+                       isc_refcount_increment(&rbtdb->references, NULL);
+                       isc_task_send(rbtdb->task, &event);
+               } else
+                       RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_write);
        }
 
  end: