Commit a0384825 authored by Mark Andrews's avatar Mark Andrews
Browse files

1580. [bug] Zone destuction on final detach takes a long time.

                        [RT #3746]

1579.   [bug]           Multiple task managers could not be created.
parent 1285fa26
......@@ -17,9 +17,10 @@
1581. [func] Disable DNSSEC support by default. To enable
DNSSEC specify "enable-dnssec yes;" in named.conf.
1580. [placeholder] rt3746a
1580. [bug] Zone destuction on final detach takes a long time.
[RT #3746]
1579. [placeholder] rt3746a
1579. [bug] Multiple task managers could not be created.
1578. [bug] Don't use CLASS E IPv4 addresses when resolving.
[RT #10346]
......
......@@ -15,7 +15,7 @@
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: db.c,v 1.72 2003/10/03 03:12:35 marka Exp $ */
/* $Id: db.c,v 1.73 2004/03/04 06:56:38 marka Exp $ */
/***
*** Imports
......@@ -730,6 +730,13 @@ dns_db_nodecount(dns_db_t *db) {
return ((db->methods->nodecount)(db));
}
void
dns_db_settask(dns_db_t *db, isc_task_t *task) {
REQUIRE(DNS_DB_VALID(db));
(db->methods->settask)(db, task);
}
isc_result_t
dns_db_register(const char *name, dns_dbcreatefunc_t create, void *driverarg,
isc_mem_t *mctx, dns_dbimplementation_t **dbimp)
......
......@@ -15,7 +15,7 @@
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: db.h,v 1.74 2003/10/03 03:12:35 marka Exp $ */
/* $Id: db.h,v 1.75 2004/03/04 06:56:40 marka Exp $ */
#ifndef DNS_DB_H
#define DNS_DB_H 1
......@@ -144,6 +144,7 @@ typedef struct dns_dbmethods {
unsigned int (*nodecount)(dns_db_t *db);
isc_boolean_t (*ispersistent)(dns_db_t *db);
void (*overmem)(dns_db_t *db, isc_boolean_t overmem);
void (*settask)(dns_db_t *db, isc_task_t *);
} dns_dbmethods_t;
typedef isc_result_t
......@@ -1189,6 +1190,16 @@ dns_db_nodecount(dns_db_t *db);
* The number of nodes in the database
*/
void
dns_db_settask(dns_db_t *db, isc_task_t *task);
/*
* If task is set then the final detach maybe performed asynchronously.
*
* Requires:
* 'db' is a valid database.
* 'task' to be valid or NULL.
*/
isc_boolean_t
dns_db_ispersistent(dns_db_t *db);
/*
......
......@@ -15,7 +15,7 @@
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: events.h,v 1.40 2002/09/04 02:26:13 jinmei Exp $ */
/* $Id: events.h,v 1.41 2004/03/04 06:56:40 marka Exp $ */
#ifndef DNS_EVENTS_H
#define DNS_EVENTS_H 1
......@@ -62,6 +62,7 @@
#define DNS_EVENT_REQUESTCONTROL (ISC_EVENTCLASS_DNS + 33)
#define DNS_EVENT_DUMPQUANTUM (ISC_EVENTCLASS_DNS + 34)
#define DNS_EVENT_IMPORTRECVDONE (ISC_EVENTCLASS_DNS + 35)
#define DNS_EVENT_FREESTORAGE (ISC_EVENTCLASS_DNS + 36)
#define DNS_EVENT_FIRSTEVENT (ISC_EVENTCLASS_DNS + 0)
#define DNS_EVENT_LASTEVENT (ISC_EVENTCLASS_DNS + 65535)
......
......@@ -15,7 +15,7 @@
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: rbt.h,v 1.57 2002/12/31 05:40:15 marka Exp $ */
/* $Id: rbt.h,v 1.58 2004/03/04 06:56:40 marka Exp $ */
#ifndef DNS_RBT_H
#define DNS_RBT_H 1
......@@ -600,8 +600,13 @@ dns_rbt_nodecount(dns_rbt_t *rbt);
void
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. Once dns_rbt_destroy2()
* has been called on a 'rbt' only dns_rbt_destroy() or dns_rbt_destroy2()
* may be used on the tree. If 'quantum' is zero then the entire tree will
* be destroyed.
*
* Requires:
* *rbt is a valid rbt manager.
......@@ -610,6 +615,10 @@ dns_rbt_destroy(dns_rbt_t **rbtp);
* All space allocated by the RBT library has been returned.
*
* *rbt is invalidated as an rbt manager.
*
* Returns:
* ISC_R_SUCCESS
* ISC_R_QUOTA if 'quantum' nodes have been destroyed.
*/
void
......
......@@ -15,13 +15,14 @@
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: rbt.c,v 1.126 2004/03/03 22:40:56 marka Exp $ */
/* $Id: rbt.c,v 1.127 2004/03/04 06:56:39 marka Exp $ */
/* Principal Authors: DCL */
#include <config.h>
#include <isc/mem.h>
#include <isc/platform.h>
#include <isc/print.h>
#include <isc/string.h>
#include <isc/util.h>
......@@ -63,6 +64,7 @@ struct dns_rbt {
unsigned int nodecount;
unsigned int hashsize;
dns_rbtnode_t ** hashtable;
unsigned int quantum;
};
#define RED 0
......@@ -225,9 +227,12 @@ 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);
static void
static isc_result_t
dns_rbt_deletetree(dns_rbt_t *rbt, dns_rbtnode_t *node);
static void
dns_rbt_deletetreeflat(dns_rbt_t *rbt, dns_rbtnode_t **nodep);
/*
* Initialize a red/black tree of trees.
*/
......@@ -263,6 +268,7 @@ dns_rbt_create(isc_mem_t *mctx, void (*deleter)(void *, void *),
return (result);
}
#endif
rbt->quantum = 0;
rbt->magic = RBT_MAGIC;
*rbtp = rbt;
......@@ -275,13 +281,22 @@ 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);
}
isc_result_t
dns_rbt_destroy2(dns_rbt_t **rbtp, unsigned int quantum) {
dns_rbt_t *rbt;
REQUIRE(rbtp != NULL && VALID_RBT(*rbtp));
rbt = *rbtp;
dns_rbt_deletetree(rbt, rbt->root);
rbt->quantum = quantum;
dns_rbt_deletetreeflat(rbt, &rbt->root);
if (rbt->root != NULL)
return (ISC_R_QUOTA);
INSIST(rbt->nodecount == 0);
......@@ -292,8 +307,8 @@ dns_rbt_destroy(dns_rbt_t **rbtp) {
rbt->magic = 0;
isc_mem_put(rbt->mctx, rbt, sizeof(*rbt));
*rbtp = NULL;
return (ISC_R_SUCCESS);
}
unsigned int
......@@ -1258,7 +1273,8 @@ dns_rbt_deletenode(dns_rbt_t *rbt, dns_rbtnode_t *node, isc_boolean_t recurse)
if (DOWN(node) != NULL) {
if (recurse)
dns_rbt_deletetree(rbt, DOWN(node));
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),
......@@ -1527,7 +1543,7 @@ hash_node(dns_rbt_t *rbt, dns_rbtnode_t *node) {
REQUIRE(DNS_RBTNODE_VALID(node));
if (rbt->nodecount >= rbt->hashsize)
if (rbt->nodecount >= (rbt->hashsize *3))
rehash(rbt);
hash_add_node(rbt, node);
......@@ -1976,19 +1992,75 @@ dns_rbt_deletefromlevel(dns_rbtnode_t *delete, dns_rbtnode_t **rootp) {
* a pointer needs to be told that this tree no longer exists,
* this function would need to adjusted accordingly.
*/
static void
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;
}
done:
if (result != ISC_R_SUCCESS)
return (result);
if (rbt->quantum != 0 && --rbt->quantum == 0)
return (ISC_R_QUOTA);
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;
#endif
isc_mem_put(rbt->mctx, node, NODE_SIZE(node));
rbt->nodecount--;
return (result);
}
static void
dns_rbt_deletetreeflat(dns_rbt_t *rbt, dns_rbtnode_t **nodep) {
dns_rbtnode_t *parent;
dns_rbtnode_t *node = *nodep;
REQUIRE(VALID_RBT(rbt));
again:
if (node == NULL) {
*nodep = NULL;
return;
}
if (LEFT(node) != NULL)
dns_rbt_deletetree(rbt, LEFT(node));
if (RIGHT(node) != NULL)
dns_rbt_deletetree(rbt, RIGHT(node));
if (DOWN(node) != NULL)
dns_rbt_deletetree(rbt, DOWN(node));
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);
......@@ -1997,8 +2069,23 @@ dns_rbt_deletetree(dns_rbt_t *rbt, dns_rbtnode_t *node) {
#if DNS_RBT_USEMAGIC
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 (rbt->quantum != 0 && --rbt->quantum == 0) {
*nodep = node;
return;
}
goto again;
}
static void
......
......@@ -15,7 +15,7 @@
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: rbtdb.c,v 1.194 2004/03/04 02:46:28 marka Exp $ */
/* $Id: rbtdb.c,v 1.195 2004/03/04 06:56:39 marka Exp $ */
/*
* Principal Author: Bob Halley
......@@ -23,6 +23,7 @@
#include <config.h>
#include <isc/event.h>
#include <isc/mem.h>
#include <isc/print.h>
#include <isc/mutex.h>
......@@ -30,10 +31,12 @@
#include <isc/refcount.h>
#include <isc/rwlock.h>
#include <isc/string.h>
#include <isc/task.h>
#include <isc/util.h>
#include <dns/db.h>
#include <dns/dbiterator.h>
#include <dns/events.h>
#include <dns/fixedname.h>
#include <dns/log.h>
#include <dns/masterdump.h>
......@@ -215,6 +218,7 @@ typedef struct {
rbtdb_version_t * future_version;
rbtdb_versionlist_t open_versions;
isc_boolean_t overmem;
isc_task_t * task;
/* Locked by tree_lock. */
dns_rbt_t * tree;
isc_boolean_t secure;
......@@ -339,6 +343,9 @@ typedef struct rbtdb_dbiterator {
#define IS_STUB(rbtdb) (((rbtdb)->common.attributes & DNS_DBATTR_STUB) != 0)
#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);
/*
* Locking
*
......@@ -382,10 +389,20 @@ attach(dns_db_t *source, dns_db_t **targetp) {
}
static void
free_rbtdb(dns_rbtdb_t *rbtdb) {
free_rbtdb_callback(isc_task_t *task, isc_event_t *event) {
dns_rbtdb_t *rbtdb = event->ev_arg;
UNUSED(task);
free_rbtdb(rbtdb, ISC_TRUE, event);
}
static void
free_rbtdb(dns_rbtdb_t *rbtdb, isc_boolean_t log, isc_event_t *event) {
unsigned int i;
isc_ondestroy_t ondest;
isc_mem_t *mctx;
isc_result_t result;
char buf[DNS_NAME_FORMATSIZE];
REQUIRE(EMPTY(rbtdb->open_versions));
REQUIRE(rbtdb->future_version == NULL);
......@@ -393,23 +410,53 @@ free_rbtdb(dns_rbtdb_t *rbtdb) {
if (rbtdb->current_version != NULL)
isc_mem_put(rbtdb->common.mctx, rbtdb->current_version,
sizeof(rbtdb_version_t));
again:
if (rbtdb->tree != NULL) {
result = dns_rbt_destroy2(&rbtdb->tree,
(rbtdb->task != NULL) ? 5 : 0);
if (result == ISC_R_QUOTA) {
INSIST(rbtdb->task != NULL);
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);
if (rbtdb->tree != NULL)
dns_rbt_destroy(&rbtdb->tree);
for (i = 0; i < rbtdb->node_lock_count; i++)
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);
DESTROYLOCK(&rbtdb->lock);
rbtdb->common.magic = 0;
rbtdb->common.impmagic = 0;
ondest = rbtdb->common.ondest;
mctx = rbtdb->common.mctx;
isc_mem_put(mctx, rbtdb, sizeof(*rbtdb));
isc_mem_detach(&mctx);
isc_mem_putanddetach(&rbtdb->common.mctx, rbtdb, sizeof(*rbtdb));
isc_ondestroy_notify(&ondest, rbtdb);
}
......@@ -439,8 +486,18 @@ maybe_free_rbtdb(dns_rbtdb_t *rbtdb) {
if (rbtdb->active == 0)
want_free = ISC_TRUE;
UNLOCK(&rbtdb->lock);
if (want_free)
free_rbtdb(rbtdb);
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);
}
}
}
......@@ -3166,8 +3223,18 @@ detachnode(dns_db_t *db, dns_dbnode_t **targetp) {
if (rbtdb->active == 0)
want_free = ISC_TRUE;
UNLOCK(&rbtdb->lock);
if (want_free)
free_rbtdb(rbtdb);
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);
}
}
}
......@@ -4552,6 +4619,22 @@ nodecount(dns_db_t *db) {
return (count);
}
static void
settask(dns_db_t *db, isc_task_t *task) {
dns_rbtdb_t *rbtdb;
rbtdb = (dns_rbtdb_t *)db;
REQUIRE(VALID_RBTDB(rbtdb));
LOCK(&rbtdb->lock);
if (rbtdb->task != NULL)
isc_task_detach(&rbtdb->task);
if (task != NULL)
isc_task_attach(task, &rbtdb->task);
UNLOCK(&rbtdb->lock);
}
static isc_boolean_t
ispersistent(dns_db_t *db) {
UNUSED(db);
......@@ -4584,7 +4667,8 @@ static dns_dbmethods_t zone_methods = {
issecure,
nodecount,
ispersistent,
overmem
overmem,
settask
};
static dns_dbmethods_t cache_methods = {
......@@ -4613,7 +4697,8 @@ static dns_dbmethods_t cache_methods = {
issecure,
nodecount,
ispersistent,
overmem
overmem,
settask
};
isc_result_t
......@@ -4714,7 +4799,7 @@ dns_rbtdb_create
*/
result = dns_name_dupwithoffsets(origin, mctx, &rbtdb->common.origin);
if (result != ISC_R_SUCCESS) {
free_rbtdb(rbtdb);
free_rbtdb(rbtdb, ISC_FALSE, NULL);
return (result);
}
......@@ -4723,7 +4808,7 @@ dns_rbtdb_create
*/
result = dns_rbt_create(mctx, delete_callback, rbtdb, &rbtdb->tree);
if (result != ISC_R_SUCCESS) {
free_rbtdb(rbtdb);
free_rbtdb(rbtdb, ISC_FALSE, NULL);
return (result);
}
/*
......@@ -4745,7 +4830,7 @@ dns_rbtdb_create
&rbtdb->origin_node);
if (result != ISC_R_SUCCESS) {
INSIST(result != ISC_R_EXISTS);
free_rbtdb(rbtdb);
free_rbtdb(rbtdb, ISC_FALSE, NULL);
return (result);
}
/*
......@@ -4771,6 +4856,7 @@ dns_rbtdb_create
rbtdb->attributes = 0;
rbtdb->secure = ISC_FALSE;
rbtdb->overmem = ISC_FALSE;
rbtdb->task = NULL;
/*
* Version Initialization.
......@@ -4780,7 +4866,7 @@ dns_rbtdb_create
rbtdb->next_serial = 2;
rbtdb->current_version = allocate_version(mctx, 1, 0, ISC_FALSE);
if (rbtdb->current_version == NULL) {
free_rbtdb(rbtdb);
free_rbtdb(rbtdb, ISC_FALSE, NULL);
return (ISC_R_NOMEMORY);
}
rbtdb->future_version = NULL;
......
......@@ -15,7 +15,7 @@
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: sdb.c,v 1.43 2004/02/27 20:41:44 marka Exp $ */
/* $Id: sdb.c,v 1.44 2004/03/04 06:56:39 marka Exp $ */
#include <config.h>
......@@ -1200,6 +1200,12 @@ overmem(dns_db_t *db, isc_boolean_t overmem) {
UNUSED(overmem);
}
static void
settask(dns_db_t *db, isc_task_t *task) {
UNUSED(db);
UNUSED(task);
}
static dns_dbmethods_t sdb_methods = {
attach,
......@@ -1227,7 +1233,8 @@ static dns_dbmethods_t sdb_methods = {
issecure,
nodecount,
ispersistent,
overmem
overmem,
settask
};
static isc_result_t
......
......@@ -15,7 +15,7 @@
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: zone.c,v 1.407 2004/03/02 02:37:11 marka Exp $ */
/* $Id: zone.c,v 1.408 2004/03/04 06:56:39 marka Exp $ */
#include <config.h>
......@@ -1046,6 +1046,7 @@ zone_load(dns_zone_t *zone, unsigned int flags) {
isc_result_totext(result));
goto cleanup;
}
dns_db_settask(db, zone->task);
if (! dns_db_ispersistent(db)) {
if (zone->masterfile != NULL) {
......@@ -4049,6 +4050,7 @@ ns_query(dns_zone_t *zone, dns_rdataset_t *soardataset, dns_stub_t *stub) {
dns_result_totext(result));
goto cleanup;
}
dns_db_settask(stub->db, zone->task);
}
dns_db_newversion(stub->db, &stub->version);
......@@ -5079,6 +5081,8 @@ dns_zone_settask(dns_zone_t *zone, isc_task_t *task) {
if (zone->task != NULL)
isc_task_detach(&zone->task);
isc_task_attach(task, &zone->task);
if (zone->db != NULL)
dns_db_settask(zone->db, zone->task);
UNLOCK_ZONE(zone);
}
......@@ -5267,6 +5271,7 @@ zone_replacedb(dns_zone_t *zone, dns_db_t *db, isc_boolean_t dump) {
if (zone->db != NULL)
dns_db_detach(&zone->db);
dns_db_attach(db, &zone->db);
dns_db_settask(zone->db, zone->task);
DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_LOADED|DNS_ZONEFLG_NEEDNOTIFY);
return (ISC_R_SUCCESS);
......
......@@ -15,7 +15,7 @@
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: task.c,v 1.89 2003/10/25 00:09:13 jinmei Exp $ */
/* $Id: task.c,v 1.90 2004/03/04 06:56:41 marka Exp $ */
/*
* Principal Author: Bob Halley
......@@ -1132,7 +1132,7 @@ isc_taskmgr_create(isc_mem_t *mctx, unsigned int workers,
}