2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-29 13:38:26 +00:00

1526. [func] Implemented "additional section caching (or acache)",

an internal cache framework for additional section
			content to improve response performance.  Several
			configuration options were provided to control the
			behavior.
This commit is contained in:
Tatuya JINMEI 神明達哉 2004-12-21 10:45:20 +00:00
parent 0e93730a02
commit d0eb2cc33c
27 changed files with 3802 additions and 95 deletions

View File

@ -770,7 +770,11 @@
1527. [cleanup] Reduce the number of gettimeofday() calls without
losing necessary timer granularity.
1526. [placeholder]
1526. [func] Implemented "additional section caching (or acache)",
an internal cache framework for additional section
content to improve response performance. Several
configuration options were provided to control the
behavior.
1525. [bug] dns_cache_create() could trigger a REQUIRE
failure in isc_mem_put() during error cleanup.

View File

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: config.c,v 1.51 2004/10/05 02:47:50 marka Exp $ */
/* $Id: config.c,v 1.52 2004/12/21 10:45:15 jinmei Exp $ */
#include <config.h>
@ -125,6 +125,9 @@ options {\n\
check-names master fail;\n\
check-names slave warn;\n\
check-names response ignore;\n\
use-additional-cache true;\n\
acache-cleaning-interval 60;\n\
max-acache-size 0;\n\
dnssec-enable no; /* Make yes for 9.4. */ \n\
"

View File

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: server.h,v 1.75 2004/10/11 05:30:19 marka Exp $ */
/* $Id: server.h,v 1.76 2004/12/21 10:45:15 jinmei Exp $ */
#ifndef NAMED_SERVER_H
#define NAMED_SERVER_H 1
@ -94,7 +94,8 @@ struct ns_server {
ns_controls_t * controls; /* Control channels */
unsigned int dispatchgen;
ns_dispatchlist_t dispatches;
dns_acache_t *acache;
};
#define NS_SERVER_MAGIC ISC_MAGIC('S','V','E','R')

View File

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: query.c,v 1.261 2004/06/30 14:16:06 marka Exp $ */
/* $Id: query.c,v 1.262 2004/12/21 10:45:15 jinmei Exp $ */
#include <config.h>
@ -92,6 +92,11 @@
#define DNS_GETDB_NOLOG 0x02U
#define DNS_GETDB_PARTIAL 0x04U
typedef struct client_additionalctx {
ns_client_t *client;
dns_rdataset_t *rdataset;
} client_additionalctx_t;
static void
query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype);
@ -538,37 +543,18 @@ query_findversion(ns_client_t *client, dns_db_t *db,
}
static inline isc_result_t
query_getzonedb(ns_client_t *client, dns_name_t *name, dns_rdatatype_t qtype,
unsigned int options, dns_zone_t **zonep, dns_db_t **dbp,
dns_dbversion_t **versionp)
query_validatezonedb(ns_client_t *client, dns_name_t *name,
dns_rdatatype_t qtype, unsigned int options,
dns_zone_t *zone, dns_db_t *db,
dns_dbversion_t **versionp)
{
isc_result_t result;
isc_boolean_t check_acl, new_zone;
dns_acl_t *queryacl;
ns_dbversion_t *dbversion;
unsigned int ztoptions;
dns_zone_t *zone = NULL;
dns_db_t *db = NULL;
isc_boolean_t partial = ISC_FALSE;
REQUIRE(zonep != NULL && *zonep == NULL);
REQUIRE(dbp != NULL && *dbp == NULL);
/*
* Find a zone database to answer the query.
*/
ztoptions = ((options & DNS_GETDB_NOEXACT) != 0) ?
DNS_ZTFIND_NOEXACT : 0;
result = dns_zt_find(client->view->zonetable, name, ztoptions, NULL,
&zone);
if (result == DNS_R_PARTIALMATCH)
partial = ISC_TRUE;
if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH)
result = dns_zone_getdb(zone, &db);
if (result != ISC_R_SUCCESS)
goto fail;
REQUIRE(zone != NULL);
REQUIRE(db != NULL);
/*
* This limits our searching to the zone where the first name
@ -689,17 +675,63 @@ query_getzonedb(ns_client_t *client, dns_name_t *name, dns_rdatatype_t qtype,
*/
dbversion->queryok = ISC_TRUE;
/* Transfer ownership, if necessary. */
if (versionp != NULL)
*versionp = dbversion->version;
return (ISC_R_SUCCESS);
refuse:
return (DNS_R_REFUSED);
fail:
return (result);
}
static inline isc_result_t
query_getzonedb(ns_client_t *client, dns_name_t *name, dns_rdatatype_t qtype,
unsigned int options, dns_zone_t **zonep, dns_db_t **dbp,
dns_dbversion_t **versionp)
{
isc_result_t result;
unsigned int ztoptions;
dns_zone_t *zone = NULL;
dns_db_t *db = NULL;
isc_boolean_t partial = ISC_FALSE;
REQUIRE(zonep != NULL && *zonep == NULL);
REQUIRE(dbp != NULL && *dbp == NULL);
/*
* Find a zone database to answer the query.
*/
ztoptions = ((options & DNS_GETDB_NOEXACT) != 0) ?
DNS_ZTFIND_NOEXACT : 0;
result = dns_zt_find(client->view->zonetable, name, ztoptions, NULL,
&zone);
if (result == DNS_R_PARTIALMATCH)
partial = ISC_TRUE;
if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH)
result = dns_zone_getdb(zone, &db);
if (result != ISC_R_SUCCESS)
goto fail;
result = query_validatezonedb(client, name, qtype, options, zone, db,
versionp);
if (result != ISC_R_SUCCESS)
goto fail;
/* Transfer ownership. */
*zonep = zone;
*dbp = db;
*versionp = dbversion->version;
if (partial && (options & DNS_GETDB_PARTIAL) != 0)
return (DNS_R_PARTIALMATCH);
return (ISC_R_SUCCESS);
refuse:
result = DNS_R_REFUSED;
fail:
if (zone != NULL)
dns_zone_detach(&zone);
@ -1237,11 +1269,516 @@ query_addadditional(void *arg, dns_name_t *name, dns_rdatatype_t qtype) {
return (eresult);
}
static inline void
query_discardcache(ns_client_t *client, dns_rdataset_t *rdataset_base,
dns_rdatasetadditional_t additionaltype,
dns_rdatatype_t type, dns_zone_t **zonep, dns_db_t **dbp,
dns_dbversion_t **versionp, dns_dbnode_t **nodep,
dns_name_t *fname)
{
dns_rdataset_t *rdataset;
while ((rdataset = ISC_LIST_HEAD(fname->list)) != NULL) {
ISC_LIST_UNLINK(fname->list, rdataset, link);
query_putrdataset(client, &rdataset);
}
if (*versionp != NULL)
dns_db_closeversion(*dbp, versionp, ISC_FALSE);
if (*nodep != NULL)
dns_db_detachnode(*dbp, nodep);
if (*dbp != NULL)
dns_db_detach(dbp);
if (*zonep != NULL)
dns_zone_detach(zonep);
(void)dns_rdataset_putadditional(client->view->acache, rdataset_base,
additionaltype, type);
}
static inline isc_result_t
query_iscachevalid(dns_zone_t *zone, dns_db_t *db, dns_db_t *db0,
dns_dbversion_t *version)
{
isc_result_t result = ISC_R_SUCCESS;
dns_dbversion_t *version_current = NULL;
dns_db_t *db_current = db0;
if (db_current == NULL) {
result = dns_zone_getdb(zone, &db_current);
if (result != ISC_R_SUCCESS)
return (result);
}
dns_db_currentversion(db_current, &version_current);
if (db_current != db || version_current != version) {
result = ISC_R_FAILURE;
goto cleanup;
}
cleanup:
dns_db_closeversion(db_current, &version_current, ISC_FALSE);
if (db0 == NULL && db_current != NULL)
dns_db_detach(&db_current);
return (result);
}
static isc_result_t
query_addadditional2(void *arg, dns_name_t *name, dns_rdatatype_t qtype) {
client_additionalctx_t *additionalctx = arg;
dns_rdataset_t *rdataset_base;
ns_client_t *client;
isc_result_t result, eresult;
dns_dbnode_t *node, *cnode;
dns_db_t *db, *cdb;
dns_name_t *fname, *mname0, cfname;
dns_rdataset_t *rdataset, *sigrdataset;
dns_rdataset_t *crdataset, *crdataset_next;
isc_buffer_t *dbuf;
isc_buffer_t b;
dns_dbversion_t *version, *cversion;
isc_boolean_t added_something, need_addname, needadditionalcache;
isc_boolean_t need_sigrrset;
dns_zone_t *zone;
dns_rdatatype_t type;
dns_rdatasetadditional_t additionaltype;
if (qtype != dns_rdatatype_a) {
/*
* This function is optimized for "address" types. For other
* types, use a generic routine.
* XXX: ideally, this function should be generic enough.
*/
return (query_addadditional(additionalctx->client,
name, qtype));
}
/*
* Initialization.
*/
rdataset_base = additionalctx->rdataset;
client = additionalctx->client;
REQUIRE(NS_CLIENT_VALID(client));
eresult = ISC_R_SUCCESS;
fname = NULL;
rdataset = NULL;
sigrdataset = NULL;
db = NULL;
cdb = NULL;
version = NULL;
cversion = NULL;
node = NULL;
cnode = NULL;
added_something = ISC_FALSE;
need_addname = ISC_FALSE;
zone = NULL;
needadditionalcache = ISC_FALSE;
additionaltype = dns_rdatasetadditional_fromauth;
dns_name_init(&cfname, NULL);
CTRACE("query_addadditional2");
/*
* We treat type A additional section processing as if it
* were "any address type" additional section processing.
* To avoid multiple lookups, we do an 'any' database
* lookup and iterate over the node.
* XXXJT: this approach can cause a suboptimal result when the cache
* DB only has partial address types and the glue DB has remaining
* ones.
*/
type = dns_rdatatype_any;
/*
* Get some resources.
*/
dbuf = query_getnamebuf(client);
if (dbuf == NULL)
goto cleanup;
fname = query_newname(client, dbuf, &b);
if (fname == NULL)
goto cleanup;
dns_name_setbuffer(&cfname, &b); /* share the buffer */
/* Check additional cache */
result = dns_rdataset_getadditional(rdataset_base, additionaltype,
type, client->view->acache, &zone,
&cdb, &cversion, &cnode, &cfname,
client->message, client->now);
if (result != ISC_R_SUCCESS)
goto findauthdb;
if (zone == NULL) {
CTRACE("query_addadditional2: auth zone not found");
goto try_cache;
}
/* Is the cached DB up-to-date? */
result = query_iscachevalid(zone, cdb, NULL, cversion);
if (result != ISC_R_SUCCESS) {
CTRACE("query_addadditional2: old auth additional cache");
query_discardcache(client, rdataset_base, additionaltype,
type, &zone, &cdb, &cversion, &cnode,
&cfname);
goto findauthdb;
}
if (cnode == NULL) {
/*
* We have a negative cache. We don't have to check the zone
* ACL, since the result (not using this zone) would be same
* regardless of the result.
*/
CTRACE("query_addadditional2: negative auth additional cache");
dns_db_closeversion(cdb, &cversion, ISC_FALSE);
dns_db_detach(&cdb);
dns_zone_detach(&zone);
goto try_cache;
}
result = query_validatezonedb(client, name, qtype, DNS_GETDB_NOLOG,
zone, cdb, NULL);
if (result != ISC_R_SUCCESS) {
query_discardcache(client, rdataset_base, additionaltype,
type, &zone, &cdb, &cversion, &cnode,
&cfname);
goto try_cache;
}
/* We've got an active cache. */
CTRACE("query_addadditional2: auth additional cache");
dns_db_closeversion(cdb, &cversion, ISC_FALSE);
db = cdb;
node = cnode;
dns_name_clone(&cfname, fname);
query_keepname(client, fname, dbuf);
goto foundcache;
/*
* Look for a zone database that might contain authoritative
* additional data.
*/
findauthdb:
result = query_getzonedb(client, name, qtype, DNS_GETDB_NOLOG,
&zone, &db, &version);
if (result != ISC_R_SUCCESS) {
/* Cache the negative result */
(void)dns_rdataset_setadditional(rdataset_base, additionaltype,
type, client->view->acache,
NULL, NULL, NULL, NULL,
NULL);
goto try_cache;
}
CTRACE("query_addadditional2: db_find");
/*
* Since we are looking for authoritative data, we do not set
* the GLUEOK flag. Glue will be looked for later, but not
* necessarily in the same database.
*/
node = NULL;
result = dns_db_find(db, name, version, type, client->query.dboptions,
client->now, &node, fname, NULL, NULL);
if (result == ISC_R_SUCCESS)
goto found;
/* Cache the negative result */
(void)dns_rdataset_setadditional(rdataset_base, additionaltype,
type, client->view->acache, zone, db,
version, NULL, fname);
if (node != NULL)
dns_db_detachnode(db, &node);
version = NULL;
dns_db_detach(&db);
/*
* No authoritative data was found. The cache is our next best bet.
*/
try_cache:
additionaltype = dns_rdatasetadditional_fromcache;
result = query_getcachedb(client, name, qtype, &db, DNS_GETDB_NOLOG);
if (result != ISC_R_SUCCESS)
/*
* Most likely the client isn't allowed to query the cache.
*/
goto try_glue;
result = dns_db_find(db, name, version, type, client->query.dboptions,
client->now, &node, fname, NULL, NULL);
if (result == ISC_R_SUCCESS)
goto found;
if (node != NULL)
dns_db_detachnode(db, &node);
dns_db_detach(&db);
try_glue:
/*
* No cached data was found. Glue is our last chance.
* RFC1035 sayeth:
*
* NS records cause both the usual additional section
* processing to locate a type A record, and, when used
* in a referral, a special search of the zone in which
* they reside for glue information.
*
* This is the "special search". Note that we must search
* the zone where the NS record resides, not the zone it
* points to, and that we only do the search in the delegation
* case (identified by client->query.gluedb being set).
*/
if (client->query.gluedb == NULL)
goto cleanup;
/*
* Don't poision caches using the bailiwick protection model.
*/
if (!dns_name_issubdomain(name, dns_db_origin(client->query.gluedb)))
goto cleanup;
/* Check additional cache */
additionaltype = dns_rdatasetadditional_fromglue;
result = dns_rdataset_getadditional(rdataset_base, additionaltype,
type, client->view->acache, NULL,
&cdb, &cversion, &cnode, &cfname,
client->message, client->now);
if (result != ISC_R_SUCCESS)
goto findglue;
result = query_iscachevalid(zone, cdb, client->query.gluedb, cversion);
if (result != ISC_R_SUCCESS) {
CTRACE("query_addadditional2: old glue additional cache");
query_discardcache(client, rdataset_base, additionaltype,
type, &zone, &cdb, &cversion, &cnode,
&cfname);
goto findglue;
}
if (cnode == NULL) {
/* We have a negative cache. */
CTRACE("query_addadditional2: negative glue additional cache");
dns_db_closeversion(cdb, &cversion, ISC_FALSE);
dns_db_detach(&cdb);
goto cleanup;
}
/* Cache hit. */
CTRACE("query_addadditional2: glue additional cache");
dns_db_closeversion(cdb, &cversion, ISC_FALSE);
db = cdb;
node = cnode;
dns_name_clone(&cfname, fname);
query_keepname(client, fname, dbuf);
goto foundcache;
findglue:
dns_db_attach(client->query.gluedb, &db);
result = dns_db_find(db, name, version, type,
client->query.dboptions | DNS_DBFIND_GLUEOK,
client->now, &node, fname, NULL, NULL);
if (!(result == ISC_R_SUCCESS ||
result == DNS_R_ZONECUT ||
result == DNS_R_GLUE)) {
/* cache the negative result */
(void)dns_rdataset_setadditional(rdataset_base, additionaltype,
type, client->view->acache,
NULL, db, version, NULL,
fname);
goto cleanup;
}
found:
/*
* We have found a DB node to iterate over from a DB.
* We are going to look for address RRsets (i.e., A and AAAA) in the DB
* node we've just found. We'll then store the complete information
* in the additional data cache.
*/
dns_name_clone(fname, &cfname);
query_keepname(client, fname, dbuf);
needadditionalcache = ISC_TRUE;
rdataset = query_newrdataset(client);
if (rdataset == NULL)
goto cleanup;
if (WANTDNSSEC(client)) {
sigrdataset = query_newrdataset(client);
if (sigrdataset == NULL)
goto cleanup;
}
/*
* Find A RRset with sig RRset. Even if we don't find a sig RRset
* for a client using DNSSEC, we'll continue the process to make a
* complete list to be cached. However, we need to cancel the
* caching when something unexpected happens, in order to avoid
* caching incomplete information.
*/
result = dns_db_findrdataset(db, node, version, dns_rdatatype_a, 0,
client->now, rdataset, sigrdataset);
if (result == DNS_R_NCACHENXDOMAIN)
goto setcache;
if (result == DNS_R_NCACHENXRRSET) {
dns_rdataset_disassociate(rdataset);
/*
* Negative cache entries don't have sigrdatasets.
*/
INSIST(sigrdataset == NULL ||
! dns_rdataset_isassociated(sigrdataset));
}
if (result == ISC_R_SUCCESS) {
/* Remember the result as a cache */
ISC_LIST_APPEND(cfname.list, rdataset, link);
if (sigrdataset != NULL &&
dns_rdataset_isassociated(sigrdataset)) {
ISC_LIST_APPEND(cfname.list, sigrdataset,
link);
sigrdataset =
query_newrdataset(client);
if (sigrdataset == NULL)
needadditionalcache = ISC_FALSE;
}
rdataset = query_newrdataset(client);
if (rdataset == NULL) {
/* do not cache incomplete information */
goto foundcache;
}
}
/* Find AAAA RRset with sig RRset */
result = dns_db_findrdataset(db, node, version,
dns_rdatatype_aaaa, 0,
client->now, rdataset,
sigrdataset);
/* The NXDOMAIN case should be covered above */
INSIST(result != DNS_R_NCACHENXDOMAIN);
if (result == DNS_R_NCACHENXRRSET) {
dns_rdataset_disassociate(rdataset);
/*
* Negative cache entries don't have sigrdatasets.
*/
INSIST(sigrdataset == NULL ||
! dns_rdataset_isassociated(sigrdataset));
}
if (result == ISC_R_SUCCESS) {
ISC_LIST_APPEND(cfname.list, rdataset, link);
rdataset = NULL;
if (sigrdataset != NULL &&
dns_rdataset_isassociated(sigrdataset)) {
ISC_LIST_APPEND(cfname.list, sigrdataset,
link);
sigrdataset = NULL;
}
}
setcache:
/*
* Set the new result in the cache if required. We do not support
* caching additional data from a cache DB.
*/
if (needadditionalcache == ISC_TRUE &&
(additionaltype == dns_rdatasetadditional_fromauth ||
additionaltype == dns_rdatasetadditional_fromglue)) {
(void)dns_rdataset_setadditional(rdataset_base, additionaltype,
type, client->view->acache,
zone, db, version, node,
&cfname);
}
foundcache:
need_sigrrset = ISC_FALSE;
mname0 = NULL;
for (crdataset = ISC_LIST_HEAD(cfname.list);
crdataset != NULL;
crdataset = crdataset_next) {
dns_name_t *mname;
crdataset_next = ISC_LIST_NEXT(crdataset, link);
mname = NULL;
if (crdataset->type == dns_rdatatype_a ||
crdataset->type == dns_rdatatype_aaaa) {
if (!query_isduplicate(client, fname, crdataset->type,
&mname)) {
if (mname != NULL) {
/*
* A different type of this name is
* already stored in the additional
* section. We'll reuse the name.
* Note that this should happen at most
* once. Otherwise, fname->link could
* leak below.
*/
INSIST(mname0 == NULL);
query_releasename(client, &fname);
fname = mname;
mname0 = mname;
} else
need_addname = ISC_TRUE;
ISC_LIST_UNLINK(cfname.list, crdataset, link);
ISC_LIST_APPEND(fname->list, crdataset, link);
added_something = ISC_TRUE;
need_sigrrset = ISC_TRUE;
} else
need_sigrrset = ISC_FALSE;
} else if (crdataset->type == dns_rdatatype_sig &&
need_sigrrset && WANTDNSSEC(client)) {
ISC_LIST_UNLINK(cfname.list, crdataset, link);
ISC_LIST_APPEND(fname->list, crdataset, link);
added_something = ISC_TRUE; /* just in case */
need_sigrrset = ISC_FALSE;
}
}
CTRACE("query_addadditional2: addname");
/*
* If we haven't added anything, then we're done.
*/
if (!added_something)
goto cleanup;
/*
* We may have added our rdatasets to an existing name, if so, then
* need_addname will be ISC_FALSE. Whether we used an existing name
* or a new one, we must set fname to NULL to prevent cleanup.
*/
if (need_addname)
dns_message_addname(client->message, fname,
DNS_SECTION_ADDITIONAL);
fname = NULL;
cleanup:
CTRACE("query_addadditional2: cleanup");
if (rdataset != NULL)
query_putrdataset(client, &rdataset);
if (sigrdataset != NULL)
query_putrdataset(client, &sigrdataset);
while ((crdataset = ISC_LIST_HEAD(cfname.list)) != NULL) {
ISC_LIST_UNLINK(cfname.list, crdataset, link);
query_putrdataset(client, &crdataset);
}
if (fname != NULL)
query_releasename(client, &fname);
if (node != NULL)
dns_db_detachnode(db, &node);
if (db != NULL)
dns_db_detach(&db);
if (zone != NULL)
dns_zone_detach(&zone);
CTRACE("query_addadditional2: done");
return (eresult);
}
static inline void
query_addrdataset(ns_client_t *client, dns_name_t *fname,
dns_rdataset_t *rdataset)
{
dns_rdatatype_t type = rdataset->type;
client_additionalctx_t additionalctx;
/*
* Add 'rdataset' and any pertinent additional data to
@ -1264,8 +1801,10 @@ query_addrdataset(ns_client_t *client, dns_name_t *fname,
*
* We don't care if dns_rdataset_additionaldata() fails.
*/
(void)dns_rdataset_additionaldata(rdataset,
query_addadditional, client);
additionalctx.client = client;
additionalctx.rdataset = rdataset;
(void)dns_rdataset_additionaldata(rdataset, query_addadditional2,
&additionalctx);
/*
* RFC 2535 section 3.5 says that when NS, SOA, A, or AAAA records
* are retrieved, any KEY RRs for the owner name should be added
@ -1362,11 +1901,12 @@ query_addrrset(ns_client_t *client, dns_name_t **namep,
}
static inline isc_result_t
query_addsoa(ns_client_t *client, dns_db_t *db, isc_boolean_t zero_ttl) {
dns_name_t *name, *fname;
query_addsoa(ns_client_t *client, dns_db_t *db, dns_dbversion_t *version,
isc_boolean_t zero_ttl)
{
dns_name_t *name;
dns_dbnode_t *node;
isc_result_t result, eresult;
dns_fixedname_t foundname;
dns_rdataset_t *rdataset = NULL, *sigrdataset = NULL;
dns_rdataset_t **sigrdatasetp = NULL;
@ -1378,8 +1918,6 @@ query_addsoa(ns_client_t *client, dns_db_t *db, isc_boolean_t zero_ttl) {
name = NULL;
rdataset = NULL;
node = NULL;
dns_fixedname_init(&foundname);
fname = dns_fixedname_name(&foundname);
/*
* Get resources and make 'name' be the database origin.
@ -1405,9 +1943,26 @@ query_addsoa(ns_client_t *client, dns_db_t *db, isc_boolean_t zero_ttl) {
/*
* Find the SOA.
*/
result = dns_db_find(db, name, NULL, dns_rdatatype_soa,
client->query.dboptions, 0, &node,
fname, rdataset, sigrdataset);
result = dns_db_getsoanode(db, &node);
if (result == ISC_R_SUCCESS) {
result = dns_db_findrdataset(db, node, version,
dns_rdatatype_soa,
0, client->now, rdataset,
sigrdataset);
} else {
dns_fixedname_t foundname;
dns_name_t *fname;
dns_fixedname_init(&foundname);
fname = dns_fixedname_name(&foundname);
result = dns_db_find(db, name, version, dns_rdatatype_soa,
client->query.dboptions, 0, &node,
fname, rdataset, sigrdataset);
if (result == ISC_R_SUCCESS)
(void)dns_db_setsoanode(db, node);
}
if (result != ISC_R_SUCCESS) {
/*
* This is bad. We tried to get the SOA RR at the zone top
@ -1463,7 +2018,7 @@ query_addsoa(ns_client_t *client, dns_db_t *db, isc_boolean_t zero_ttl) {
}
static inline isc_result_t
query_addns(ns_client_t *client, dns_db_t *db) {
query_addns(ns_client_t *client, dns_db_t *db, dns_dbversion_t *version) {
dns_name_t *name, *fname;
dns_dbnode_t *node;
isc_result_t result, eresult;
@ -1510,13 +2065,25 @@ query_addns(ns_client_t *client, dns_db_t *db) {
/*
* Find the NS rdataset.
*/
CTRACE("query_addns: calling dns_db_find");
result = dns_db_find(db, name, NULL, dns_rdatatype_ns,
client->query.dboptions, 0, &node,
fname, rdataset, sigrdataset);
CTRACE("query_addns: dns_db_find complete");
result = dns_db_getnsnode(db, &node);
if (result == ISC_R_SUCCESS) {
result = dns_db_findrdataset(db, node, version,
dns_rdatatype_ns,
0, client->now, rdataset,
sigrdataset);
} else {
CTRACE("query_addns: calling dns_db_find");
result = dns_db_find(db, name, NULL, dns_rdatatype_ns,
client->query.dboptions, 0, &node,
fname, rdataset, sigrdataset);
CTRACE("query_addns: dns_db_find complete");
if (result == ISC_R_SUCCESS)
(void)dns_db_setnsnode(db, node);
}
if (result != ISC_R_SUCCESS) {
CTRACE("query_addns: dns_db_find failed");
CTRACE("query_addns: "
"dns_db_findrdataset or dns_db_find failed");
/*
* This is bad. We tried to get the NS rdataset at the zone
* top and it didn't work!
@ -2514,7 +3081,7 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
if (is_zone)
authoritative = ISC_TRUE;
if (event == NULL && client->query.restarts == 0) {
if (is_zone) {
dns_zone_attach(zone, &client->query.authzone);
@ -2838,7 +3405,7 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
/*
* Add SOA.
*/
result = query_addsoa(client, db, ISC_FALSE);
result = query_addsoa(client, db, version, ISC_FALSE);
if (result != ISC_R_SUCCESS) {
QUERY_ERROR(result);
goto cleanup;
@ -2879,9 +3446,9 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
* resolver and not have it cached.
*/
if (qtype == dns_rdatatype_soa)
result = query_addsoa(client, db, ISC_TRUE);
result = query_addsoa(client, db, version, ISC_TRUE);
else
result = query_addsoa(client, db, ISC_FALSE);
result = query_addsoa(client, db, version, ISC_FALSE);
if (result != ISC_R_SUCCESS) {
QUERY_ERROR(result);
goto cleanup;
@ -3205,7 +3772,8 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
/*
* Add SOA.
*/
result = query_addsoa(client, db, ISC_FALSE);
result = query_addsoa(client, db, version,
ISC_FALSE);
if (result == ISC_R_SUCCESS)
result = ISC_R_NOMORE;
} else {
@ -3257,7 +3825,7 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
qtype == dns_rdatatype_any) &&
dns_name_equal(client->query.qname,
dns_db_origin(db))))
(void)query_addns(client, db);
(void)query_addns(client, db, version);
} else if (qtype != dns_rdatatype_ns) {
if (fname != NULL)
query_releasename(client, &fname);

View File

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: server.c,v 1.433 2004/11/10 22:14:28 marka Exp $ */
/* $Id: server.c,v 1.434 2004/12/21 10:45:15 jinmei Exp $ */
#include <config.h>
@ -41,6 +41,7 @@
#include <bind9/check.h>
#include <dns/acache.h>
#include <dns/adb.h>
#include <dns/cache.h>
#include <dns/db.h>
@ -733,6 +734,7 @@ configure_view(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
isc_result_t result;
isc_uint32_t max_adb_size;
isc_uint32_t max_cache_size;
isc_uint32_t max_acache_size;
isc_uint32_t lame_ttl;
dns_tsig_keyring_t *ring;
dns_view_t *pview = NULL; /* Production view */
@ -776,6 +778,51 @@ configure_view(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
CHECKM(ns_config_getport(config, &port), "port");
dns_view_setdstport(view, port);
/*
* Create additional cache for this view and zones under the view
* unless explicitly disabled.
*/
obj = NULL;
ns_config_get(maps, "use-additional-cache", &obj);
if (obj == NULL || cfg_obj_asboolean(obj)) {
cmctx = NULL;
CHECK(isc_mem_create(0, 0, &cmctx));
CHECK(dns_acache_create(&view->acache, cmctx, ns_g_taskmgr,
ns_g_timermgr));
isc_mem_detach(&cmctx);
}
if (view->acache != NULL) {
obj = NULL;
result = ns_config_get(maps, "acache-cleaning-interval", &obj);
INSIST(result == ISC_R_SUCCESS);
dns_acache_setcleaninginterval(view->acache,
cfg_obj_asuint32(obj) * 60);
obj = NULL;
result = ns_config_get(maps, "max-acache-size", &obj);
INSIST(result == ISC_R_SUCCESS);
if (cfg_obj_isstring(obj)) {
str = cfg_obj_asstring(obj);
INSIST(strcasecmp(str, "unlimited") == 0);
max_acache_size = ISC_UINT32_MAX;
} else {
isc_resourcevalue_t value;
value = cfg_obj_asuint64(obj);
if (value > ISC_UINT32_MAX) {
cfg_obj_log(obj, ns_g_lctx, ISC_LOG_ERROR,
"'max-acache-size "
"%" ISC_PRINT_QUADFORMAT
"d' is too large",
value);
result = ISC_R_RANGE;
goto cleanup;
}
max_acache_size = (isc_uint32_t)value;
}
dns_acache_setcachesize(view->acache, max_acache_size);
}
/*
* Configure the zones.
*/
@ -1737,6 +1784,8 @@ configure_zone(cfg_obj_t *config, cfg_obj_t *zconfig, cfg_obj_t *vconfig,
* new view.
*/
dns_zone_setview(zone, view);
if (view->acache != NULL)
dns_zone_setacache(zone, view->acache);
} else {
/*
* We cannot reuse an existing zone, we have
@ -1745,6 +1794,8 @@ configure_zone(cfg_obj_t *config, cfg_obj_t *zconfig, cfg_obj_t *vconfig,
CHECK(dns_zone_create(&zone, mctx));
CHECK(dns_zone_setorigin(zone, origin));
dns_zone_setview(zone, view);
if (view->acache != NULL)
dns_zone_setacache(zone, view->acache);
CHECK(dns_zonemgr_managezone(ns_g_server->zonemgr, zone));
}

View File

@ -2,7 +2,7 @@
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.0//EN"
"http://www.oasis-open.org/docbook/xml/4.0/docbookx.dtd">
<!-- File: $Id: Bv9ARM-book.xml,v 1.259 2004/11/11 01:08:24 marka Exp $ -->
<!-- File: $Id: Bv9ARM-book.xml,v 1.260 2004/12/21 10:45:16 jinmei Exp $ -->
<book>
<title>BIND 9 Administrator Reference Manual</title>
@ -392,7 +392,12 @@ signed zones, serving many thousands of queries per second.</para></sect1>
cache and zones loaded off disk. The <command>max-cache-size</command>
option can be used to limit the amount of memory used by the cache,
at the expense of reducing cache hit rates and causing more <acronym>DNS</acronym>
traffic. It is still good practice to have enough memory to load
traffic.
Additionally, if additional section caching
(<xref linkend="acache"/>) is enabled,
the <command>max-acache-size</command> can be used to limit the amount
of memory used by the mechanism.
It is still good practice to have enough memory to load
all zone and cache data into memory &mdash; unfortunately, the best way
to determine this for a given installation is to watch the name server
in operation. After a few weeks the server process should reach
@ -2800,8 +2805,11 @@ statement in the <filename>named.conf</filename> file:</para>
<optional> edns-udp-size <replaceable>number</replaceable>; </optional>
<optional> root-delegation-only <optional> exclude { <replaceable>namelist</replaceable> } </optional> ; </optional>
<optional> querylog <replaceable>yes_or_no</replaceable> ; </optional>
};
<optional> disable-algorithms <replaceable>domain</replaceable> { <replaceable>algorithm</replaceable>; <optional> <replaceable>algorithm</replaceable>; </optional> }; </optional>
<optional> use-additional-cache <replaceable>yes_or_no</replaceable> ; </optional>
<optional> acache-cleaning-interval <replaceable>number</replaceable>; </optional>
<optional> max-acache-size <replaceable>size_spec</replaceable> ; </optional>
};
</programlisting>
</sect2>
@ -4346,6 +4354,99 @@ to be incremented, and may additionally cause the
</sect3>
<sect3 id="acache">
<title>Additional Section Caching</title>
<para>
The additional section cache, also called <command>acache,</command>
is an internal cache to improve the response performance of BIND 9.
When the additional section caching is enabled, BIND 9 will
cache internal short-cut to the additional section content for each
answer RR.
Note that acache is an internal caching mechanism of BIND 9, and is
not relevant to the DNS caching server function.
</para>
<para>
The additional section caching does not make any difference on the
response content (except the RRsets ordering of the additional
section, see below), but can improve the response performance significantly.
It is particularly effective when BIND 9 acts as an authoritative server
for a zone that has many delegations with many glue RRs.
</para>
<para>
In order to achieve the maximum performance improvement by acache,
it is recommended to set <command>additional-from-cache</command>
to <command>no</command>, since the current implementation of acache
does not make a short-cut of additional section information from a DNS
cache data.
</para>
<para>
One obvious disadvantage of acache is that it requires much more
memory for the internal cached data.
Thus, if the response performance does not matter and memory
consumption is much more severe, the acache mechanism can be
disabled by setting <command>use-additional-cache</command> to
<command>no</command>.
It is also possible to specify the upper limit of memory consumption
for acache by <command>max-acache-size</command>.
</para>
<para>
The additional section caching also has a minor effect on the RRset
ordering in the additional section.
Without acache, the "cyclic" order is effective for the additional
section as well as the answer and authority sections.
However, the additional section caching fixes the ordering when it
first caches an RRset for the additional section, and the same
ordering will be kept in succeeding responses, regardless of the
configuration for <command>rrset-order</command>.
This should be minor, though, since an RRset in the additional section
typically only contains a small number of RRs (and in many cases it
only contains a single RR), in which case the
ordering does not matter much.
</para>
<para>
The following is a summary of options related to acache.
</para>
<variablelist>
<varlistentry><term><command>use-additional-cache</command></term>
<listitem><para>
If yes, the additional section caching is enabled.
The default value is yes.
</para>
</listitem></varlistentry>
<varlistentry><term><command>acache-cleaning-interval</command></term>
<listitem><para>
The server will remove stale cache entries, based on an LRU based
algorithm, every <command>acache-cleaning-interval</command> minutes.
The default is 60 minutes.
If set to 0, no periodic cleaning will occur.
</para>
</listitem></varlistentry>
<varlistentry><term><command>max-acache-size</command></term>
<listitem><para>
The maximum amount of memory to use for the server's acache, in bytes.
When the amount of data in the acache reaches this limit, the server
will cause more aggressive cleaning so that the limit is not exceeded.
In a server with multiple views, the limit applies separately to the
acache of each view.
The default is <literal>unlimited</literal>, meaning that
entries are purged from acache only at the periodic cleaning time.
</para>
</listitem></varlistentry>
</variablelist>
</sect3>
</sect2>
<sect2 id="server_statement_grammar">

View File

@ -13,7 +13,7 @@
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
# $Id: Makefile.in,v 1.148 2004/12/09 01:40:59 marka Exp $
# $Id: Makefile.in,v 1.149 2004/12/21 10:45:16 jinmei Exp $
srcdir = @srcdir@
VPATH = @srcdir@
@ -49,7 +49,7 @@ DSTOBJS = dst_api.@O@ dst_lib.@O@ dst_parse.@O@ dst_result.@O@ \
opensslrsa_link.@O@
# Alphabetically
DNSOBJS = acl.@O@ adb.@O@ byaddr.@O@ \
DNSOBJS = acache.@O@ acl.@O@ adb.@O@ byaddr.@O@ \
cache.@O@ callbacks.@O@ compress.@O@ \
db.@O@ dbiterator.@O@ dbtable.@O@ diff.@O@ dispatch.@O@ \
dnssec.@O@ ds.@O@ forward.@O@ journal.@O@ keytable.@O@ \
@ -73,7 +73,7 @@ DSTSRCS = dst_api.c dst_lib.c dst_parse.c \
openssl_link.c openssldh_link.c \
openssldsa_link.c opensslrsa_link.c
DNSSRCS = acl.c adb.c byaddr.c \
DNSSRCS = acache.c acl.c adb.c byaddr.c \
cache.c callbacks.c compress.c \
db.c dbiterator.c dbtable.c diff.c dispatch.c \
dnssec.c ds.c forward.c journal.c keytable.c \

1575
lib/dns/acache.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: db.c,v 1.74 2004/03/05 05:09:18 marka Exp $ */
/* $Id: db.c,v 1.75 2004/12/21 10:45:16 jinmei Exp $ */
/***
*** Imports
@ -791,3 +791,51 @@ dns_db_unregister(dns_dbimplementation_t **dbimp) {
isc_mem_detach(&mctx);
RWUNLOCK(&implock, isc_rwlocktype_write);
}
isc_result_t
dns_db_getsoanode(dns_db_t *db, dns_dbnode_t **nodep) {
REQUIRE(DNS_DB_VALID(db));
REQUIRE(dns_db_iszone(db) == ISC_TRUE);
REQUIRE(nodep != NULL && *nodep == NULL);
if (db->methods->getsoanode != NULL)
return ((db->methods->getsoanode)(db, nodep));
return (ISC_R_NOTFOUND);
}
isc_result_t
dns_db_setsoanode(dns_db_t *db, dns_dbnode_t *node) {
REQUIRE(DNS_DB_VALID(db));
REQUIRE(dns_db_iszone(db) == ISC_TRUE);
REQUIRE(node != NULL);
if (db->methods->setsoanode != NULL)
return ((db->methods->setsoanode)(db, node));
return (ISC_R_FAILURE);
}
isc_result_t
dns_db_getnsnode(dns_db_t *db, dns_dbnode_t **nodep) {
REQUIRE(DNS_DB_VALID(db));
REQUIRE(dns_db_iszone(db) == ISC_TRUE);
REQUIRE(nodep != NULL && *nodep == NULL);
if (db->methods->getnsnode != NULL)
return ((db->methods->getnsnode)(db, nodep));
return (ISC_R_NOTFOUND);
}
isc_result_t
dns_db_setnsnode(dns_db_t *db, dns_dbnode_t *node) {
REQUIRE(DNS_DB_VALID(db));
REQUIRE(dns_db_iszone(db) == ISC_TRUE);
REQUIRE(node != NULL);
if (db->methods->setnsnode != NULL)
return ((db->methods->setnsnode)(db, node));
return (ISC_R_FAILURE);
}

View File

@ -0,0 +1,440 @@
/*
* Copyright (C) 2003 Internet Software Consortium.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
* DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
* INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
* FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: acache.h,v 1.2 2004/12/21 10:45:18 jinmei Exp $ */
#ifndef DNS_ACACHE_H
#define DNS_ACACHE_H 1
/*****
***** Module Info
*****/
/*
* Acache
*
* The Additional Cache Object
*
* This module manages internal caching entries that correspond to
* the additional section data of a DNS DB node (an RRset header, more
* accurately). An additional cache entry is expected to be (somehow)
* attached to a particular RR in a particular DB node, and contains a set
* of information of an additional data for the DB node.
*
* An additional cache object is intended to be created as a per-view
* object, and manages all cache entries within the view.
*
* The intended usage of the additional caching is to provide a short cut
* to additional glue RRs of an NS RR. For each NS RR, it is often
* necessary to look for glue RRs to make a proper response. Once the
* glue RRs are known, the additional caching allows the client to
* associate the information to the original NS RR so that further
* expensive lookups can be avoided for the NS RR.
*
* Each additional cache entry contains information to identify a
* particular DB node and (optionally) an associated RRset. The
* information consists of its zone, database, the version of the
* database, database node, and RRset.
*
* A "negative" information can also be cached. For example, if a glue
* RR does not exist as an authoritative data in the same zone as that
* of the NS RR, this fact can be cached by specifying a NULL pointer
* for the database, version, and node. (See the description for
* dns_acache_getentry() below for more details.)
*
* Since each member stored in an additional cache entry holds a reference
* to a corresponding object, a stale cache entry may cause unnecessary
* memory consumption. For instance, when a zone is reloaded, additional
* cache entries that have a reference to the zone (and its DB and/or
* DB nodes) can delay the cleanup of the referred objects. In order to
* minimize such a bad effect, this module provides several cleanup
* mechanisms.
*
* The first one is a shutdown procedure called when the associated view
* is shut down. In this case, dns_acache_shutdown() will be called and
* all cache entries will be purged. This mechanism will help the
* situation when the configuration is reloaded or the main server is
* stopped.
*
* Per-DB cleanup mechanism is also provided. Each additional cache entry
* is associated with related DB, which is expected to have been
* registered when the DB was created by dns_acache_setdb(). If a
* particular DB is going to be destroyed, the primary holder of the DB,
* a typical example of which is a zone, will call dns_acache_putdb().
* Then this module will clean-up all cache entries associated with the
* DB. This mechanism is effective when a secondary zone DB is going to
* be stale after a zone transfer.
*
* Finally, this module supports for periodic clean-up of stale entries.
* Each cache entry has a timestamp field, which is updated every time
* the entry is referred. A periodically invoked cleaner checks the
* timestamp of each entry, and purge entries that have not been referred
* for a certain period. The cleaner interval can be specified by
* dns_acache_setcleaninginterval(). If the periodic clean-up is not
* enough, it is also possible to specify the upper limit of entries
* in terms of the memory consumption. If the maximum value is
* specified, the cleaner is invoked when the memory consumption reaches
* the high watermark inferred from the maximum value. In this case,
* the cleaner will use more aggressive algorithm to decide the "victim"
* entries. The maximum value can be specified by
* dns_acache_setcachesize().
*
* When a cache entry is going to be purged within this module, the
* callback function specified at the creation time will be called.
* The callback function is expected to release all internal resources
* related to the entry, which will typically be specific to DB
* implementation, and to call dns_acache_detachentry(). The callback
* mechanism is very important, since the holder of an additional cache
* entry may not be able to initiate the clean-up of the entry, due to
* the reference ordering. For example, as long as an additional cache
* entry has a reference to a DB object, the DB cannot be freed, in which
* a DB node may have a reference to the cache entry.
*
* Credits:
* The basic idea of this kind of short-cut for frequently used
* information is similar to the "pre-compiled answer" approach adopted
* in nsd by NLnet LABS with RIPE NCC. Our work here is an independent
* effort, but the success of nsd encouraged us to pursue this path.
*
* The design and implementation of the periodic memory management and
* the upper limitation of memory consumption was derived from the cache
* DB implementation of BIND9.
*
* MP:
* There are two main locks in this module. One is for each entry, and
* the other is for the additional cache object.
*
* Reliability:
* The callback function for a cache entry is called with holding the
* entry lock. Thus, it implicitly assumes the callback function does not
* call a function that can require the lock. Typically, the only
* function that can be called from the callback function safely is
* dns_acache_detachentry(). The breakage of this implicit assumption
* may cause a deadlock.
*
* Resources:
* In a 32-bit architecture (such as i386), the following additional
* memory is required comparing to the case that disables this module.
* - 76 bytes for each additional cache entry
* - if the entry has a DNS name and associated RRset,
* * 44 bytes + size of the name (1-255 bytes)
* * 52 bytes x number_of_RRs
* - 28 bytes for each DB related to this module
*
* Using the additional cache also requires extra memory consumption in
* the DB implementation. In the current implementation for rbtdb, we
* need:
* - two additional pointers for each DB node (8 bytes for a 32-bit
* architecture
* - for each RR associated to an RR in a DB node, we also need
* a pointer and management objects to support the additional cache
* function. These are allocated on-demand. The total size is
* 32 bytes for a 32-bit architecture.
*
* Security:
* Since this module does not handle any low-level data directly,
* no security issue specific to this module is anticipated.
*
* Standards:
* None.
*/
/***
*** Imports
***/
#include <isc/mutex.h>
#include <isc/lang.h>
#include <isc/refcount.h>
#include <isc/stdtime.h>
#include <dns/types.h>
/***
*** Functions
***/
ISC_LANG_BEGINDECLS
isc_result_t
dns_acache_create(dns_acache_t **acachep, isc_mem_t *mctx,
isc_taskmgr_t *taskmgr, isc_timermgr_t *timermgr);
/*
* Create a new DNS additional cache object.
*
* Requires:
*
* 'mctx' is a valid memory context
*
* 'taskmgr' is a valid task manager
*
* 'timermgr' is a valid timer or NULL. If NULL, no periodic cleaning of
* the cache will take place.
*
* 'acachep' is a valid pointer, and *acachep == NULL
*
* Ensures:
*
* '*acachep' is attached to the newly created cache
*
* Returns:
*
* ISC_R_SUCCESS
* ISC_R_NOMEMORY
* ISC_R_UNEXPECTED
*/
void
dns_acache_attach(dns_acache_t *source, dns_acache_t **targetp);
/*
* Attach *targetp to cache.
*
* Requires:
*
* 'acache' is a valid additional cache.
*
* 'targetp' points to a NULL dns_acache_t *.
*
* Ensures:
*
* *targetp is attached to the 'source' additional cache.
*/
void
dns_acache_detach(dns_acache_t **acachep);
/*
* Detach *acachep from its cache.
*
* Requires:
*
* '*acachep' points to a valid additional cache.
*
* Ensures:
*
* *acachep is NULL.
*
* If '*acachep' is the last reference to the cache and the additional
* cache does not have an outstanding task, all resources used by the
* cache will be freed.
*/
void
dns_acache_setcleaninginterval(dns_acache_t *acache, unsigned int t);
/*
* Set the periodic cleaning interval of an additional cache to 'interval'
* seconds.
*/
void
dns_acache_setcachesize(dns_acache_t *acache, isc_uint32_t size);
/*
* Set the maximum additional cache size. 0 means unlimited.
*/
isc_result_t
dns_acache_setdb(dns_acache_t *acache, dns_db_t *db);
/*
* Set 'db' in 'acache' when the db can be referred from acache, in order
* to provide a hint for resolving the back reference.
*
* Requires:
* 'acache' is a valid acache pointer.
* 'db' is a valid DNS DB pointer.
*
* Ensures:
* 'acache' will have a reference to 'db'.
*
* Returns:
* ISC_R_SUCCESS
* ISC_R_EXISTS (which means the specified 'db' is already set)
* ISC_R_NOMEMORY
*/
isc_result_t
dns_acache_putdb(dns_acache_t *acache, dns_db_t *db);
/*
* Release 'db' from 'acache' if it has been set by dns_acache_setdb().
*
* Requires:
* 'acache' is a valid acache pointer.
* 'db' is a valid DNS DB pointer.
*
* Ensures:
* 'acache' will release the reference to 'db'. Additionally, the content
* of each cache entry that is related to the 'db' will be released via
* the callback function.
*
* Returns:
* ISC_R_SUCCESS
* ISC_R_NOTFOUND (which means the specified 'db' is not set in 'acache')
* ISC_R_NOMEMORY
*/
void
dns_acache_shutdown(dns_acache_t *acache);
/*
* Shutdown 'acache'.
*
* Requires:
*
* '*acache' is a valid additional cache.
*/
isc_result_t
dns_acache_createentry(dns_acache_t *acache, dns_db_t *origdb,
void (*callback)(dns_acacheentry_t *, void **),
void *cbarg, dns_acacheentry_t **entryp);
/*
* Create an additional cache entry. A new entry is created and attached to
* the given additional cache object. A callback function is also associated
* with the created entry, which will be called when the cache entry is purged
* for some reason.
*
* Requires:
*
* 'acache' is a valid additional cache.
* 'entryp' is a valid pointer, and *entryp == NULL
* 'origdb' is a valid DNS DB pointer.
* 'callback' and 'cbarg' can be NULL. In this case, however, the entry
* is meaningless (and will be cleaned-up in the next periodical
* cleaning).
*
* Ensures:
* '*entryp' will point to a new additional cache entry.
*
* Returns:
* ISC_R_SUCCESS
* ISC_R_NOMEMORY
*/
isc_result_t
dns_acache_getentry(dns_acacheentry_t *entry, dns_zone_t **zonep,
dns_db_t **dbp, dns_dbversion_t **versionp,
dns_dbnode_t **nodep, dns_name_t *fname,
dns_message_t *msg, isc_stdtime_t now);
/*
* Get content from a particular additional cache entry.
*
* Requires:
*
* 'entry' is a valid additional cache entry.
* 'zonep' is a NULL pointer or '*zonep' == NULL (this is the only
* optional parameter.)
* 'dbp' is a valid pointer, and '*dbp' == NULL
* 'versionp' is a valid pointer, and '*versionp' == NULL
* 'nodep' is a valid pointer, and '*nodep' == NULL
* 'fname' is a valid DNS name.
* 'msg' is a valid DNS message.
*
* Ensures:
* Several possible cases can happen according to the content.
* 1. For a positive cache entry,
* '*zonep' will point to the corresponding zone (if zonep is a valid
* pointer),
* '*dbp' will point to a DB for the zone,
* '*versionp' will point to its version, and
* '*nodep' will point to the corresponding DB node.
* 'fname' will have the DNS name of the DB node and contain a list of
* rdataset for the node (which can be an empty list).
*
* 2. For a negative cache entry that means no corresponding zone exists,
* '*zonep' == NULL (if zonep is a valid pointer)
* '*dbp', '*versionp', and '*nodep' will be NULL.
*
* 3. For a negative cache entry that means no corresponding DB node
* exists, '*zonep' will point to the corresponding zone (if zonep is a
* valid pointer),
* '*dbp' will point to a corresponding DB for zone,
* '*versionp' will point to its version.
* '*nodep' will be kept as NULL.
* 'fname' will not change.
*
* On failure, no new references will be created.
*
* Returns:
* ISC_R_SUCCESS
* ISC_R_NOMEMORY
*/
isc_result_t
dns_acache_setentry(dns_acache_t *acache, dns_acacheentry_t *entry,
dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *version,
dns_dbnode_t *node, dns_name_t *fname);
/*
* Set content to a particular additional cache entry.
*
* Requires:
* 'acache' is a valid additional cache.
* 'entry' is a valid additional cache entry.
* All the others pointers are NULL or a valid pointer of the
* corresponding type.
*
* Returns:
* ISC_R_SUCCESS
* ISC_R_NOMEMORY
* ISC_R_NOTFOUND
*/
void
dns_acache_cancelentry(dns_acacheentry_t *entry);
/*
* Cancel the use of the cache entry 'entry'. This function is supposed to
* be called when the node that holds the entry finds the content is not
* correct any more. This function will try to release as much dependency as
* possible, and will be ready to be cleaned-up. The registered callback
* function will be canceled and will never called.
*
* Requires:
* 'entry' is a valid additional cache entry.
*/
void
dns_acache_attachentry(dns_acacheentry_t *source, dns_acacheentry_t **targetp);
/*
* Attach *targetp to the cache entry 'source'.
*
* Requires:
*
* 'source' is a valid additional cache entry.
*
* 'targetp' points to a NULL dns_acacheentry_t *.
*
* Ensures:
*
* *targetp is attached to 'source'.
*/
void
dns_acache_detachentry(dns_acacheentry_t **entryp);
/*
* Detach *entryp from its cache.
*
* Requires:
*
* '*entryp' points to a valid additional cache entry.
*
* Ensures:
*
* *entryp is NULL.
*
* If '*entryp' is the last reference to the entry,
* cache does not have an outstanding task, all resources used by the
* entry (including the entry object itself) will be freed.
*/
ISC_LANG_ENDDECLS
#endif /* DNS_ACACHE_H */

View File

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: db.h,v 1.77 2004/05/14 04:45:57 marka Exp $ */
/* $Id: db.h,v 1.78 2004/12/21 10:45:18 jinmei Exp $ */
#ifndef DNS_DB_H
#define DNS_DB_H 1
@ -145,6 +145,10 @@ typedef struct dns_dbmethods {
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 *);
isc_result_t (*getsoanode)(dns_db_t *db, dns_dbnode_t **nodep);
isc_result_t (*setsoanode)(dns_db_t *db, dns_dbnode_t *nodep);
isc_result_t (*getnsnode)(dns_db_t *db, dns_dbnode_t **nodep);
isc_result_t (*setnsnode)(dns_db_t *db, dns_dbnode_t *nodep);
} dns_dbmethods_t;
typedef isc_result_t
@ -1266,6 +1270,84 @@ dns_db_unregister(dns_dbimplementation_t **dbimp);
* Any memory allocated in *dbimp will be freed.
*/
isc_result_t
dns_db_getsoanode(dns_db_t *db, dns_dbnode_t **nodep);
/*
* Get a cached SOA DB node corresponding to the DB's zone.
*
* Requires:
*
* 'db' is a valid zone database.
* 'nodep' != NULL && '*nodep' == NULL
*
* Ensures:
* On sucess, '*nodep' will point to a DB node for the SOA RR of 'db.'
*
* Returns:
* ISC_R_SUCCESS
* ISC_R_NOTFOUND - an SOA RR node has not been cached in 'db' or SOA RR
* caching is not supported for 'db'
*/
isc_result_t
dns_db_setsoanode(dns_db_t *db, dns_dbnode_t *node);
/*
* Set an SOA DB node as cache corresponding to the DB's zone. If there is
* already a node set in the DB, it will be detached and replaced with the
* new one.
*
* Requires:
*
* 'db' is a valid zone database.
* 'node' is a valid DB node.
*
* Ensures:
* On sucess, '*nodep' will point to a DB node for the SOA RR of 'db.'
*
* Returns:
* ISC_R_SUCCESS
* ISC_R_FAILURE - SOA RR caching is not supported for 'db'
*/
isc_result_t
dns_db_getnsnode(dns_db_t *db, dns_dbnode_t **nodep);
/*
* Get a cached NS DB node corresponding to the DB's zone.
*
* Requires:
*
* 'db' is a valid zone database.
* 'nodep' != NULL && '*nodep' == NULL
*
* Ensures:
* On sucess, '*nodep' will point to a DB node for the NS RR of 'db.'
*
* Returns:
* ISC_R_SUCCESS
* ISC_R_NOTFOUND - an NS RR node has not been cached in 'db' or NS RR
* caching is not supported for 'db'
*/
isc_result_t
dns_db_setnsnode(dns_db_t *db, dns_dbnode_t *node);
/*
* Set an NS DB node as cache corresponding to the DB's zone. If there is
* already a node set in the DB, it will be detached and replaced with the
* new one.
*
* Requires:
*
* 'db' is a valid zone database.
* 'node' is a valid DB node.
*
* Ensures:
* On sucess, '*nodep' will point to a DB node for the NS RR of 'db.'
*
* Returns:
* ISC_R_SUCCESS
* ISC_R_FAILURE - NS RR caching is not supported for 'db'
*/
ISC_LANG_ENDDECLS
#endif /* DNS_DB_H */

View File

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: events.h,v 1.42 2004/03/05 05:09:42 marka Exp $ */
/* $Id: events.h,v 1.43 2004/12/21 10:45:19 jinmei Exp $ */
#ifndef DNS_EVENTS_H
#define DNS_EVENTS_H 1
@ -63,6 +63,10 @@
#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_VIEWACACHESHUTDOWN (ISC_EVENTCLASS_DNS + 37)
#define DNS_EVENT_ACACHECONTROL (ISC_EVENTCLASS_DNS + 38)
#define DNS_EVENT_ACACHECLEAN (ISC_EVENTCLASS_DNS + 39)
#define DNS_EVENT_ACACHEOVERMEM (ISC_EVENTCLASS_DNS + 40)
#define DNS_EVENT_FIRSTEVENT (ISC_EVENTCLASS_DNS + 0)
#define DNS_EVENT_LASTEVENT (ISC_EVENTCLASS_DNS + 65535)

View File

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: log.h,v 1.33 2004/03/05 05:09:43 marka Exp $ */
/* $Id: log.h,v 1.34 2004/12/21 10:45:19 jinmei Exp $ */
/* Principal Authors: DCL */
@ -69,6 +69,7 @@ LIBDNS_EXTERNAL_DATA extern isc_logmodule_t dns_modules[];
#define DNS_LOGMODULE_SDB (&dns_modules[22])
#define DNS_LOGMODULE_DIFF (&dns_modules[23])
#define DNS_LOGMODULE_HINTS (&dns_modules[24])
#define DNS_LOGMODULE_ACACHE (&dns_modules[25])
ISC_LANG_BEGINDECLS

View File

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: rdataset.h,v 1.51 2004/03/05 05:09:45 marka Exp $ */
/* $Id: rdataset.h,v 1.52 2004/12/21 10:45:19 jinmei Exp $ */
#ifndef DNS_RDATASET_H
#define DNS_RDATASET_H 1
@ -54,11 +54,18 @@
#include <isc/lang.h>
#include <isc/magic.h>
#include <isc/stdtime.h>
#include <dns/types.h>
ISC_LANG_BEGINDECLS
typedef enum {
dns_rdatasetadditional_fromauth,
dns_rdatasetadditional_fromcache,
dns_rdatasetadditional_fromglue
} dns_rdatasetadditional_t;
typedef struct dns_rdatasetmethods {
void (*disassociate)(dns_rdataset_t *rdataset);
isc_result_t (*first)(dns_rdataset_t *rdataset);
@ -74,6 +81,30 @@ typedef struct dns_rdatasetmethods {
dns_name_t *name,
dns_rdataset_t *nsec,
dns_rdataset_t *nsecsig);
isc_result_t (*getadditional)(dns_rdataset_t *rdataset,
dns_rdatasetadditional_t type,
dns_rdatatype_t qtype,
dns_acache_t *acache,
dns_zone_t **zonep,
dns_db_t **dbp,
dns_dbversion_t **versionp,
dns_dbnode_t **nodep,
dns_name_t *fname,
dns_message_t *msg,
isc_stdtime_t now);
isc_result_t (*setadditional)(dns_rdataset_t *rdataset,
dns_rdatasetadditional_t type,
dns_rdatatype_t qtype,
dns_acache_t *acache,
dns_zone_t *zone,
dns_db_t *db,
dns_dbversion_t *version,
dns_dbnode_t *node,
dns_name_t *fname);
isc_result_t (*putadditional)(dns_acache_t *acache,
dns_rdataset_t *rdataset,
dns_rdatasetadditional_t type,
dns_rdatatype_t qtype);
} dns_rdatasetmethods_t;
#define DNS_RDATASET_MAGIC ISC_MAGIC('D','N','S','R')
@ -409,7 +440,6 @@ dns_rdataset_towirepartial(dns_rdataset_t *rdataset,
* written.
*/
isc_result_t
dns_rdataset_additionaldata(dns_rdataset_t *rdataset,
dns_additionaldatafunc_t add, void *arg);
@ -463,6 +493,100 @@ dns_rdataset_addnoqname(dns_rdataset_t *rdataset, dns_name_t *name);
* 'name' to be valid and have NSEC and RRSIG(NSEC) rdatasets.
*/
isc_result_t
dns_rdataset_getadditional(dns_rdataset_t *rdataset,
dns_rdatasetadditional_t type,
dns_rdatatype_t qtype,
dns_acache_t *acache,
dns_zone_t **zonep,
dns_db_t **dbp,
dns_dbversion_t **versionp,
dns_dbnode_t **nodep,
dns_name_t *fname,
dns_message_t *msg,
isc_stdtime_t now);
/*
* Get cached additional information from the DB node for a particular
* 'rdataset.' 'type' is one of dns_rdatasetadditional_fromauth,
* dns_rdatasetadditional_fromcache, and dns_rdatasetadditional_fromglue,
* which specifies the origin of the information. 'qtype' is intended to
* be used for specifying a particular rdata type in the cached information.
*
* Requires:
* 'rdataset' is a valid rdataset.
* 'acache' can be NULL, in which case this function will simply return
* ISC_R_FAILURE.
* For the other pointers, see dns_acache_getentry().
*
* Ensures:
* See dns_acache_getentry().
*
* Returns:
* ISC_R_SUCCESS
* ISC_R_FAILURE - additional information caching is not supported.
* ISC_R_NOTFOUND - the corresponding DB node has not cached additional
* information for 'rdataset.'
*
* Any error that dns_acache_getentry() can return.
*/
isc_result_t
dns_rdataset_setadditional(dns_rdataset_t *rdataset,
dns_rdatasetadditional_t type,
dns_rdatatype_t qtype,
dns_acache_t *acache,
dns_zone_t *zone,
dns_db_t *db,
dns_dbversion_t *version,
dns_dbnode_t *node,
dns_name_t *fname);
/*
* Set cached additional information to the DB node for a particular
* 'rdataset.' See dns_rdataset_getadditional for the semantics of 'type'
* and 'qtype'.
*
* Requires:
* 'rdataset' is a valid rdataset.
* 'acache' can be NULL, in which case this function will simply return
* ISC_R_FAILURE.
* For the other pointers, see dns_acache_setentry().
*
* Ensures:
* See dns_acache_setentry().
*
* Returns:
* ISC_R_SUCCESS
* ISC_R_FAILURE - additional information caching is not supported.
* ISC_R_NOMEMORY
*
* Any error that dns_acache_setentry() can return.
*/
isc_result_t
dns_rdataset_putadditional(dns_acache_t *acache,
dns_rdataset_t *rdataset,
dns_rdatasetadditional_t type,
dns_rdatatype_t qtype);
/*
* Discard cached additional information stored in the DB node for a particular
* 'rdataset.' See dns_rdataset_getadditional for the semantics of 'type'
* and 'qtype'.
*
* Requires:
* 'rdataset' is a valid rdataset.
* 'acache' can be NULL, in which case this function will simply return
* ISC_R_FAILURE.
*
* Ensures:
* See dns_acache_cancelentry().
*
* Returns:
* ISC_R_SUCCESS
* ISC_R_FAILURE - additional information caching is not supported.
* ISC_R_NOTFOUND - the corresponding DB node has not cached additional
* information for 'rdataset.'
*/
ISC_LANG_ENDDECLS
#endif /* DNS_RDATASET_H */

View File

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: types.h,v 1.110 2004/03/30 02:13:44 marka Exp $ */
/* $Id: types.h,v 1.111 2004/12/21 10:45:19 jinmei Exp $ */
#ifndef DNS_TYPES_H
#define DNS_TYPES_H 1
@ -30,6 +30,8 @@
#include <isc/types.h>
typedef struct dns_acache dns_acache_t;
typedef struct dns_acacheentry dns_acacheentry_t;
typedef struct dns_acl dns_acl_t;
typedef struct dns_aclelement dns_aclelement_t;
typedef struct dns_aclenv dns_aclenv_t;

View File

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: view.h,v 1.91 2004/03/10 02:19:56 marka Exp $ */
/* $Id: view.h,v 1.92 2004/12/21 10:45:19 jinmei Exp $ */
#ifndef DNS_VIEW_H
#define DNS_VIEW_H 1
@ -86,6 +86,7 @@ struct dns_view {
dns_resolver_t * resolver;
dns_adb_t * adb;
dns_requestmgr_t * requestmgr;
dns_acache_t * acache;
dns_cache_t * cache;
dns_db_t * cachedb;
dns_db_t * hints;

View File

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: zone.h,v 1.127 2004/10/26 02:01:19 marka Exp $ */
/* $Id: zone.h,v 1.128 2004/12/21 10:45:19 jinmei Exp $ */
#ifndef DNS_ZONE_H
#define DNS_ZONE_H 1
@ -1432,6 +1432,19 @@ dns_zone_checknames(dns_zone_t *zone, dns_name_t *name, dns_rdata_t *rdata);
* DNS_R_BADNAME failed rdata checks.
*/
void
dns_zone_setacache(dns_zone_t *zone, dns_acache_t *acache);
/*
* Associate the zone with an additional cache.
*
* Require:
* 'zone' to be a valid zone.
* 'acache' to be a non NULL pointer.
*
* Ensures:
* 'zone' will have a reference to 'acache'
*/
ISC_LANG_ENDDECLS
#endif /* DNS_ZONE_H */

View File

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: log.c,v 1.36 2004/03/05 05:09:20 marka Exp $ */
/* $Id: log.c,v 1.37 2004/12/21 10:45:16 jinmei Exp $ */
/* Principal Authors: DCL */
@ -74,6 +74,7 @@ LIBDNS_EXTERNAL_DATA isc_logmodule_t dns_modules[] = {
{ "dns/sdb", 0 },
{ "dns/diff", 0 },
{ "dns/hints", 0 },
{ "dns/acache", 0 },
{ NULL, 0 }
};

View File

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: ncache.c,v 1.36 2004/03/05 05:09:21 marka Exp $ */
/* $Id: ncache.c,v 1.37 2004/12/21 10:45:17 jinmei Exp $ */
#include <config.h>
@ -473,6 +473,9 @@ static dns_rdatasetmethods_t rdataset_methods = {
rdataset_clone,
rdataset_count,
NULL,
NULL,
NULL,
NULL,
NULL
};

View File

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: rbtdb.c,v 1.200 2004/05/23 06:59:20 marka Exp $ */
/* $Id: rbtdb.c,v 1.201 2004/12/21 10:45:17 jinmei Exp $ */
/*
* Principal Author: Bob Halley
@ -34,6 +34,7 @@
#include <isc/task.h>
#include <isc/util.h>
#include <dns/acache.h>
#include <dns/db.h>
#include <dns/dbiterator.h>
#include <dns/events.h>
@ -46,6 +47,8 @@
#include <dns/rdatasetiter.h>
#include <dns/rdataslab.h>
#include <dns/result.h>
#include <dns/view.h>
#include <dns/zone.h>
#include <dns/zonekey.h>
#ifdef DNS_RBTDB_VERSION64
@ -103,6 +106,8 @@ struct noqname {
void * nsecsig;
};
typedef struct acachectl acachectl_t;
typedef struct rdatasetheader {
/*
* Locked by the owning node's lock.
@ -140,6 +145,9 @@ typedef struct rdatasetheader {
* should not be so crucial, no lock is set for the counter for
* performance reasons.
*/
acachectl_t *additional_auth;
acachectl_t *additional_glue;
} rdatasetheader_t;
#define RDATASET_ATTR_NONEXISTENT 0x0001
@ -148,6 +156,19 @@ typedef struct rdatasetheader {
#define RDATASET_ATTR_RETAIN 0x0008
#define RDATASET_ATTR_NXDOMAIN 0x0010
typedef struct acache_cbarg {
dns_rdatasetadditional_t type;
unsigned int count;
dns_db_t *db;
dns_dbnode_t *node;
rdatasetheader_t *header;
} acache_cbarg_t;
struct acachectl {
dns_acacheentry_t *entry;
acache_cbarg_t *cbarg;
};
/*
* XXX
* When the cache will pre-expire data (due to memory low or other
@ -219,6 +240,8 @@ typedef struct {
rbtdb_versionlist_t open_versions;
isc_boolean_t overmem;
isc_task_t * task;
dns_dbnode_t *soanode;
dns_dbnode_t *nsnode;
/* Locked by tree_lock. */
dns_rbt_t * tree;
isc_boolean_t secure;
@ -264,6 +287,30 @@ static isc_result_t rdataset_getnoqname(dns_rdataset_t *rdataset,
dns_name_t *name,
dns_rdataset_t *nsec,
dns_rdataset_t *nsecsig);
static isc_result_t rdataset_getadditional(dns_rdataset_t *rdataset,
dns_rdatasetadditional_t type,
dns_rdatatype_t qtype,
dns_acache_t *acache,
dns_zone_t **zonep,
dns_db_t **dbp,
dns_dbversion_t **versionp,
dns_dbnode_t **nodep,
dns_name_t *fname,
dns_message_t *msg,
isc_stdtime_t now);
static isc_result_t rdataset_setadditional(dns_rdataset_t *rdataset,
dns_rdatasetadditional_t type,
dns_rdatatype_t qtype,
dns_acache_t *acache,
dns_zone_t *zone,
dns_db_t *db,
dns_dbversion_t *version,
dns_dbnode_t *node,
dns_name_t *fname);
static isc_result_t rdataset_putadditional(dns_acache_t *acache,
dns_rdataset_t *rdataset,
dns_rdatasetadditional_t type,
dns_rdatatype_t qtype);
static dns_rdatasetmethods_t rdataset_methods = {
rdataset_disassociate,
@ -273,7 +320,10 @@ static dns_rdatasetmethods_t rdataset_methods = {
rdataset_clone,
rdataset_count,
NULL,
rdataset_getnoqname
rdataset_getnoqname,
rdataset_getadditional,
rdataset_setadditional,
rdataset_putadditional
};
static void rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp);
@ -468,6 +518,11 @@ maybe_free_rbtdb(dns_rbtdb_t *rbtdb) {
/* XXX check for open versions here */
if (rbtdb->soanode != NULL)
dns_db_detachnode((dns_db_t *)rbtdb, &rbtdb->soanode);
if (rbtdb->nsnode != NULL)
dns_db_detachnode((dns_db_t *)rbtdb, &rbtdb->nsnode);
/*
* Even though there are no external direct references, there still
* may be nodes in use.
@ -631,6 +686,35 @@ add_changed(dns_rbtdb_t *rbtdb, rbtdb_version_t *version,
return (changed);
}
static void
free_acachearray(isc_mem_t *mctx, rdatasetheader_t *header,
acachectl_t *array)
{
unsigned int count;
unsigned int i;
unsigned char *raw;
/*
* The caller must be holding the corresponding node lock.
*/
if (array == NULL)
return;
raw = (unsigned char *)header + sizeof(*header);
count = raw[0] * 256 + raw[1];
/*
* Sanity check: since an additional cache entry has a reference to
* the original DB node (in the callback arg), there should be no
* acache entries when the node can be freed.
*/
for (i = 0; i < count; i++)
INSIST(array[i].entry == NULL && array[i].cbarg == NULL);
isc_mem_put(mctx, array, count * sizeof(acachectl_t));
}
static inline void
free_noqname(isc_mem_t *mctx, struct noqname **noqname) {
@ -652,7 +736,10 @@ free_rdataset(isc_mem_t *mctx, rdatasetheader_t *rdataset) {
if (rdataset->noqname != NULL)
free_noqname(mctx, &rdataset->noqname);
free_acachearray(mctx, rdataset, rdataset->additional_auth);
free_acachearray(mctx, rdataset, rdataset->additional_glue);
if ((rdataset->attributes & RDATASET_ATTR_NONEXISTENT) != 0)
size = sizeof(*rdataset);
else
@ -4265,6 +4352,8 @@ addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
newheader->noqname = NULL;
newheader->count = 0;
newheader->trust = rdataset->trust;
newheader->additional_auth = NULL;
newheader->additional_glue = NULL;
if (rbtversion != NULL) {
newheader->serial = rbtversion->serial;
now = 0;
@ -4338,6 +4427,8 @@ subtractrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
newheader->trust = 0;
newheader->noqname = NULL;
newheader->count = 0;
newheader->additional_auth = NULL;
newheader->additional_glue = NULL;
LOCK(&rbtdb->node_locks[rbtnode->locknum].lock);
@ -4390,6 +4481,13 @@ subtractrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
* header, not newheader.
*/
newheader->serial = rbtversion->serial;
/*
* XXXJT: dns_rdataslab_subtract() copied the pointers
* to additional info. We need to clear these fields
* to avoid having duplicated references.
*/
newheader->additional_auth = NULL;
newheader->additional_glue = NULL;
} else if (result == DNS_R_NXRRSET) {
/*
* This subtraction would remove all of the rdata;
@ -4409,6 +4507,8 @@ subtractrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
newheader->serial = rbtversion->serial;
newheader->noqname = NULL;
newheader->count = 0;
newheader->additional_auth = NULL;
newheader->additional_glue = NULL;
} else {
free_rdataset(rbtdb->common.mctx, newheader);
goto unlock;
@ -4474,6 +4574,8 @@ deleterdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
newheader->attributes = RDATASET_ATTR_NONEXISTENT;
newheader->trust = 0;
newheader->noqname = NULL;
newheader->additional_auth = NULL;
newheader->additional_glue = NULL;
if (rbtversion != NULL)
newheader->serial = rbtversion->serial;
else
@ -4556,6 +4658,8 @@ loading_addrdataset(void *arg, dns_name_t *name, dns_rdataset_t *rdataset) {
newheader->serial = 1;
newheader->noqname = NULL;
newheader->count = 0;
newheader->additional_auth = NULL;
newheader->additional_glue = NULL;
result = add(rbtdb, node, rbtdb->current_version, newheader,
DNS_DBADD_MERGE, ISC_TRUE, NULL, 0);
@ -4755,6 +4859,74 @@ ispersistent(dns_db_t *db) {
return (ISC_FALSE);
}
static isc_result_t
getsoanode(dns_db_t *db, dns_dbnode_t **nodep) {
dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
isc_result_t result = ISC_R_SUCCESS;
REQUIRE(VALID_RBTDB(rbtdb));
REQUIRE(nodep != NULL && *nodep == NULL);
LOCK(&rbtdb->lock);
if (rbtdb->soanode != NULL) {
attachnode(db, rbtdb->soanode, nodep);
} else
result = ISC_R_NOTFOUND;
UNLOCK(&rbtdb->lock);
return (result);
}
static isc_result_t
setsoanode(dns_db_t *db, dns_dbnode_t *node) {
dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
REQUIRE(VALID_RBTDB(rbtdb));
REQUIRE(node != NULL);
LOCK(&rbtdb->lock);
if (rbtdb->soanode != NULL)
detachnode(db, &rbtdb->soanode);
attachnode(db, node, &rbtdb->soanode);
UNLOCK(&rbtdb->lock);
return (ISC_R_SUCCESS);
}
static isc_result_t
getnsnode(dns_db_t *db, dns_dbnode_t **nodep) {
dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
isc_result_t result = ISC_R_SUCCESS;
REQUIRE(VALID_RBTDB(rbtdb));
REQUIRE(nodep != NULL && *nodep == NULL);
LOCK(&rbtdb->lock);
if (rbtdb->nsnode != NULL) {
attachnode(db, rbtdb->nsnode, nodep);
} else
result = ISC_R_NOTFOUND;
UNLOCK(&rbtdb->lock);
return (result);
}
static isc_result_t
setnsnode(dns_db_t *db, dns_dbnode_t *node) {
dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
REQUIRE(VALID_RBTDB(rbtdb));
REQUIRE(node != NULL);
LOCK(&rbtdb->lock);
if (rbtdb->nsnode != NULL)
detachnode(db, &rbtdb->nsnode);
attachnode(db, node, &rbtdb->nsnode);
UNLOCK(&rbtdb->lock);
return (ISC_R_SUCCESS);
}
static dns_dbmethods_t zone_methods = {
attach,
detach,
@ -4782,7 +4954,11 @@ static dns_dbmethods_t zone_methods = {
nodecount,
ispersistent,
overmem,
settask
settask,
getsoanode,
setsoanode,
getnsnode,
setnsnode
};
static dns_dbmethods_t cache_methods = {
@ -4812,7 +4988,11 @@ static dns_dbmethods_t cache_methods = {
nodecount,
ispersistent,
overmem,
settask
settask,
getsoanode,
setsoanode,
getnsnode,
setnsnode
};
isc_result_t
@ -5704,3 +5884,346 @@ dbiterator_origin(dns_dbiterator_t *iterator, dns_name_t *name) {
return (dns_name_copy(origin, name, NULL));
}
/*
* Additional cache routines.
*/
static isc_result_t
rdataset_getadditional(dns_rdataset_t *rdataset, dns_rdatasetadditional_t type,
dns_rdatatype_t qtype, dns_acache_t *acache,
dns_zone_t **zonep, dns_db_t **dbp,
dns_dbversion_t **versionp, dns_dbnode_t **nodep,
dns_name_t *fname, dns_message_t *msg,
isc_stdtime_t now)
{
dns_rbtdb_t *rbtdb = rdataset->private1;
dns_rbtnode_t *rbtnode = rdataset->private2;
unsigned char *raw = rdataset->private3;
unsigned int current_count = rdataset->privateuint4;
unsigned int count;
rdatasetheader_t *header;
isc_mutex_t *nodelock;
unsigned int total_count;
acachectl_t *acarray;
dns_acacheentry_t *entry;
isc_result_t result;
UNUSED(qtype); /* we do not use this value at least for now */
UNUSED(acache);
header = (struct rdatasetheader *)(raw - sizeof(*header));
total_count = rdataset_count(rdataset);
INSIST(total_count > current_count);
count = total_count - current_count - 1;
acarray = NULL;
nodelock = &rbtdb->node_locks[rbtnode->locknum].lock;
LOCK(nodelock);
switch (type) {
case dns_rdatasetadditional_fromauth:
acarray = header->additional_auth;
break;
case dns_rdatasetadditional_fromcache:
acarray = NULL;
break;
case dns_rdatasetadditional_fromglue:
acarray = header->additional_glue;
break;
default:
INSIST(0);
}
if (acarray == NULL) {
UNLOCK(nodelock);
return (ISC_R_NOTFOUND);
}
if (acarray[count].entry == NULL) {
UNLOCK(nodelock);
return (ISC_R_NOTFOUND);
}
entry = NULL;
dns_acache_attachentry(acarray[count].entry, &entry);
UNLOCK(nodelock);
result = dns_acache_getentry(entry, zonep, dbp, versionp,
nodep, fname, msg, now);
dns_acache_detachentry(&entry);
return (result);
}
static void
acache_callback(dns_acacheentry_t *entry, void **arg) {
dns_rbtdb_t *rbtdb;
dns_rbtnode_t *rbtnode;
isc_mutex_t *nodelock;
acachectl_t *acarray = NULL;
acache_cbarg_t *cbarg;
unsigned int count;
REQUIRE(arg != NULL);
cbarg = *arg;
/*
* The caller must hold the entry lock.
*/
rbtdb = (dns_rbtdb_t *)cbarg->db;
rbtnode = (dns_rbtnode_t *)cbarg->node;
nodelock = &rbtdb->node_locks[rbtnode->locknum].lock;
LOCK(nodelock);
switch (cbarg->type) {
case dns_rdatasetadditional_fromauth:
acarray = cbarg->header->additional_auth;
break;
case dns_rdatasetadditional_fromglue:
acarray = cbarg->header->additional_glue;
break;
default:
INSIST(0);
}
count = cbarg->count;
if (acarray[count].entry == entry)
acarray[count].entry = NULL;
INSIST(acarray[count].cbarg != NULL);
isc_mem_put(rbtdb->common.mctx, acarray[count].cbarg,
sizeof(acache_cbarg_t));
acarray[count].cbarg = NULL;
dns_acache_detachentry(&entry);
UNLOCK(nodelock);
dns_db_detachnode((dns_db_t *)rbtdb, (dns_dbnode_t **)&rbtnode);
dns_db_detach((dns_db_t **)&rbtdb);
*arg = NULL;
}
static void
acache_cancelentry(isc_mem_t *mctx, dns_acacheentry_t *entry,
acache_cbarg_t **cbargp)
{
acache_cbarg_t *cbarg;
REQUIRE(mctx != NULL);
REQUIRE(entry != NULL);
REQUIRE(cbargp != NULL && *cbargp != NULL);
cbarg = *cbargp;
dns_acache_cancelentry(entry);
dns_db_detachnode(cbarg->db, &cbarg->node);
dns_db_detach(&cbarg->db);
isc_mem_put(mctx, cbarg, sizeof(acache_cbarg_t));
*cbargp = NULL;
}
static isc_result_t
rdataset_setadditional(dns_rdataset_t *rdataset, dns_rdatasetadditional_t type,
dns_rdatatype_t qtype, dns_acache_t *acache,
dns_zone_t *zone, dns_db_t *db,
dns_dbversion_t *version, dns_dbnode_t *node,
dns_name_t *fname)
{
dns_rbtdb_t *rbtdb = rdataset->private1;
dns_rbtnode_t *rbtnode = rdataset->private2;
unsigned char *raw = rdataset->private3;
unsigned int current_count = rdataset->privateuint4;
rdatasetheader_t *header;
unsigned int total_count, count;
isc_mutex_t *nodelock;
isc_mem_t *mctx = rbtdb->common.mctx;
isc_result_t result;
acachectl_t *acarray;
dns_acacheentry_t *newentry, *oldentry = NULL;
acache_cbarg_t *newcbarg, *oldcbarg = NULL;
UNUSED(qtype);
if (type == dns_rdatasetadditional_fromcache)
return (ISC_R_SUCCESS);
header = (struct rdatasetheader *)(raw - sizeof(*header));
total_count = rdataset_count(rdataset);
INSIST(total_count > current_count);
count = total_count - current_count - 1; /* should be private data */
newcbarg = isc_mem_get(mctx, sizeof(*newcbarg));
if (newcbarg == NULL)
return (ISC_R_NOMEMORY);
newcbarg->type = type;
newcbarg->count = count;
newcbarg->header = header;
newcbarg->db = NULL;
dns_db_attach((dns_db_t *)rbtdb, &newcbarg->db);
newcbarg->node = NULL;
dns_db_attachnode((dns_db_t *)rbtdb, (dns_dbnode_t *)rbtnode,
&newcbarg->node);
newentry = NULL;
result = dns_acache_createentry(acache, (dns_db_t *)rbtdb,
acache_callback, newcbarg, &newentry);
if (result != ISC_R_SUCCESS)
goto fail;
/* Set cache data in the new entry. */
result = dns_acache_setentry(acache, newentry, zone, db,
version, node, fname);
if (result != ISC_R_SUCCESS)
goto fail;
nodelock = &rbtdb->node_locks[rbtnode->locknum].lock;
LOCK(nodelock);
acarray = NULL;
switch (type) {
case dns_rdatasetadditional_fromauth:
acarray = header->additional_auth;
break;
case dns_rdatasetadditional_fromglue:
acarray = header->additional_glue;
break;
default:
INSIST(0);
}
if (acarray == NULL) {
unsigned int i;
acarray = isc_mem_get(mctx, total_count *
sizeof(acachectl_t));
if (acarray == NULL) {
UNLOCK(nodelock);
goto fail;
}
for (i = 0; i < total_count; i++) {
acarray[i].entry = NULL;
acarray[i].cbarg = NULL;
}
}
switch (type) {
case dns_rdatasetadditional_fromauth:
header->additional_auth = acarray;
break;
case dns_rdatasetadditional_fromglue:
header->additional_glue = acarray;
break;
default:
INSIST(0);
}
if (acarray[count].entry != NULL) {
/*
* Swap the entry. Delay cleaning-up the old entry since
* it would require a node lock.
*/
oldentry = acarray[count].entry;
INSIST(acarray[count].cbarg != NULL);
oldcbarg = acarray[count].cbarg;
}
acarray[count].entry = newentry;
acarray[count].cbarg = newcbarg;
UNLOCK(nodelock);
if (oldentry != NULL) {
if (oldcbarg != NULL)
acache_cancelentry(mctx, oldentry, &oldcbarg);
dns_acache_detachentry(&oldentry);
}
return (ISC_R_SUCCESS);
fail:
if (newentry != NULL) {
if (newcbarg != NULL)
acache_cancelentry(mctx, newentry, &newcbarg);
dns_acache_detachentry(&newentry);
}
return (result);
}
static isc_result_t
rdataset_putadditional(dns_acache_t *acache, dns_rdataset_t *rdataset,
dns_rdatasetadditional_t type, dns_rdatatype_t qtype)
{
dns_rbtdb_t *rbtdb = rdataset->private1;
dns_rbtnode_t *rbtnode = rdataset->private2;
unsigned char *raw = rdataset->private3;
unsigned int current_count = rdataset->privateuint4;
rdatasetheader_t *header;
isc_mutex_t *nodelock;
unsigned int total_count, count;
acachectl_t *acarray;
dns_acacheentry_t *entry;
acache_cbarg_t *cbarg;
UNUSED(qtype); /* we do not use this value at least for now */
UNUSED(acache);
if (type == dns_rdatasetadditional_fromcache)
return (ISC_R_SUCCESS);
header = (struct rdatasetheader *)(raw - sizeof(*header));
total_count = rdataset_count(rdataset);
INSIST(total_count > current_count);
count = total_count - current_count - 1;
acarray = NULL;
entry = NULL;
nodelock = &rbtdb->node_locks[rbtnode->locknum].lock;
LOCK(nodelock);
switch (type) {
case dns_rdatasetadditional_fromauth:
acarray = header->additional_auth;
break;
case dns_rdatasetadditional_fromglue:
acarray = header->additional_glue;
break;
default:
INSIST(0);
}
if (acarray == NULL) {
UNLOCK(nodelock);
return (ISC_R_NOTFOUND);
}
entry = acarray[count].entry;
if (entry == NULL) {
UNLOCK(nodelock);
return (ISC_R_NOTFOUND);
}
acarray[count].entry = NULL;
cbarg = acarray[count].cbarg;
acarray[count].cbarg = NULL;
UNLOCK(nodelock);
if (entry != NULL) {
if(cbarg != NULL)
acache_cancelentry(rbtdb->common.mctx, entry, &cbarg);
dns_acache_detachentry(&entry);
}
return (ISC_R_SUCCESS);
}

View File

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: rdatalist.c,v 1.28 2004/03/05 05:09:23 marka Exp $ */
/* $Id: rdatalist.c,v 1.29 2004/12/21 10:45:17 jinmei Exp $ */
#include <config.h>
@ -38,7 +38,10 @@ static dns_rdatasetmethods_t methods = {
isc__rdatalist_clone,
isc__rdatalist_count,
isc__rdatalist_addnoqname,
isc__rdatalist_getnoqname
isc__rdatalist_getnoqname,
NULL,
NULL,
NULL
};
void

View File

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: rdataset.c,v 1.72 2004/03/05 05:09:23 marka Exp $ */
/* $Id: rdataset.c,v 1.73 2004/12/21 10:45:17 jinmei Exp $ */
#include <config.h>
@ -174,6 +174,9 @@ static dns_rdatasetmethods_t question_methods = {
question_clone,
question_count,
NULL,
NULL,
NULL,
NULL,
NULL
};
@ -624,3 +627,81 @@ dns_rdataset_getnoqname(dns_rdataset_t *rdataset, dns_name_t *name,
return (ISC_R_NOTIMPLEMENTED);
return((rdataset->methods->getnoqname)(rdataset, name, nsec, nsecsig));
}
/*
* Additional cache stuff
*/
isc_result_t
dns_rdataset_getadditional(dns_rdataset_t *rdataset,
dns_rdatasetadditional_t type,
dns_rdatatype_t qtype,
dns_acache_t *acache,
dns_zone_t **zonep,
dns_db_t **dbp,
dns_dbversion_t **versionp,
dns_dbnode_t **nodep,
dns_name_t *fname,
dns_message_t *msg,
isc_stdtime_t now)
{
REQUIRE(DNS_RDATASET_VALID(rdataset));
REQUIRE(rdataset->methods != NULL);
REQUIRE(zonep == NULL || *zonep == NULL);
REQUIRE(dbp != NULL && *dbp == NULL);
REQUIRE(versionp != NULL && *versionp == NULL);
REQUIRE(nodep != NULL && *nodep == NULL);
REQUIRE(fname != NULL);
REQUIRE(msg != NULL);
if (acache != NULL && rdataset->methods->getadditional != NULL) {
return ((rdataset->methods->getadditional)(rdataset, type,
qtype, acache,
zonep, dbp,
versionp, nodep,
fname, msg, now));
}
return (ISC_R_FAILURE);
}
isc_result_t
dns_rdataset_setadditional(dns_rdataset_t *rdataset,
dns_rdatasetadditional_t type,
dns_rdatatype_t qtype,
dns_acache_t *acache,
dns_zone_t *zone,
dns_db_t *db,
dns_dbversion_t *version,
dns_dbnode_t *node,
dns_name_t *fname)
{
REQUIRE(DNS_RDATASET_VALID(rdataset));
REQUIRE(rdataset->methods != NULL);
if (acache != NULL && rdataset->methods->setadditional != NULL) {
return ((rdataset->methods->setadditional)(rdataset, type,
qtype, acache, zone,
db, version,
node, fname));
}
return (ISC_R_FAILURE);
}
isc_result_t
dns_rdataset_putadditional(dns_acache_t *acache,
dns_rdataset_t *rdataset,
dns_rdatasetadditional_t type,
dns_rdatatype_t qtype)
{
REQUIRE(DNS_RDATASET_VALID(rdataset));
REQUIRE(rdataset->methods != NULL);
if (acache != NULL && rdataset->methods->putadditional != NULL) {
return ((rdataset->methods->putadditional)(acache, rdataset,
type, qtype));
}
return (ISC_R_FAILURE);
}

View File

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: rdataslab.c,v 1.35 2004/03/05 05:09:23 marka Exp $ */
/* $Id: rdataslab.c,v 1.36 2004/12/21 10:45:17 jinmei Exp $ */
#include <config.h>
@ -241,6 +241,9 @@ static dns_rdatasetmethods_t rdataset_methods = {
rdataset_clone,
rdataset_count,
NULL,
NULL,
NULL,
NULL,
NULL
};

View File

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: sdb.c,v 1.46 2004/07/22 03:58:07 marka Exp $ */
/* $Id: sdb.c,v 1.47 2004/12/21 10:45:18 jinmei Exp $ */
#include <config.h>
@ -1234,7 +1234,11 @@ static dns_dbmethods_t sdb_methods = {
nodecount,
ispersistent,
overmem,
settask
settask,
NULL,
NULL,
NULL,
NULL
};
static isc_result_t
@ -1361,7 +1365,10 @@ static dns_rdatasetmethods_t methods = {
rdataset_clone,
isc__rdatalist_count,
isc__rdatalist_addnoqname,
isc__rdatalist_getnoqname
isc__rdatalist_getnoqname,
NULL,
NULL,
NULL
};
static void

View File

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: view.c,v 1.126 2004/03/10 02:19:56 marka Exp $ */
/* $Id: view.c,v 1.127 2004/12/21 10:45:18 jinmei Exp $ */
#include <config.h>
@ -24,6 +24,7 @@
#include <isc/string.h> /* Required for HP/UX (and others?) */
#include <isc/util.h>
#include <dns/acache.h>
#include <dns/acl.h>
#include <dns/adb.h>
#include <dns/cache.h>
@ -120,6 +121,7 @@ dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass,
goto cleanup_trustedkeys;
}
view->acache = NULL;
view->cache = NULL;
view->cachedb = NULL;
view->hints = NULL;
@ -253,6 +255,8 @@ destroy(dns_view_t *view) {
dns_adb_detach(&view->adb);
if (view->resolver != NULL)
dns_resolver_detach(&view->resolver);
if (view->acache != NULL)
dns_acache_detach(&view->acache);
if (view->requestmgr != NULL)
dns_requestmgr_detach(&view->requestmgr);
if (view->task != NULL)
@ -365,6 +369,8 @@ view_flushanddetach(dns_view_t **viewp, isc_boolean_t flush) {
dns_adb_shutdown(view->adb);
if (!REQSHUTDOWN(view))
dns_requestmgr_shutdown(view->requestmgr);
if (view->acache != NULL)
dns_acache_shutdown(view->acache);
if (view->flush)
dns_zt_flushanddetach(&view->zonetable);
else

View File

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: zone.c,v 1.425 2004/11/23 05:23:46 marka Exp $ */
/* $Id: zone.c,v 1.426 2004/12/21 10:45:18 jinmei Exp $ */
#include <config.h>
@ -31,6 +31,7 @@
#include <isc/timer.h>
#include <isc/util.h>
#include <dns/acache.h>
#include <dns/acl.h>
#include <dns/adb.h>
#include <dns/callbacks.h>
@ -206,6 +207,7 @@ struct dns_zone {
dns_ssutable_t *ssutable;
isc_uint32_t sigvalidityinterval;
dns_view_t *view;
dns_acache_t *acache;
/*
* Zones in certain states such as "waiting for zone transfer"
* or "zone transfer in progress" are kept on per-state linked lists
@ -384,6 +386,8 @@ static void zone_iattach(dns_zone_t *source, dns_zone_t **target);
static void zone_idetach(dns_zone_t **zonep);
static isc_result_t zone_replacedb(dns_zone_t *zone, dns_db_t *db,
isc_boolean_t dump);
static inline void zone_attachdb(dns_zone_t *zone, dns_db_t *db);
static inline void zone_detachdb(dns_zone_t *zone);
static isc_result_t default_journal(dns_zone_t *zone);
static void zone_xfrdone(dns_zone_t *zone, isc_result_t result);
static isc_result_t zone_postload(dns_zone_t *zone, dns_db_t *db,
@ -572,6 +576,7 @@ dns_zone_create(dns_zone_t **zonep, isc_mem_t *mctx) {
zone->ssutable = NULL;
zone->sigvalidityinterval = 30 * 24 * 3600;
zone->view = NULL;
zone->acache = NULL;
ISC_LINK_INIT(zone, statelink);
zone->statelist = NULL;
zone->counters = NULL;
@ -636,7 +641,9 @@ zone_free(dns_zone_t *zone) {
if (zone->counters != NULL)
dns_stats_freecounters(zone->mctx, &zone->counters);
if (zone->db != NULL)
dns_db_detach(&zone->db);
zone_detachdb(zone);
if (zone->acache != NULL)
dns_acache_detach(&zone->acache);
zone_freedbargs(zone);
RUNTIME_CHECK(dns_zone_setmasterswithkeys(zone, NULL, NULL, 0)
== ISC_R_SUCCESS);
@ -821,6 +828,33 @@ dns_zone_setorigin(dns_zone_t *zone, dns_name_t *origin) {
return (result);
}
void
dns_zone_setacache(dns_zone_t *zone, dns_acache_t *acache) {
REQUIRE(DNS_ZONE_VALID(zone));
REQUIRE(acache != NULL);
LOCK_ZONE(zone);
if (zone->acache != NULL)
dns_acache_detach(&zone->acache);
dns_acache_attach(acache, &zone->acache);
if (zone->db != NULL) {
isc_result_t result;
/*
* If the zone reuses an existing DB, the DB needs to be
* set in the acache explicitly. We can safely ignore the
* case where the DB is already set. If other error happens,
* the acache will not work effectively.
*/
result = dns_acache_setdb(acache, zone->db);
if (result != ISC_R_SUCCESS && result != ISC_R_EXISTS) {
UNEXPECTED_ERROR(__FILE__, __LINE__,
"dns_acache_setdb() failed: %s",
isc_result_totext(result));
}
}
UNLOCK_ZONE(zone);
}
static isc_result_t
dns_zone_setstring(dns_zone_t *zone, char **field, const char *value) {
@ -1423,7 +1457,7 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime,
if (result != ISC_R_SUCCESS)
goto cleanup;
} else {
dns_db_attach(db, &zone->db);
zone_attachdb(zone, db);
DNS_ZONE_SETFLAG(zone,
DNS_ZONEFLG_LOADED|DNS_ZONEFLG_NEEDNOTIFY);
}
@ -2641,7 +2675,7 @@ zone_unload(dns_zone_t *zone) {
REQUIRE(LOCKED_ZONE(zone));
dns_db_detach(&zone->db);
zone_detachdb(zone);
DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_LOADED);
DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NEEDDUMP);
}
@ -3400,7 +3434,7 @@ stub_callback(isc_task_t *task, isc_event_t *event) {
dns_db_closeversion(stub->db, &stub->version, ISC_TRUE);
LOCK_ZONE(zone);
if (zone->db == NULL)
dns_db_attach(stub->db, &zone->db);
zone_attachdb(zone, stub->db);
UNLOCK_ZONE(zone);
dns_db_detach(&stub->db);
@ -5427,8 +5461,8 @@ zone_replacedb(dns_zone_t *zone, dns_db_t *db, isc_boolean_t dump) {
"replacing zone database");
if (zone->db != NULL)
dns_db_detach(&zone->db);
dns_db_attach(db, &zone->db);
zone_detachdb(zone);
zone_attachdb(zone, db);
dns_db_settask(zone->db, zone->task);
DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_LOADED|DNS_ZONEFLG_NEEDNOTIFY);
return (ISC_R_SUCCESS);
@ -5438,6 +5472,31 @@ zone_replacedb(dns_zone_t *zone, dns_db_t *db, isc_boolean_t dump) {
return (result);
}
static inline void
zone_attachdb(dns_zone_t *zone, dns_db_t *db) {
REQUIRE(zone->db == NULL && db != NULL);
dns_db_attach(db, &zone->db);
if (zone->acache != NULL) {
isc_result_t result;
result = dns_acache_setdb(zone->acache, db);
if (result != ISC_R_SUCCESS && result != ISC_R_EXISTS) {
UNEXPECTED_ERROR(__FILE__, __LINE__,
"dns_acache_setdb() failed: %s",
isc_result_totext(result));
}
}
}
static inline void
zone_detachdb(dns_zone_t *zone) {
REQUIRE(zone->db != NULL);
if (zone->acache != NULL)
(void)dns_acache_putdb(zone->acache, zone->db);
dns_db_detach(&zone->db);
}
static void
zone_xfrdone(dns_zone_t *zone, isc_result_t result) {
isc_time_t now;

View File

@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: namedconf.c,v 1.41 2004/11/11 01:08:24 marka Exp $ */
/* $Id: namedconf.c,v 1.42 2004/12/21 10:45:20 jinmei Exp $ */
#include <config.h>
@ -733,6 +733,9 @@ view_clauses[] = {
{ "dnssec-must-be-secure", &cfg_type_mustbesecure,
CFG_CLAUSEFLAG_MULTI },
{ "ixfr-from-differences", &cfg_type_ixfrdifftype, 0 },
{ "use-additional-cache", &cfg_type_boolean, 0 },
{ "acache-cleaning-interval", &cfg_type_uint32, 0 },
{ "max-acache-size", &cfg_type_sizenodefault, 0 },
{ NULL, NULL, 0 }
};