From 7d44d8aacda98eb2b526af34757a6bbcc97cd388 Mon Sep 17 00:00:00 2001 From: Bob Halley Date: Fri, 30 Jul 1999 23:32:19 +0000 Subject: [PATCH] add beginload and endload support --- lib/dns/db.c | 56 +++++++++++- lib/dns/include/dns/db.h | 67 ++++++++++++++- lib/dns/rbtdb.c | 179 +++++++++++++++++++++++---------------- 3 files changed, 225 insertions(+), 77 deletions(-) diff --git a/lib/dns/db.c b/lib/dns/db.c index f3d0d6cc34..d2b60ab5fe 100644 --- a/lib/dns/db.c +++ b/lib/dns/db.c @@ -27,6 +27,7 @@ #include #include +#include #include /*** @@ -169,15 +170,66 @@ dns_db_class(dns_db_t *db) { return (db->rdclass); } +dns_result_t +dns_db_beginload(dns_db_t *db, dns_addrdatasetfunc_t *addp, + dns_dbload_t **dbloadp) { + /* + * Begin loading 'db'. + */ + + REQUIRE(DNS_DB_VALID(db)); + REQUIRE(addp != NULL && *addp == NULL); + REQUIRE(dbloadp != NULL && *dbloadp == NULL); + + return ((db->methods->beginload)(db, addp, dbloadp)); +} + +dns_result_t +dns_db_endload(dns_db_t *db, dns_dbload_t **dbloadp) { + /* + * Finish loading 'db'. + */ + + REQUIRE(DNS_DB_VALID(db)); + REQUIRE(dbloadp != NULL && *dbloadp != NULL); + + return ((db->methods->endload)(db, dbloadp)); +} + dns_result_t dns_db_load(dns_db_t *db, char *filename) { + dns_result_t result, eresult; + int soacount, nscount; + dns_rdatacallbacks_t callbacks; + isc_boolean_t age_ttl = ISC_FALSE; + /* * Load master file 'filename' into 'db'. */ REQUIRE(DNS_DB_VALID(db)); - return (db->methods->load(db, filename)); + if ((db->attributes & DNS_DBATTR_CACHE) != 0) + age_ttl = ISC_TRUE; + + dns_rdatacallbacks_init(&callbacks); + + result = dns_db_beginload(db, &callbacks.add, &callbacks.add_private); + if (result != DNS_R_SUCCESS) + return (result); + result = dns_master_load(filename, &db->origin, &db->origin, + db->rdclass, age_ttl, &soacount, &nscount, + &callbacks, db->mctx); + eresult = dns_db_endload(db, &callbacks.add_private); + /* + * We always call dns_db_endload(), but we only want to return its + * result if dns_master_load() succeeded. If dns_master_load() + * failed, we want to return the result code it gave us. + */ + if (result == ISC_R_SUCCESS) + result = eresult; + + return (result); } dns_result_t @@ -188,7 +240,7 @@ dns_db_dump(dns_db_t *db, dns_dbversion_t *version, char *filename) { REQUIRE(DNS_DB_VALID(db)); - return (db->methods->dump(db, version, filename)); + return ((db->methods->dump)(db, version, filename)); } /*** diff --git a/lib/dns/include/dns/db.h b/lib/dns/include/dns/db.h index 56aae8d374..e182805cd4 100644 --- a/lib/dns/include/dns/db.h +++ b/lib/dns/include/dns/db.h @@ -63,6 +63,7 @@ #include #include #include +#include ISC_LANG_BEGINDECLS @@ -73,7 +74,9 @@ ISC_LANG_BEGINDECLS typedef struct dns_dbmethods { void (*attach)(dns_db_t *source, dns_db_t **targetp); void (*detach)(dns_db_t **dbp); - dns_result_t (*load)(dns_db_t *db, char *filename); + dns_result_t (*beginload)(dns_db_t *db, dns_addrdatasetfunc_t *addp, + dns_dbload_t **dbloadp); + dns_result_t (*endload)(dns_db_t *db, dns_dbload_t **dbloadp); dns_result_t (*dump)(dns_db_t *db, dns_dbversion_t *version, char *filename); void (*currentversion)(dns_db_t *db, @@ -307,11 +310,73 @@ dns_db_class(dns_db_t *db); * The class of the database. */ +dns_result_t +dns_db_beginload(dns_db_t *db, dns_addrdatasetfunc_t *addp, + dns_dbload_t **dbloadp); +/* + * Begin loading 'db'. + * + * Requires: + * + * 'db' is a valid database. + * + * This is the first attempt to load 'db'. + * + * addp != NULL && *addp == NULL + * + * dbloadp != NULL && *dbloadp == NULL + * + * Ensures: + * + * On success, *addp will be a valid dns_addrdatasetfunc_t suitable + * for loading 'db'. *dbloadp will be a valid DB load context which + * should be used as 'arg' when *addp is called. + * + * Returns: + * + * DNS_R_SUCCESS + * DNS_R_NOMEMORY + * + * Other results are possible, depending upon the database + * implementation used, syntax errors in the master file, etc. + */ + +dns_result_t +dns_db_endload(dns_db_t *db, dns_dbload_t **dbloadp); +/* + * Finish loading 'db'. + * + * Requires: + * + * 'db' is a valid database that is being loaded. + * + * dbloadp != NULL and *dbloadp is a valid database load context. + * + * Ensures: + * + * *dbloadp == NULL + * + * Returns: + * + * DNS_R_SUCCESS + * DNS_R_NOMEMORY + * + * Other results are possible, depending upon the database + * implementation used, syntax errors in the master file, etc. + */ + dns_result_t dns_db_load(dns_db_t *db, char *filename); /* * Load master file 'filename' into 'db'. * + * Notes: + * This routine is equivalent to calling + * + * dns_db_beginload(); + * dns_master_load(); + * dns_db_endload(); + * * Requires: * * 'db' is a valid database. diff --git a/lib/dns/rbtdb.c b/lib/dns/rbtdb.c index 2ee2d35fdd..08524ba601 100644 --- a/lib/dns/rbtdb.c +++ b/lib/dns/rbtdb.c @@ -30,6 +30,7 @@ #include #include +#include #include #include #include @@ -145,6 +146,7 @@ typedef struct { } dns_rbtdb_t; #define RBTDB_ATTR_LOADED 0x01 +#define RBTDB_ATTR_LOADING 0x02 /* * Search Context @@ -2716,10 +2718,8 @@ deleterdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, } static dns_result_t -add_rdataset_callback(dns_rdatacallbacks_t *callbacks, dns_name_t *name, - dns_rdataset_t *rdataset) -{ - rbtdb_load_t *loadctx = callbacks->commit_private; +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 = NULL; dns_result_t result; @@ -2767,76 +2767,73 @@ add_rdataset_callback(dns_rdatacallbacks_t *callbacks, dns_name_t *name, } static dns_result_t -load(dns_db_t *db, char *filename) { - rbtdb_load_t loadctx; +beginload(dns_db_t *db, dns_addrdatasetfunc_t *addp, dns_dbload_t **dbloadp) { + rbtdb_load_t *loadctx; dns_rbtdb_t *rbtdb; - int soacount, nscount; - dns_rdatacallbacks_t callbacks; dns_result_t result; - dns_name_t name; - isc_boolean_t age_ttl; rbtdb = (dns_rbtdb_t *)db; REQUIRE(VALID_RBTDB(rbtdb)); - loadctx.rbtdb = rbtdb; + loadctx = isc_mem_get(rbtdb->common.mctx, sizeof *loadctx); + if (loadctx == NULL) + return (DNS_R_NOMEMORY); + + loadctx->rbtdb = rbtdb; if ((rbtdb->common.attributes & DNS_DBATTR_CACHE) != 0) { - if (isc_stdtime_get(&loadctx.now) != ISC_R_SUCCESS) - return (DNS_R_UNEXPECTED); - age_ttl = ISC_TRUE; + if (isc_stdtime_get(&loadctx->now) != ISC_R_SUCCESS) { + result = DNS_R_UNEXPECTED; + goto cleanup_loadctx; + } } else { - loadctx.now = 0; - age_ttl = ISC_FALSE; + loadctx->now = 0; } LOCK(&rbtdb->lock); - REQUIRE((rbtdb->attributes & RBTDB_ATTR_LOADED) == 0); - /* - * We set RBTDB_ATTR_LOADED even though we don't know the - * load is going to succeed because we don't want someone to try - * again with partial prior load results if a load fails. - */ - rbtdb->attributes |= RBTDB_ATTR_LOADED; + REQUIRE((rbtdb->attributes & (RBTDB_ATTR_LOADED|RBTDB_ATTR_LOADING)) + == 0); + rbtdb->attributes |= RBTDB_ATTR_LOADING; UNLOCK(&rbtdb->lock); - /* - * 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 add_rdataset_callback(), 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 ((rbtdb->common.attributes & DNS_DBATTR_CACHE) == 0) { - result = dns_rbt_addnode(rbtdb->tree, &rbtdb->common.origin, - &rbtdb->origin_node); - if (result != DNS_R_SUCCESS) { - INSIST(result != DNS_R_EXISTS); - return (result); - } - dns_name_init(&name, NULL); - dns_rbt_namefromnode(rbtdb->origin_node, &name); - rbtdb->origin_node->locknum = - dns_name_hash(&name, ISC_TRUE) % - rbtdb->node_lock_count; - } + *addp = loading_addrdataset; + *dbloadp = loadctx; - dns_rdatacallbacks_init(&callbacks); - callbacks.commit = add_rdataset_callback; - callbacks.commit_private = &loadctx; + return (DNS_R_SUCCESS); - return (dns_master_load(filename, &rbtdb->common.origin, - &rbtdb->common.origin, rbtdb->common.rdclass, - age_ttl, &soacount, &nscount, &callbacks, - rbtdb->common.mctx)); + cleanup_loadctx: + isc_mem_put(rbtdb->common.mctx, loadctx, sizeof *loadctx); + + return (result); +} + +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; + + REQUIRE(VALID_RBTDB(rbtdb)); + REQUIRE(dbloadp != NULL); + loadctx = *dbloadp; + REQUIRE(loadctx->rbtdb == rbtdb); + + LOCK(&rbtdb->lock); + + REQUIRE((rbtdb->attributes & RBTDB_ATTR_LOADING) != 0); + REQUIRE((rbtdb->attributes & RBTDB_ATTR_LOADED) == 0); + + rbtdb->attributes &= ~RBTDB_ATTR_LOADING; + rbtdb->attributes |= RBTDB_ATTR_LOADED; + + UNLOCK(&rbtdb->lock); + + *dbloadp = NULL; + + isc_mem_put(rbtdb->common.mctx, loadctx, sizeof *loadctx); + + return (DNS_R_SUCCESS); } static dns_result_t @@ -2866,7 +2863,8 @@ delete_callback(void *data, void *arg) { static dns_dbmethods_t zone_methods = { attach, detach, - load, + beginload, + endload, dump, currentversion, newversion, @@ -2889,7 +2887,8 @@ static dns_dbmethods_t zone_methods = { static dns_dbmethods_t cache_methods = { attach, detach, - load, + beginload, + endload, dump, currentversion, newversion, @@ -2920,10 +2919,10 @@ dns_rbtdb_create dns_db_t **dbp) { dns_rbtdb_t *rbtdb; - isc_result_t iresult; - dns_result_t dresult; + isc_result_t result; int i; isc_region_t r1, r2; + dns_name_t name; /* Keep the compiler happy. */ (void)argc; @@ -2942,22 +2941,22 @@ dns_rbtdb_create rbtdb->common.rdclass = rdclass; rbtdb->common.mctx = mctx; - iresult = isc_mutex_init(&rbtdb->lock); - if (iresult != ISC_R_SUCCESS) { + result = isc_mutex_init(&rbtdb->lock); + if (result != ISC_R_SUCCESS) { isc_mem_put(rbtdb->common.mctx, rbtdb, sizeof *rbtdb); UNEXPECTED_ERROR(__FILE__, __LINE__, "isc_mutex_init() failed: %s", - isc_result_totext(iresult)); + isc_result_totext(result)); return (DNS_R_UNEXPECTED); } - iresult = isc_rwlock_init(&rbtdb->tree_lock, 0, 0); - if (iresult != ISC_R_SUCCESS) { + result = isc_rwlock_init(&rbtdb->tree_lock, 0, 0); + if (result != ISC_R_SUCCESS) { isc_mutex_destroy(&rbtdb->lock); isc_mem_put(rbtdb->common.mctx, rbtdb, sizeof *rbtdb); UNEXPECTED_ERROR(__FILE__, __LINE__, "isc_rwlock_init() failed: %s", - isc_result_totext(iresult)); + isc_result_totext(result)); return (DNS_R_UNEXPECTED); } @@ -2968,8 +2967,8 @@ dns_rbtdb_create rbtdb->node_locks = isc_mem_get(mctx, rbtdb->node_lock_count * sizeof (rbtdb_nodelock_t)); for (i = 0; i < (int)(rbtdb->node_lock_count); i++) { - iresult = isc_mutex_init(&rbtdb->node_locks[i].lock); - if (iresult != ISC_R_SUCCESS) { + result = isc_mutex_init(&rbtdb->node_locks[i].lock); + if (result != ISC_R_SUCCESS) { i--; while (i >= 0) { isc_mutex_destroy(&rbtdb->node_locks[i].lock); @@ -2983,7 +2982,7 @@ dns_rbtdb_create isc_mem_put(rbtdb->common.mctx, rbtdb, sizeof *rbtdb); UNEXPECTED_ERROR(__FILE__, __LINE__, "isc_mutex_init() failed: %s", - isc_result_totext(iresult)); + isc_result_totext(result)); return (DNS_R_UNEXPECTED); } rbtdb->node_locks[i].references = 0; @@ -3003,17 +3002,49 @@ dns_rbtdb_create memcpy(r2.base, r1.base, r1.length); dns_name_fromregion(&rbtdb->common.origin, &r2); - rbtdb->origin_node = NULL; - /* * Make the Red-Black Tree. */ - dresult = dns_rbt_create(mctx, delete_callback, rbtdb, &rbtdb->tree); - if (dresult != DNS_R_SUCCESS) { + result = dns_rbt_create(mctx, delete_callback, rbtdb, &rbtdb->tree); + if (result != DNS_R_SUCCESS) { free_rbtdb(rbtdb); - return (dresult); + 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 ((rbtdb->common.attributes & DNS_DBATTR_CACHE) == 0) { + rbtdb->origin_node = NULL; + result = dns_rbt_addnode(rbtdb->tree, &rbtdb->common.origin, + &rbtdb->origin_node); + if (result != DNS_R_SUCCESS) { + INSIST(result != DNS_R_EXISTS); + free_rbtdb(rbtdb); + return (result); + } + /* + * We need to give the origin node the right locknum. + */ + dns_name_init(&name, NULL); + dns_rbt_namefromnode(rbtdb->origin_node, &name); + rbtdb->origin_node->locknum = + dns_name_hash(&name, ISC_TRUE) % + rbtdb->node_lock_count; } + /* + * Misc. Initialization. + */ rbtdb->references = 1; rbtdb->attributes = 0;