mirror of
https://github.com/isc-projects/bind9.git
synced 2026-02-27 03:51:16 -05:00
add beginload and endload support
This commit is contained in:
parent
4478cd2fa8
commit
7d44d8aacd
3 changed files with 225 additions and 77 deletions
56
lib/dns/db.c
56
lib/dns/db.c
|
|
@ -27,6 +27,7 @@
|
|||
#include <isc/assertions.h>
|
||||
|
||||
#include <dns/db.h>
|
||||
#include <dns/master.h>
|
||||
#include <dns/rdataset.h>
|
||||
|
||||
/***
|
||||
|
|
@ -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));
|
||||
}
|
||||
|
||||
/***
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@
|
|||
#include <dns/types.h>
|
||||
#include <dns/result.h>
|
||||
#include <dns/name.h>
|
||||
#include <dns/callbacks.h>
|
||||
|
||||
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.
|
||||
|
|
|
|||
179
lib/dns/rbtdb.c
179
lib/dns/rbtdb.c
|
|
@ -30,6 +30,7 @@
|
|||
#include <isc/mutex.h>
|
||||
#include <isc/rwlock.h>
|
||||
|
||||
#include <dns/types.h>
|
||||
#include <dns/name.h>
|
||||
#include <dns/fixedname.h>
|
||||
#include <dns/db.h>
|
||||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue