summaryrefslogtreecommitdiff
path: root/lib/dns/rbtdb.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/dns/rbtdb.c')
-rw-r--r--lib/dns/rbtdb.c162
1 files changed, 94 insertions, 68 deletions
diff --git a/lib/dns/rbtdb.c b/lib/dns/rbtdb.c
index a0fa148cf5456..82499d85c0ee0 100644
--- a/lib/dns/rbtdb.c
+++ b/lib/dns/rbtdb.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2004-2015 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2004-2016 Internet Systems Consortium, Inc. ("ISC")
* Copyright (C) 1999-2003 Internet Software Consortium.
*
* Permission to use, copy, modify, and/or distribute this software for any
@@ -401,6 +401,9 @@ typedef ISC_LIST(dns_rbtnode_t) rbtnodelist_t;
#define RDATASET_ATTR_STATCOUNT 0x0040
#define RDATASET_ATTR_OPTOUT 0x0080
#define RDATASET_ATTR_NEGATIVE 0x0100
+#define RDATASET_ATTR_PREFETCH 0x0200
+#define RDATASET_ATTR_CASESET 0x0400
+#define RDATASET_ATTR_ZEROTTL 0x0800
typedef struct acache_cbarg {
dns_rdatasetadditional_t type;
@@ -441,6 +444,16 @@ struct acachectl {
(((header)->attributes & RDATASET_ATTR_OPTOUT) != 0)
#define NEGATIVE(header) \
(((header)->attributes & RDATASET_ATTR_NEGATIVE) != 0)
+#define PREFETCH(header) \
+ (((header)->attributes & RDATASET_ATTR_PREFETCH) != 0)
+#define CASESET(header) \
+ (((header)->attributes & RDATASET_ATTR_CASESET) != 0)
+#define ZEROTTL(header) \
+ (((header)->attributes & RDATASET_ATTR_ZEROTTL) != 0)
+
+#define ACTIVE(header, now) \
+ (((header)->rdh_ttl > (now)) || \
+ ((header)->rdh_ttl == (now) && ZEROTTL(header)))
#define DEFAULT_NODE_LOCK_COUNT 7 /*%< Should be prime. */
@@ -1637,6 +1650,19 @@ delete_node(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node)
INSIST(!ISC_LINK_LINKED(node, deadlink));
+ if (isc_log_wouldlog(dns_lctx, ISC_LOG_DEBUG(1))) {
+ char printname[DNS_NAME_FORMATSIZE];
+ isc_log_write(dns_lctx,
+ DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_CACHE,
+ ISC_LOG_DEBUG(1),
+ "delete_node(): %p %s (bucket %d)",
+ node,
+ dns_rbt_formatnodename(node,
+ printname, sizeof(printname)),
+ node->locknum);
+ }
+
switch (node->nsec) {
case DNS_RBT_NSEC_NORMAL:
#ifdef BIND9
@@ -1704,6 +1730,24 @@ delete_node(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node)
}
}
+/*
+ * Caller must be holding the node lock.
+ */
+static inline void
+new_reference(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node) {
+ unsigned int lockrefs, noderefs;
+ isc_refcount_t *lockref;
+
+ INSIST(!ISC_LINK_LINKED(node, deadlink));
+ dns_rbtnode_refincrement0(node, &noderefs);
+ if (noderefs == 1) { /* this is the first reference to the node */
+ lockref = &rbtdb->node_locks[node->locknum].references;
+ isc_refcount_increment0(lockref, &lockrefs);
+ INSIST(lockrefs != 0);
+ }
+ INSIST(noderefs != 0);
+}
+
/*%
* Clean up dead nodes. These are nodes which have no references, and
* have no data. They are dead but we could not or chose not to delete
@@ -1728,32 +1772,36 @@ cleanup_dead_nodes(dns_rbtdb_t *rbtdb, int bucketnum) {
INSIST(dns_rbtnode_refcurrent(node) == 0 &&
node->data == NULL);
- delete_node(rbtdb, node);
+ if (node->parent != NULL &&
+ node->parent->down == node && node->left == NULL &&
+ node->right == NULL && rbtdb->task != NULL)
+ {
+ isc_event_t *ev;
+ dns_db_t *db;
+ ev = isc_event_allocate(rbtdb->common.mctx, NULL,
+ DNS_EVENT_RBTPRUNE,
+ prune_tree, node,
+ sizeof(isc_event_t));
+ if (ev != NULL) {
+ new_reference(rbtdb, node);
+ db = NULL;
+ attach((dns_db_t *)rbtdb, &db);
+ ev->ev_sender = db;
+ isc_task_send(rbtdb->task, &ev);
+ } else {
+ ISC_LIST_APPEND(rbtdb->deadnodes[bucketnum],
+ node, deadlink);
+ }
+ } else {
+ delete_node(rbtdb, node);
+ }
node = ISC_LIST_HEAD(rbtdb->deadnodes[bucketnum]);
count--;
}
}
/*
- * Caller must be holding the node lock.
- */
-static inline void
-new_reference(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node) {
- unsigned int lockrefs, noderefs;
- isc_refcount_t *lockref;
-
- INSIST(!ISC_LINK_LINKED(node, deadlink));
- dns_rbtnode_refincrement0(node, &noderefs);
- if (noderefs == 1) { /* this is the first reference to the node */
- lockref = &rbtdb->node_locks[node->locknum].references;
- isc_refcount_increment0(lockref, &lockrefs);
- INSIST(lockrefs != 0);
- }
- INSIST(noderefs != 0);
-}
-
-/*
* This function is assumed to be called when a node is newly referenced
* and can be in the deadnode list. In that case the node must be retrieved
* from the list because it is going to be used. In addition, if the caller
@@ -1969,21 +2017,6 @@ decrement_reference(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node,
deadlink);
}
} else {
- if (isc_log_wouldlog(dns_lctx, ISC_LOG_DEBUG(1))) {
- char printname[DNS_NAME_FORMATSIZE];
-
- isc_log_write(dns_lctx,
- DNS_LOGCATEGORY_DATABASE,
- DNS_LOGMODULE_CACHE,
- ISC_LOG_DEBUG(1),
- "decrement_reference: "
- "delete from rbt: %p %s",
- node,
- dns_rbt_formatnodename(node,
- printname,
- sizeof(printname)));
- }
-
delete_node(rbtdb, node);
}
} else {
@@ -4305,7 +4338,7 @@ cache_zonecut_callback(dns_rbtnode_t *node, dns_name_t *name, void *arg) {
header_prev = NULL;
for (header = node->data; header != NULL; header = header_next) {
header_next = header->next;
- if (header->rdh_ttl < search->now) {
+ if (!ACTIVE(header, search->now)) {
/*
* This rdataset is stale. If no one else is
* using the node, we can clean it up right
@@ -4313,7 +4346,7 @@ cache_zonecut_callback(dns_rbtnode_t *node, dns_name_t *name, void *arg) {
* the node as dirty, so it will get cleaned
* up later.
*/
- if ((header->rdh_ttl < search->now - RBTDB_VIRTUAL) &&
+ if ((header->rdh_ttl < search->now - RBTDB_VIRTUAL) &&
(locktype == isc_rwlocktype_write ||
NODE_TRYUPGRADE(lock) == ISC_R_SUCCESS)) {
/*
@@ -4429,7 +4462,7 @@ find_deepest_zonecut(rbtdb_search_t *search, dns_rbtnode_t *node,
header != NULL;
header = header_next) {
header_next = header->next;
- if (header->rdh_ttl < search->now) {
+ if (!ACTIVE(header, search->now)) {
/*
* This rdataset is stale. If no one else is
* using the node, we can clean it up right
@@ -4437,7 +4470,7 @@ find_deepest_zonecut(rbtdb_search_t *search, dns_rbtnode_t *node,
* the node as dirty, so it will get cleaned
* up later.
*/
- if ((header->rdh_ttl < search->now -
+ if ((header->rdh_ttl < search->now -
RBTDB_VIRTUAL) &&
(locktype == isc_rwlocktype_write ||
NODE_TRYUPGRADE(lock) == ISC_R_SUCCESS)) {
@@ -4606,7 +4639,7 @@ find_coveringnsec(rbtdb_search_t *search, dns_dbnode_t **nodep,
header != NULL;
header = header_next) {
header_next = header->next;
- if (header->rdh_ttl < now) {
+ if (!ACTIVE(header, now)) {
/*
* This rdataset is stale. If no one else is
* using the node, we can clean it up right
@@ -4614,7 +4647,7 @@ find_coveringnsec(rbtdb_search_t *search, dns_dbnode_t **nodep,
* node as dirty, so it will get cleaned up
* later.
*/
- if ((header->rdh_ttl < now - RBTDB_VIRTUAL) &&
+ if ((header->rdh_ttl < now - RBTDB_VIRTUAL) &&
(locktype == isc_rwlocktype_write ||
NODE_TRYUPGRADE(lock) == ISC_R_SUCCESS)) {
/*
@@ -5013,14 +5046,14 @@ cache_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
header_prev = NULL;
for (header = node->data; header != NULL; header = header_next) {
header_next = header->next;
- if (header->rdh_ttl < now) {
+ if (!ACTIVE(header, 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 ((header->rdh_ttl < now - RBTDB_VIRTUAL) &&
+ if ((header->rdh_ttl < now - RBTDB_VIRTUAL) &&
(locktype == isc_rwlocktype_write ||
NODE_TRYUPGRADE(lock) == ISC_R_SUCCESS)) {
/*
@@ -5320,7 +5353,7 @@ cache_findzonecut(dns_db_t *db, dns_name_t *name, unsigned int options,
header_prev = NULL;
for (header = node->data; header != NULL; header = header_next) {
header_next = header->next;
- if (header->rdh_ttl < now) {
+ if (!ACTIVE(header, now)) {
/*
* This rdataset is stale. If no one else is using the
* node, we can clean it up right now, otherwise we
@@ -5809,7 +5842,7 @@ cache_findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
for (header = rbtnode->data; header != NULL; header = header_next) {
header_next = header->next;
- if (header->rdh_ttl < now) {
+ if (!ACTIVE(header, now)) {
if ((header->rdh_ttl < now - RBTDB_VIRTUAL) &&
(locktype == isc_rwlocktype_write ||
NODE_TRYUPGRADE(lock) == ISC_R_SUCCESS)) {
@@ -6134,7 +6167,7 @@ add32(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion,
}
}
if (topheader != NULL && EXISTS(topheader) &&
- topheader->rdh_ttl >= now) {
+ ACTIVE(topheader, now)) {
/*
* Found one.
*/
@@ -6200,7 +6233,7 @@ add32(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion,
* has no effect, provided that the cache data isn't stale.
*/
if (rbtversion == NULL && trust < header->trust &&
- (header->rdh_ttl >= now || header_nx)) {
+ (ACTIVE(header, now) || header_nx)) {
free_rdataset(rbtdb, rbtdb->common.mctx, newheader);
if (addedrdataset != NULL)
bind_rdataset(rbtdb, rbtnode, header, now,
@@ -6270,7 +6303,7 @@ add32(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion,
* Don't lower trust of existing record if the
* update is forced.
*/
- if (IS_CACHE(rbtdb) && header->rdh_ttl >= now &&
+ if (IS_CACHE(rbtdb) && ACTIVE(header, now) &&
header->type == dns_rdatatype_ns &&
!header_nx && !newheader_nx &&
header->trust >= newheader->trust &&
@@ -6306,7 +6339,7 @@ add32(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion,
* to be no more than the current NS RRset's TTL. This
* ensures the delegations that are withdrawn are honoured.
*/
- if (IS_CACHE(rbtdb) && header->rdh_ttl >= now &&
+ if (IS_CACHE(rbtdb) && ACTIVE(header, now) &&
header->type == dns_rdatatype_ns &&
!header_nx && !newheader_nx &&
header->trust <= newheader->trust) {
@@ -6314,7 +6347,7 @@ add32(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion,
newheader->rdh_ttl = header->rdh_ttl;
}
}
- if (IS_CACHE(rbtdb) && header->rdh_ttl >= now &&
+ if (IS_CACHE(rbtdb) && ACTIVE(header, now) &&
(header->type == dns_rdatatype_a ||
header->type == dns_rdatatype_aaaa ||
header->type == dns_rdatatype_ds ||
@@ -6646,6 +6679,8 @@ addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
newheader->type = RBTDB_RDATATYPE_VALUE(rdataset->type,
rdataset->covers);
newheader->attributes = 0;
+ if (rdataset->ttl == 0U)
+ newheader->attributes |= RDATASET_ATTR_ZEROTTL;
newheader->noqname = NULL;
newheader->closest = NULL;
newheader->count = init_count++;
@@ -7130,13 +7165,14 @@ loading_addrdataset(void *arg, dns_name_t *name, dns_rdataset_t *rdataset) {
isc_region_t region;
rdatasetheader_t *newheader;
+ REQUIRE(rdataset->rdclass == rbtdb->common.rdclass);
+
/*
* This routine does no node locking. See comments in
* 'load' below for more information on loading and
* locking.
*/
-
/*
* SOA records are only allowed at top of zone.
*/
@@ -8615,6 +8651,8 @@ dbiterator_first(dns_dbiterator_t *iterator) {
dns_name_t *name, *origin;
if (rbtdbiter->result != ISC_R_SUCCESS &&
+ rbtdbiter->result != ISC_R_NOTFOUND &&
+ rbtdbiter->result != DNS_R_PARTIALMATCH &&
rbtdbiter->result != ISC_R_NOMORE)
return (rbtdbiter->result);
@@ -8668,6 +8706,8 @@ dbiterator_last(dns_dbiterator_t *iterator) {
dns_name_t *name, *origin;
if (rbtdbiter->result != ISC_R_SUCCESS &&
+ rbtdbiter->result != ISC_R_NOTFOUND &&
+ rbtdbiter->result != DNS_R_PARTIALMATCH &&
rbtdbiter->result != ISC_R_NOMORE)
return (rbtdbiter->result);
@@ -8718,6 +8758,7 @@ dbiterator_seek(dns_dbiterator_t *iterator, dns_name_t *name) {
if (rbtdbiter->result != ISC_R_SUCCESS &&
rbtdbiter->result != ISC_R_NOTFOUND &&
+ rbtdbiter->result != DNS_R_PARTIALMATCH &&
rbtdbiter->result != ISC_R_NOMORE)
return (rbtdbiter->result);
@@ -8766,23 +8807,7 @@ dbiterator_seek(dns_dbiterator_t *iterator, dns_name_t *name) {
}
}
-#if 1
- if (result == ISC_R_SUCCESS) {
- result = dns_rbtnodechain_current(rbtdbiter->current, iname,
- origin, NULL);
- if (result == ISC_R_SUCCESS) {
- rbtdbiter->new_origin = ISC_TRUE;
- reference_iter_node(rbtdbiter);
- }
- } else if (result == DNS_R_PARTIALMATCH) {
- result = ISC_R_NOTFOUND;
- rbtdbiter->node = NULL;
- }
-
- rbtdbiter->result = result;
-#else
if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
- isc_result_t tresult;
tresult = dns_rbtnodechain_current(rbtdbiter->current, iname,
origin, NULL);
if (tresult == ISC_R_SUCCESS) {
@@ -8797,7 +8822,6 @@ dbiterator_seek(dns_dbiterator_t *iterator, dns_name_t *name) {
rbtdbiter->result = (result == DNS_R_PARTIALMATCH) ?
ISC_R_SUCCESS : result;
-#endif
return (result);
}
@@ -8960,6 +8984,8 @@ dbiterator_pause(dns_dbiterator_t *iterator) {
rbtdb_dbiterator_t *rbtdbiter = (rbtdb_dbiterator_t *)iterator;
if (rbtdbiter->result != ISC_R_SUCCESS &&
+ rbtdbiter->result != ISC_R_NOTFOUND &&
+ rbtdbiter->result != DNS_R_PARTIALMATCH &&
rbtdbiter->result != ISC_R_NOMORE)
return (rbtdbiter->result);