2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-31 06:25:31 +00:00

Pass time to routines which add or create rdatasets.

Add TTL aging and removal of stale rdatasets (cache databases only).
This commit is contained in:
Bob Halley
1999-04-09 01:12:30 +00:00
parent 63e6086ef9
commit 0b1f55d73f

View File

@@ -66,11 +66,10 @@ typedef isc_uint64_t rbtdb_serial_t;
typedef isc_uint32_t rbtdb_serial_t; typedef isc_uint32_t rbtdb_serial_t;
#endif #endif
/* XXX */
static const rbtdb_serial_t max_serial = ~((rbtdb_serial_t)0);
typedef struct rdatasetheader { typedef struct rdatasetheader {
/* Not locked. */ /*
* Locked by the owning node's lock.
*/
dns_ttl_t ttl; dns_ttl_t ttl;
rbtdb_serial_t serial; rbtdb_serial_t serial;
dns_rdatatype_t type; dns_rdatatype_t type;
@@ -79,6 +78,9 @@ typedef struct rdatasetheader {
* We don't use the LIST macros, because the LIST structure has * We don't use the LIST macros, because the LIST structure has
* both head and tail pointers. We only have a head pointer in * both head and tail pointers. We only have a head pointer in
* the node to save space. * the node to save space.
*
* XXXRTH we could probably do away with 'prev' with a little effort.
* The effort would be worth it for the memory savings.
*/ */
struct rdatasetheader *prev; struct rdatasetheader *prev;
struct rdatasetheader *next; struct rdatasetheader *next;
@@ -86,6 +88,7 @@ typedef struct rdatasetheader {
} rdatasetheader_t; } rdatasetheader_t;
#define RDATASET_ATTR_NONEXISTENT 0x01 #define RDATASET_ATTR_NONEXISTENT 0x01
#define RDATASET_ATTR_STALE 0x02
#define DEFAULT_NODE_LOCK_COUNT 7 /* Should be prime. */ #define DEFAULT_NODE_LOCK_COUNT 7 /* Should be prime. */
@@ -150,8 +153,17 @@ typedef struct {
dns_rbtnode_t * zonecut; dns_rbtnode_t * zonecut;
rdatasetheader_t * zonecut_rdataset; rdatasetheader_t * zonecut_rdataset;
dns_fixedname_t zonecut_name; dns_fixedname_t zonecut_name;
isc_stdtime_t now;
} rbtdb_search_t; } rbtdb_search_t;
/*
* Load Context
*/
typedef struct {
dns_rbtdb_t * rbtdb;
isc_stdtime_t now;
} rbtdb_load_t;
static dns_result_t rdataset_disassociate(dns_rdataset_t *rdatasetp); static dns_result_t rdataset_disassociate(dns_rdataset_t *rdatasetp);
static dns_result_t rdataset_first(dns_rdataset_t *rdataset); static dns_result_t rdataset_first(dns_rdataset_t *rdataset);
static dns_result_t rdataset_next(dns_rdataset_t *rdataset); static dns_result_t rdataset_next(dns_rdataset_t *rdataset);
@@ -470,8 +482,6 @@ clean_cache_node(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node) {
* Caller must be holding the node lock. * Caller must be holding the node lock.
*/ */
/* XXX should remove stale data. */
for (current = node->data; current != NULL; current = top_next) { for (current = node->data; current != NULL; current = top_next) {
top_next = current->next; top_next = current->next;
dcurrent = current->down; dcurrent = current->down;
@@ -483,7 +493,21 @@ clean_cache_node(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node) {
} while (dcurrent != NULL); } while (dcurrent != NULL);
current->down = NULL; current->down = NULL;
} }
/*
* If current is nonexistent or stale, we can clean it up.
*/
if ((current->attributes &
(RDATASET_ATTR_NONEXISTENT|RDATASET_ATTR_STALE)) != 0) {
if (current->prev != NULL)
current->prev->next = current->next;
else
node->data = current->next;
if (current->next != NULL)
current->next->prev = current->prev;
free_rdataset(mctx, current);
}
} }
node->dirty = 0;
} }
static inline void static inline void
@@ -580,20 +604,24 @@ no_references(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node,
/* /*
* Caller must be holding the node lock. * Caller must be holding the node lock.
*/ */
REQUIRE(node->references == 0); REQUIRE(node->references == 0);
if ((rbtdb->common.attributes & DNS_DBATTR_CACHE) != 0) if (node->dirty) {
clean_cache_node(rbtdb, node); if ((rbtdb->common.attributes & DNS_DBATTR_CACHE) != 0)
else if (node->dirty) { clean_cache_node(rbtdb, node);
if (least_serial == 0) { else {
/* if (least_serial == 0) {
* Caller doesn't know the least serial. Get it. /*
*/ * Caller doesn't know the least serial.
LOCK(&rbtdb->lock); * Get it.
least_serial = rbtdb->least_serial; */
UNLOCK(&rbtdb->lock); LOCK(&rbtdb->lock);
least_serial = rbtdb->least_serial;
UNLOCK(&rbtdb->lock);
}
clean_zone_node(rbtdb, node, least_serial);
} }
clean_zone_node(rbtdb, node, least_serial);
} }
INSIST(rbtdb->node_locks[node->locknum].references > 0); INSIST(rbtdb->node_locks[node->locknum].references > 0);
@@ -953,7 +981,8 @@ zone_zonecut_callback(dns_rbtnode_t *node, dns_name_t *name, void *arg) {
static inline void static inline void
bind_rdataset(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, bind_rdataset(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node,
rdatasetheader_t *header, dns_rdataset_t *rdataset) rdatasetheader_t *header, isc_stdtime_t now,
dns_rdataset_t *rdataset)
{ {
unsigned char *raw; unsigned char *raw;
unsigned int count; unsigned int count;
@@ -967,7 +996,7 @@ bind_rdataset(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node,
rdataset->methods = &rdataset_methods; rdataset->methods = &rdataset_methods;
rdataset->rdclass = rbtdb->common.rdclass; rdataset->rdclass = rbtdb->common.rdclass;
rdataset->type = header->type; rdataset->type = header->type;
rdataset->ttl = header->ttl; rdataset->ttl = header->ttl - now;
rdataset->private1 = rbtdb; rdataset->private1 = rbtdb;
rdataset->private2 = node; rdataset->private2 = node;
raw = (unsigned char *)header + sizeof *header; raw = (unsigned char *)header + sizeof *header;
@@ -1030,7 +1059,7 @@ setup_delegation(rbtdb_search_t *search, dns_dbnode_t **nodep,
if (rdataset != NULL) { if (rdataset != NULL) {
LOCK(&(search->rbtdb->node_locks[node->locknum].lock)); LOCK(&(search->rbtdb->node_locks[node->locknum].lock));
bind_rdataset(search->rbtdb, node, search->zonecut_rdataset, bind_rdataset(search->rbtdb, node, search->zonecut_rdataset,
rdataset); search->now, rdataset);
UNLOCK(&(search->rbtdb->node_locks[node->locknum].lock)); UNLOCK(&(search->rbtdb->node_locks[node->locknum].lock));
} }
@@ -1098,7 +1127,7 @@ valid_glue(rbtdb_search_t *search, dns_name_t *name, dns_rdatatype_t type,
static dns_result_t static dns_result_t
zone_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version, zone_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
dns_rdatatype_t type, unsigned int options, dns_rdatatype_t type, unsigned int options, isc_stdtime_t now,
dns_dbnode_t **nodep, dns_name_t *foundname, dns_dbnode_t **nodep, dns_name_t *foundname,
dns_rdataset_t *rdataset) dns_rdataset_t *rdataset)
{ {
@@ -1118,6 +1147,12 @@ zone_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
REQUIRE(VALID_RBTDB(search.rbtdb)); REQUIRE(VALID_RBTDB(search.rbtdb));
/*
* We don't care about 'now'. We set it to zero so compilers won't
* complain about it being unused.
*/
now = 0;
/* /*
* If the caller didn't supply a version, attach to the current * If the caller didn't supply a version, attach to the current
* version. * version.
@@ -1135,6 +1170,7 @@ zone_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
search.zonecut = NULL; search.zonecut = NULL;
dns_fixedname_init(&search.zonecut_name); dns_fixedname_init(&search.zonecut_name);
dns_rbtnodechain_init(&search.chain, search.rbtdb->common.mctx); dns_rbtnodechain_init(&search.chain, search.rbtdb->common.mctx);
search.now = 0;
/* /*
* XXXDNSSEC Set secure_zone properly when implementing DNSSEC. * XXXDNSSEC Set secure_zone properly when implementing DNSSEC.
@@ -1403,7 +1439,7 @@ zone_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
} }
if (rdataset != NULL && type != dns_rdatatype_any) if (rdataset != NULL && type != dns_rdatatype_any)
bind_rdataset(search.rbtdb, node, found, rdataset); bind_rdataset(search.rbtdb, node, found, 0, rdataset);
node_exit: node_exit:
UNLOCK(&(search.rbtdb->node_locks[node->locknum].lock)); UNLOCK(&(search.rbtdb->node_locks[node->locknum].lock));
@@ -1549,7 +1585,7 @@ find_deepest_zonecut(rbtdb_search_t *search, dns_dbnode_t **nodep,
} }
if (rdataset != NULL) if (rdataset != NULL)
bind_rdataset(search->rbtdb, node, header, bind_rdataset(search->rbtdb, node, header,
rdataset); search->now, rdataset);
} }
node_exit: node_exit:
@@ -1564,7 +1600,7 @@ find_deepest_zonecut(rbtdb_search_t *search, dns_dbnode_t **nodep,
static dns_result_t static dns_result_t
cache_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version, cache_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
dns_rdatatype_t type, unsigned int options, dns_rdatatype_t type, unsigned int options, isc_stdtime_t now,
dns_dbnode_t **nodep, dns_name_t *foundname, dns_dbnode_t **nodep, dns_name_t *foundname,
dns_rdataset_t *rdataset) dns_rdataset_t *rdataset)
{ {
@@ -1573,11 +1609,10 @@ cache_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
rbtdb_search_t search; rbtdb_search_t search;
isc_boolean_t cname_ok = ISC_TRUE; isc_boolean_t cname_ok = ISC_TRUE;
isc_boolean_t empty_node; isc_boolean_t empty_node;
rdatasetheader_t *header, *nsheader, *nxtheader; rdatasetheader_t *header, *header_next, *found, *nsheader, *nxtheader;
/* /*
* XXXRTH Currently this code has no support for negative caching, * XXXRTH Currently this code has no support for negative caching.
* nor does it remove/avoid stale rdatasets.
*/ */
search.rbtdb = (dns_rbtdb_t *)db; search.rbtdb = (dns_rbtdb_t *)db;
@@ -1585,14 +1620,23 @@ cache_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
REQUIRE(VALID_RBTDB(search.rbtdb)); REQUIRE(VALID_RBTDB(search.rbtdb));
REQUIRE(version == NULL); REQUIRE(version == NULL);
if (now == 0 && isc_stdtime_get(&now) != ISC_R_SUCCESS) {
/*
* We don't need to call UNEXPECTED_ERROR() because
* isc_stdtime_get() will already have done so.
*/
return (DNS_R_UNEXPECTED);
}
search.rbtversion = NULL; search.rbtversion = NULL;
search.serial = max_serial; search.serial = 1;
search.options = options; search.options = options;
search.copy_name = ISC_FALSE; search.copy_name = ISC_FALSE;
search.need_cleanup = ISC_FALSE; search.need_cleanup = ISC_FALSE;
search.zonecut = NULL; search.zonecut = NULL;
dns_fixedname_init(&search.zonecut_name); dns_fixedname_init(&search.zonecut_name);
dns_rbtnodechain_init(&search.chain, search.rbtdb->common.mctx); dns_rbtnodechain_init(&search.chain, search.rbtdb->common.mctx);
search.now = now;
RWLOCK(&search.rbtdb->tree_lock, isc_rwlocktype_read); RWLOCK(&search.rbtdb->tree_lock, isc_rwlocktype_read);
@@ -1639,14 +1683,38 @@ cache_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
LOCK(&(search.rbtdb->node_locks[node->locknum].lock)); LOCK(&(search.rbtdb->node_locks[node->locknum].lock));
found = NULL;
nsheader = NULL; nsheader = NULL;
nxtheader = NULL; nxtheader = NULL;
empty_node = ISC_TRUE; empty_node = ISC_TRUE;
for (header = node->data; header != NULL; header = header->next) { for (header = node->data; header != NULL; header = header_next) {
if ((header->attributes & RDATASET_ATTR_NONEXISTENT) == 0) { header_next = header->next;
if (header->ttl <= now) {
/*
* This rdataset is stale. If no one else is using the
* node, we can clean it up right now, otherwise we
* mark it as stale, and the node as dirty, so it will
* get cleaned up later.
*/
if (node->references == 0) {
INSIST(header->down == NULL);
if (header->prev != NULL)
header->prev->next = header->next;
else
node->data = header->next;
if (header->next != NULL)
header->next->prev = header->prev;
free_rdataset(search.rbtdb->common.mctx,
header);
} else {
header->attributes |= RDATASET_ATTR_STALE;
node->dirty = 1;
}
} else if ((header->attributes & RDATASET_ATTR_NONEXISTENT)
== 0) {
/* /*
* We now know that there is at least one active * We now know that there is at least one active
* rdataset at this node. * non-stale rdataset at this node.
*/ */
empty_node = ISC_FALSE; empty_node = ISC_FALSE;
@@ -1655,9 +1723,9 @@ cache_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
*/ */
if (header->type == type || if (header->type == type ||
type == dns_rdatatype_any || type == dns_rdatatype_any ||
(cname_ok && header->type == (cname_ok && header->type ==
dns_rdatatype_cname)) { dns_rdatatype_cname)) {
break; found = header;
} else if (header->type == dns_rdatatype_ns) { } else if (header->type == dns_rdatatype_ns) {
/* /*
* Remember a NS rdataset even if we're * Remember a NS rdataset even if we're
@@ -1689,7 +1757,7 @@ cache_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
/* /*
* If we didn't find what we were looking for... * If we didn't find what we were looking for...
*/ */
if (header == NULL) { if (found == NULL) {
/* /*
* XXXDNSSEC If we found an NXT record for this name, we * XXXDNSSEC If we found an NXT record for this name, we
* can tell whether the desired type exists or not. We don't * can tell whether the desired type exists or not. We don't
@@ -1704,7 +1772,8 @@ cache_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
if (nsheader != NULL) { if (nsheader != NULL) {
new_reference(search.rbtdb, node); new_reference(search.rbtdb, node);
*nodep = node; *nodep = node;
bind_rdataset(search.rbtdb, node, nsheader, rdataset); bind_rdataset(search.rbtdb, node, nsheader, search.now,
rdataset);
result = DNS_R_DELEGATION; result = DNS_R_DELEGATION;
goto node_exit; goto node_exit;
} }
@@ -1725,9 +1794,9 @@ cache_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
*nodep = node; *nodep = node;
} }
if (type != header->type && if (type != found->type &&
type != dns_rdatatype_any && type != dns_rdatatype_any &&
header->type == dns_rdatatype_cname) { found->type == dns_rdatatype_cname) {
/* /*
* We weren't doing an ANY query and we found a CNAME instead * We weren't doing an ANY query and we found a CNAME instead
* of the type we were looking for, so we need to indicate * of the type we were looking for, so we need to indicate
@@ -1742,7 +1811,8 @@ cache_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
} }
if (rdataset != NULL && type != dns_rdatatype_any) if (rdataset != NULL && type != dns_rdatatype_any)
bind_rdataset(search.rbtdb, node, header, rdataset); bind_rdataset(search.rbtdb, node, found, search.now,
rdataset);
node_exit: node_exit:
UNLOCK(&(search.rbtdb->node_locks[node->locknum].lock)); UNLOCK(&(search.rbtdb->node_locks[node->locknum].lock));
@@ -1850,8 +1920,9 @@ createiterator(dns_db_t *db, dns_dbversion_t *version,
} }
static dns_result_t static dns_result_t
findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, zone_findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
dns_rdatatype_t type, dns_rdataset_t *rdataset) dns_rdatatype_t type, isc_stdtime_t now,
dns_rdataset_t *rdataset)
{ {
dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db; dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
dns_rbtnode_t *rbtnode = (dns_rbtnode_t *)node; dns_rbtnode_t *rbtnode = (dns_rbtnode_t *)node;
@@ -1863,14 +1934,11 @@ findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
REQUIRE(VALID_RBTDB(rbtdb)); REQUIRE(VALID_RBTDB(rbtdb));
REQUIRE(type != dns_rdatatype_any); REQUIRE(type != dns_rdatatype_any);
if ((db->attributes & DNS_DBATTR_CACHE) == 0) { if (rbtversion == NULL) {
if (rbtversion == NULL) { currentversion(db, (dns_dbversion_t **)(&rbtversion));
currentversion(db, (dns_dbversion_t **)(&rbtversion)); close_version = ISC_TRUE;
close_version = ISC_TRUE; }
} serial = rbtversion->serial;
serial = rbtversion->serial;
} else
serial = max_serial;
LOCK(&rbtdb->node_locks[rbtnode->locknum].lock); LOCK(&rbtdb->node_locks[rbtnode->locknum].lock);
@@ -1893,7 +1961,7 @@ findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
} }
} }
if (header != NULL) if (header != NULL)
bind_rdataset(rbtdb, rbtnode, header, rdataset); bind_rdataset(rbtdb, rbtnode, header, now, rdataset);
UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock); UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock);
@@ -1906,9 +1974,62 @@ findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
return (DNS_R_SUCCESS); return (DNS_R_SUCCESS);
} }
static dns_result_t
cache_findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
dns_rdatatype_t type, isc_stdtime_t now,
dns_rdataset_t *rdataset)
{
dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
dns_rbtnode_t *rbtnode = (dns_rbtnode_t *)node;
rdatasetheader_t *header, *header_next, *found;
REQUIRE(VALID_RBTDB(rbtdb));
REQUIRE(type != dns_rdatatype_any);
version = NULL; /* Keep compilers quiet. */
if (now == 0 && isc_stdtime_get(&now) != ISC_R_SUCCESS) {
/*
* We don't need to call UNEXPECTED_ERROR() because
* isc_stdtime_get() will already have done so.
*/
return (DNS_R_UNEXPECTED);
}
LOCK(&rbtdb->node_locks[rbtnode->locknum].lock);
found = NULL;
for (header = rbtnode->data; header != NULL; header = header_next) {
header_next = header->next;
if (header->ttl <= now) {
/*
* We don't check if rbtnode->references == 0 and try
* to free like we do in cache_find(), because
* rbtnode->references must be non-zero. This is so
* because 'node' is an argument to the function.
*/
header->attributes |= RDATASET_ATTR_STALE;
rbtnode->dirty = 1;
} else if (header->type == type &&
(header->attributes & RDATASET_ATTR_NONEXISTENT) ==
0) {
found = header;
}
}
if (found != NULL)
bind_rdataset(rbtdb, rbtnode, found, now, rdataset);
UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock);
if (found == NULL)
return (DNS_R_NOTFOUND);
return (DNS_R_SUCCESS);
}
static dns_result_t static dns_result_t
allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
dns_rdatasetiter_t **iteratorp) isc_stdtime_t now, dns_rdatasetiter_t **iteratorp)
{ {
dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db; dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
dns_rbtnode_t *rbtnode = (dns_rbtnode_t *)node; dns_rbtnode_t *rbtnode = (dns_rbtnode_t *)node;
@@ -1922,24 +2043,28 @@ allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
return (DNS_R_NOMEMORY); return (DNS_R_NOMEMORY);
if ((db->attributes & DNS_DBATTR_CACHE) == 0) { if ((db->attributes & DNS_DBATTR_CACHE) == 0) {
LOCK(&rbtdb->lock); now = 0;
if (rbtversion == NULL) { if (rbtversion == NULL)
rbtversion = rbtdb->current_version; currentversion(db, (dns_dbversion_t **)(&rbtversion));
if (rbtversion->references == 0) } else {
PREPEND(rbtdb->open_versions, rbtversion, if (now == 0 && isc_stdtime_get(&now) != ISC_R_SUCCESS) {
link); /*
* We don't need to call UNEXPECTED_ERROR() because
* isc_stdtime_get() will already have done so.
*/
isc_mem_put(rbtdb->common.mctx, iterator,
sizeof *iterator);
return (DNS_R_UNEXPECTED);
} }
rbtversion->references++;
INSIST(rbtversion->references != 0);
UNLOCK(&rbtdb->lock);
} else
rbtversion = NULL; rbtversion = NULL;
}
iterator->common.magic = DNS_RDATASETITER_MAGIC; iterator->common.magic = DNS_RDATASETITER_MAGIC;
iterator->common.methods = &rdatasetiter_methods; iterator->common.methods = &rdatasetiter_methods;
iterator->common.db = db; iterator->common.db = db;
iterator->common.node = node; iterator->common.node = node;
iterator->common.version = (dns_dbversion_t *)rbtversion; iterator->common.version = (dns_dbversion_t *)rbtversion;
iterator->common.now = now;
LOCK(&rbtdb->node_locks[rbtnode->locknum].lock); LOCK(&rbtdb->node_locks[rbtnode->locknum].lock);
@@ -2046,10 +2171,9 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion,
newheader->down = header; newheader->down = header;
header->prev = newheader; header->prev = newheader;
header->next = NULL; header->next = NULL;
if (changed != NULL) { rbtnode->dirty = 1;
rbtnode->dirty = 1; if (changed != NULL)
changed->dirty = ISC_TRUE; changed->dirty = ISC_TRUE;
}
} }
} else { } else {
/* /*
@@ -2081,7 +2205,7 @@ delegating_type(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node,
static dns_result_t static dns_result_t
addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
dns_rdataset_t *rdataset) isc_stdtime_t now, dns_rdataset_t *rdataset)
{ {
dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db; dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
dns_rbtnode_t *rbtnode = (dns_rbtnode_t *)node; dns_rbtnode_t *rbtnode = (dns_rbtnode_t *)node;
@@ -2093,6 +2217,12 @@ addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
REQUIRE(VALID_RBTDB(rbtdb)); REQUIRE(VALID_RBTDB(rbtdb));
if (rbtversion == NULL) {
if (now == 0 && isc_stdtime_get(&now) != ISC_R_SUCCESS)
return (DNS_R_UNEXPECTED);
} else
now = 0;
result = dns_rdataslab_fromrdataset(rdataset, rbtdb->common.mctx, result = dns_rdataslab_fromrdataset(rdataset, rbtdb->common.mctx,
&region, &region,
sizeof (rdatasetheader_t)); sizeof (rdatasetheader_t));
@@ -2100,14 +2230,15 @@ addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
return (result); return (result);
newheader = (rdatasetheader_t *)region.base; newheader = (rdatasetheader_t *)region.base;
newheader->ttl = rdataset->ttl; newheader->ttl = rdataset->ttl + now;
newheader->type = rdataset->type; newheader->type = rdataset->type;
newheader->attributes = 0; newheader->attributes = 0;
if (rbtversion != NULL) { if (rbtversion != NULL) {
newheader->serial = rbtversion->serial; newheader->serial = rbtversion->serial;
merge = ISC_TRUE; merge = ISC_TRUE;
now = 0;
} else { } else {
newheader->serial = 0; newheader->serial = 1;
merge = ISC_FALSE; merge = ISC_FALSE;
} }
@@ -2177,7 +2308,8 @@ static dns_result_t
add_rdataset_callback(dns_rdatacallbacks_t *callbacks, dns_name_t *name, add_rdataset_callback(dns_rdatacallbacks_t *callbacks, dns_name_t *name,
dns_rdataset_t *rdataset) dns_rdataset_t *rdataset)
{ {
dns_rbtdb_t *rbtdb = callbacks->commit_private; rbtdb_load_t *loadctx = callbacks->commit_private;
dns_rbtdb_t *rbtdb = loadctx->rbtdb;
dns_rbtnode_t *node = NULL; dns_rbtnode_t *node = NULL;
dns_result_t result; dns_result_t result;
isc_region_t region; isc_region_t region;
@@ -2206,7 +2338,7 @@ add_rdataset_callback(dns_rdatacallbacks_t *callbacks, dns_name_t *name,
if (result != DNS_R_SUCCESS) if (result != DNS_R_SUCCESS)
return (result); return (result);
newheader = (rdatasetheader_t *)region.base; newheader = (rdatasetheader_t *)region.base;
newheader->ttl = rdataset->ttl; newheader->ttl = rdataset->ttl + loadctx->now; /* XXX overflow check */
newheader->type = rdataset->type; newheader->type = rdataset->type;
newheader->attributes = 0; newheader->attributes = 0;
newheader->serial = 1; newheader->serial = 1;
@@ -2222,14 +2354,30 @@ add_rdataset_callback(dns_rdatacallbacks_t *callbacks, dns_name_t *name,
static dns_result_t static dns_result_t
load(dns_db_t *db, char *filename) { load(dns_db_t *db, char *filename) {
dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db; rbtdb_load_t loadctx;
dns_rbtdb_t *rbtdb;
int soacount, nscount; int soacount, nscount;
dns_rdatacallbacks_t callbacks; dns_rdatacallbacks_t callbacks;
dns_result_t result; dns_result_t result;
dns_name_t name; dns_name_t name;
rbtdb = (dns_rbtdb_t *)db;
REQUIRE(VALID_RBTDB(rbtdb)); REQUIRE(VALID_RBTDB(rbtdb));
loadctx.rbtdb = rbtdb;
if ((rbtdb->common.attributes & DNS_DBATTR_CACHE) != 0) {
/*
* XXXRTH This is not quite right. We should probably
* use the last file modification time or perhaps the value
* of an new master file option (e.g. $TIME) as the 'now'
* time.
*/
if (isc_stdtime_get(&loadctx.now) != DNS_R_SUCCESS)
return (DNS_R_UNEXPECTED);
} else
loadctx.now = 0;
LOCK(&rbtdb->lock); LOCK(&rbtdb->lock);
REQUIRE((rbtdb->attributes & RBTDB_ATTR_LOADED) == 0); REQUIRE((rbtdb->attributes & RBTDB_ATTR_LOADED) == 0);
@@ -2264,13 +2412,14 @@ load(dns_db_t *db, char *filename) {
} }
dns_name_init(&name, NULL); dns_name_init(&name, NULL);
dns_rbt_namefromnode(rbtdb->origin_node, &name); dns_rbt_namefromnode(rbtdb->origin_node, &name);
rbtdb->origin_node->locknum = dns_name_hash(&name, ISC_TRUE) % rbtdb->origin_node->locknum =
dns_name_hash(&name, ISC_TRUE) %
rbtdb->node_lock_count; rbtdb->node_lock_count;
} }
dns_rdatacallbacks_init(&callbacks); dns_rdatacallbacks_init(&callbacks);
callbacks.commit = add_rdataset_callback; callbacks.commit = add_rdataset_callback;
callbacks.commit_private = rbtdb; callbacks.commit_private = &loadctx;
return (dns_master_load(filename, &rbtdb->common.origin, return (dns_master_load(filename, &rbtdb->common.origin,
&rbtdb->common.origin, rbtdb->common.rdclass, &rbtdb->common.origin, rbtdb->common.rdclass,
@@ -2302,7 +2451,7 @@ static dns_dbmethods_t zone_methods = {
detachnode, detachnode,
printnode, printnode,
createiterator, createiterator,
findrdataset, zone_findrdataset,
allrdatasets, allrdatasets,
addrdataset, addrdataset,
deleterdataset deleterdataset
@@ -2321,7 +2470,7 @@ static dns_dbmethods_t cache_methods = {
detachnode, detachnode,
printnode, printnode,
createiterator, createiterator,
findrdataset, cache_findrdataset,
allrdatasets, allrdatasets,
addrdataset, addrdataset,
deleterdataset deleterdataset
@@ -2556,11 +2705,15 @@ rdatasetiter_first(dns_rdatasetiter_t *iterator) {
rbtdb_version_t *rbtversion = rbtiterator->common.version; rbtdb_version_t *rbtversion = rbtiterator->common.version;
rdatasetheader_t *header, *top_next; rdatasetheader_t *header, *top_next;
rbtdb_serial_t serial; rbtdb_serial_t serial;
isc_stdtime_t now;
if ((rbtdb->common.attributes & DNS_DBATTR_CACHE) == 0) if ((rbtdb->common.attributes & DNS_DBATTR_CACHE) == 0) {
serial = rbtversion->serial; serial = rbtversion->serial;
else now = 0;
serial = max_serial; } else {
serial = 1;
now = rbtiterator->common.now;
}
LOCK(&rbtdb->node_locks[rbtnode->locknum].lock); LOCK(&rbtdb->node_locks[rbtnode->locknum].lock);
@@ -2573,7 +2726,8 @@ rdatasetiter_first(dns_rdatasetiter_t *iterator) {
* exist" record? * exist" record?
*/ */
if ((header->attributes & if ((header->attributes &
RDATASET_ATTR_NONEXISTENT) != 0) RDATASET_ATTR_NONEXISTENT) != 0 ||
(now != 0 && now >= header->ttl))
header = NULL; header = NULL;
break; break;
} else } else
@@ -2601,15 +2755,19 @@ rdatasetiter_next(dns_rdatasetiter_t *iterator) {
rbtdb_version_t *rbtversion = rbtiterator->common.version; rbtdb_version_t *rbtversion = rbtiterator->common.version;
rdatasetheader_t *header, *top_next; rdatasetheader_t *header, *top_next;
rbtdb_serial_t serial; rbtdb_serial_t serial;
isc_stdtime_t now;
header = rbtiterator->current; header = rbtiterator->current;
if (header == NULL) if (header == NULL)
return (DNS_R_NOMORE); return (DNS_R_NOMORE);
if ((rbtdb->common.attributes & DNS_DBATTR_CACHE) == 0) if ((rbtdb->common.attributes & DNS_DBATTR_CACHE) == 0) {
serial = rbtversion->serial; serial = rbtversion->serial;
else now = 0;
serial = max_serial; } else {
serial = 1;
now = rbtiterator->common.now;
}
LOCK(&rbtdb->node_locks[rbtnode->locknum].lock); LOCK(&rbtdb->node_locks[rbtnode->locknum].lock);
@@ -2622,7 +2780,8 @@ rdatasetiter_next(dns_rdatasetiter_t *iterator) {
* exist" record? * exist" record?
*/ */
if ((header->attributes & if ((header->attributes &
RDATASET_ATTR_NONEXISTENT) != 0) RDATASET_ATTR_NONEXISTENT) != 0 ||
(now != 0 && now >= header->ttl))
header = NULL; header = NULL;
break; break;
} else } else
@@ -2654,7 +2813,8 @@ rdatasetiter_current(dns_rdatasetiter_t *iterator, dns_rdataset_t *rdataset) {
LOCK(&rbtdb->node_locks[rbtnode->locknum].lock); LOCK(&rbtdb->node_locks[rbtnode->locknum].lock);
bind_rdataset(rbtdb, rbtnode, header, rdataset); bind_rdataset(rbtdb, rbtnode, header, rbtiterator->common.now,
rdataset);
UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock); UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock);
} }