From: Mark Andrews Date: Mon, 10 May 2010 01:39:03 +0000 (+0000) Subject: 2881. [bug] Reduce the amount of time the rbtdb write lock X-Git-Tag: v9.4-ESV-R3~51^2~101 X-Git-Url: http://git.ipfire.org/gitweb/?a=commitdiff_plain;h=121f783b6660f2cb49829bdc51eb522fd327437e;p=thirdparty%2Fbind9.git 2881. [bug] Reduce the amount of time the rbtdb write lock is held when closing a version. [RT #21198] --- diff --git a/CHANGES b/CHANGES index 37fd484e0b1..d70340ce78a 100644 --- 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] diff --git a/lib/dns/include/dns/events.h b/lib/dns/include/dns/events.h index c92f44be020..ca9257913d9 100644 --- a/lib/dns/include/dns/events.h +++ b/lib/dns/include/dns/events.h @@ -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) diff --git a/lib/dns/rbtdb.c b/lib/dns/rbtdb.c index f7f27531cd6..f453ad1fc2d 100644 --- a/lib/dns/rbtdb.c +++ b/lib/dns/rbtdb.c @@ -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: