mirror of
https://gitlab.isc.org/isc-projects/bind9
synced 2025-08-30 22:15:20 +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:
324
lib/dns/rbtdb.c
324
lib/dns/rbtdb.c
@@ -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,
|
||||||
®ion,
|
®ion,
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user