3336. [func] Maintain statistics for RRsets tagged as "stale".

[RT #29514]
This commit is contained in:
Mark Andrews 2012-06-08 16:32:44 +10:00
parent 74c2115bdf
commit 80fa3ef851
8 changed files with 287 additions and 47 deletions

View file

@ -1,3 +1,6 @@
3336. [func] Maintain statistics for RRsets tagged as "stale".
[RT #29514]
3335. [func] nslookup: return a nonzero exit code when unable
to get an answer. [RT #29492]

View file

@ -656,6 +656,7 @@ rdatasetstats_dump(dns_rdatastatstype_t type, isc_uint64_t val, void *arg) {
char typebuf[64];
const char *typestr;
isc_boolean_t nxrrset = ISC_FALSE;
isc_boolean_t stale = ISC_FALSE;
#ifdef HAVE_LIBXML2
xmlTextWriterPtr writer;
int xmlrc;
@ -677,11 +678,15 @@ rdatasetstats_dump(dns_rdatastatstype_t type, isc_uint64_t val, void *arg) {
!= 0)
nxrrset = ISC_TRUE;
if ((DNS_RDATASTATSTYPE_ATTR(type) & DNS_RDATASTATSTYPE_ATTR_STALE)
!= 0)
stale = ISC_TRUE;
switch (dumparg->type) {
case isc_statsformat_file:
fp = dumparg->arg;
fprintf(fp, "%20" ISC_PRINT_QUADFORMAT "u %s%s\n", val,
nxrrset ? "!" : "", typestr);
fprintf(fp, "%20" ISC_PRINT_QUADFORMAT "u %s%s%s\n", val,
stale ? "#" : "", nxrrset ? "!" : "", typestr);
break;
case isc_statsformat_xml:
#ifdef HAVE_LIBXML2
@ -689,7 +694,8 @@ rdatasetstats_dump(dns_rdatastatstype_t type, isc_uint64_t val, void *arg) {
TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "rrset"));
TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "name"));
TRY0(xmlTextWriterWriteFormatString(writer, "%s%s",
TRY0(xmlTextWriterWriteFormatString(writer, "%s%s%s",
stale ? "#" : "",
nxrrset ? "!" : "", typestr));
TRY0(xmlTextWriterEndElement(writer)); /* name */

View file

@ -13731,7 +13731,8 @@ HOST-127.EXAMPLE. MX 0 .
If the exclamation mark (!) is printed for a RR
type, it means that particular type of RRset is
known to be nonexistent (this is also known as
"NXRRSET").
"NXRRSET"). If a hash mark (#) is present then
the RRset is marked for garbage collection.
Maintained per view.
</para>
</entry>

View file

@ -162,10 +162,18 @@ LIBDNS_EXTERNAL_DATA extern const char *dns_statscounter_names[];
* _NXDOMAIN
* RRset type counters only. Indicates a non existent name. When this
* attribute is set, the base type is of no use.
*
* _STALE
* RRset type counters only. This indicates a record that marked for
* removal.
*
* Note: incrementing _STALE will decrement the corresponding non-stale
* counter.
*/
#define DNS_RDATASTATSTYPE_ATTR_OTHERTYPE 0x0001
#define DNS_RDATASTATSTYPE_ATTR_NXRRSET 0x0002
#define DNS_RDATASTATSTYPE_ATTR_NXDOMAIN 0x0004
#define DNS_RDATASTATSTYPE_ATTR_STALE 0x0008
/*%<
* Conversion macros among dns_rdatatype_t, attributes and isc_statscounter_t.
@ -299,6 +307,9 @@ dns_rdatasetstats_increment(dns_stats_t *stats, dns_rdatastatstype_t rrsettype);
/*%<
* Increment the statistics counter for 'rrsettype'.
*
* Note: if 'rrsettype' has the _STALE attribute set the corresponding
* non-stale counter will be decremented.
*
* Requires:
*\li 'stats' is a valid dns_stats_t created by dns_rdatasetstats_create().
*/

View file

@ -1368,6 +1368,28 @@ rollback_node(dns_rbtnode_t *node, rbtdb_serial_t serial) {
node->dirty = 1;
}
static inline void
mark_stale_header(dns_rbtdb_t *rbtdb, rdatasetheader_t *header) {
/*
* If we are already stale there is nothing to do.
*/
if ((header->attributes & RDATASET_ATTR_STALE) != 0)
return;
header->attributes |= RDATASET_ATTR_STALE;
header->node->dirty = 1;
/*
* If we have not been counted then there is nothing to do.
*/
if ((header->attributes & RDATASET_ATTR_STATCOUNT) == 0)
return;
if (EXISTS(header))
update_rrsetstats(rbtdb, header, ISC_TRUE);
}
static inline void
clean_stale_headers(dns_rbtdb_t *rbtdb, isc_mem_t *mctx, rdatasetheader_t *top)
{
@ -4245,9 +4267,8 @@ cache_zonecut_callback(dns_rbtnode_t *node, dns_name_t *name, void *arg) {
free_rdataset(search->rbtdb, mctx,
header);
} else {
header->attributes |=
RDATASET_ATTR_STALE;
node->dirty = 1;
mark_stale_header(search->rbtdb,
header);
header_prev = header;
}
} else
@ -4359,9 +4380,8 @@ find_deepest_zonecut(rbtdb_search_t *search, dns_rbtnode_t *node,
free_rdataset(rbtdb, m,
header);
} else {
header->attributes |=
RDATASET_ATTR_STALE;
node->dirty = 1;
mark_stale_header(rbtdb,
header);
header_prev = header;
}
} else
@ -4534,9 +4554,8 @@ find_coveringnsec(rbtdb_search_t *search, dns_dbnode_t **nodep,
free_rdataset(search->rbtdb, m,
header);
} else {
header->attributes |=
RDATASET_ATTR_STALE;
node->dirty = 1;
mark_stale_header(search->rbtdb,
header);
header_prev = header;
}
} else
@ -4928,9 +4947,7 @@ cache_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
free_rdataset(search.rbtdb, mctx,
header);
} else {
header->attributes |=
RDATASET_ATTR_STALE;
node->dirty = 1;
mark_stale_header(search.rbtdb, header);
header_prev = header;
}
} else
@ -5236,9 +5253,7 @@ cache_findzonecut(dns_db_t *db, dns_name_t *name, unsigned int options,
free_rdataset(search.rbtdb, mctx,
header);
} else {
header->attributes |=
RDATASET_ATTR_STALE;
node->dirty = 1;
mark_stale_header(search.rbtdb, header);
header_prev = header;
}
} else
@ -5446,8 +5461,7 @@ expirenode(dns_db_t *db, dns_dbnode_t *node, isc_stdtime_t now) {
* refcurrent(rbtnode) must be non-zero. This is so
* because 'node' is an argument to the function.
*/
header->attributes |= RDATASET_ATTR_STALE;
rbtnode->dirty = 1;
mark_stale_header(rbtdb, header);
if (log)
isc_log_write(dns_lctx, category, module,
level, "overmem cache: stale %s",
@ -5455,8 +5469,7 @@ expirenode(dns_db_t *db, dns_dbnode_t *node, isc_stdtime_t now) {
} else if (force_expire) {
if (! RETAIN(header)) {
set_ttl(rbtdb, header, 0);
header->attributes |= RDATASET_ATTR_STALE;
rbtnode->dirty = 1;
mark_stale_header(rbtdb, header);
} else if (log) {
isc_log_write(dns_lctx, category, module,
level, "overmem cache: "
@ -5712,8 +5725,7 @@ cache_findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
* non-zero. This is so because 'node' is an
* argument to the function.
*/
header->attributes |= RDATASET_ATTR_STALE;
rbtnode->dirty = 1;
mark_stale_header(rbtdb, header);
}
} else if (EXISTS(header)) {
if (header->type == matchtype)
@ -5977,9 +5989,7 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion,
*/
if (covers == dns_rdatatype_any) {
set_ttl(rbtdb, topheader, 0);
topheader->attributes |=
RDATASET_ATTR_STALE;
rbtnode->dirty = 1;
mark_stale_header(rbtdb, topheader);
} else if (topheader->type == sigtype)
sigheader = topheader;
}
@ -6024,8 +6034,7 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion,
* NXDOMAIN/NODATA(QTYPE=ANY).
*/
set_ttl(rbtdb, topheader, 0);
topheader->attributes |= RDATASET_ATTR_STALE;
rbtnode->dirty = 1;
mark_stale_header(rbtdb, topheader);
topheader = NULL;
goto find_header;
}
@ -6237,11 +6246,10 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion,
changed->dirty = ISC_TRUE;
if (rbtversion == NULL) {
set_ttl(rbtdb, header, 0);
header->attributes |= RDATASET_ATTR_STALE;
mark_stale_header(rbtdb, header);
if (sigheader != NULL) {
set_ttl(rbtdb, sigheader, 0);
sigheader->attributes |=
RDATASET_ATTR_STALE;
mark_stale_header(rbtdb, sigheader);
}
}
idx = newheader->node->locknum;
@ -9390,8 +9398,7 @@ expire_header(dns_rbtdb_t *rbtdb, rdatasetheader_t *header,
isc_boolean_t tree_locked, expire_t reason)
{
set_ttl(rbtdb, header, 0);
header->attributes |= RDATASET_ATTR_STALE;
header->node->dirty = 1;
mark_stale_header(rbtdb, header);
/*
* Caller must hold the node (write) lock.

View file

@ -50,6 +50,9 @@ typedef enum {
* XXXJT: this introduces tight coupling with the rdata implementation.
* Ideally, we should have rdata handle this type of details.
*/
/*
* types, !types, nxdomain, stale types, stale !types, stale nxdomain
*/
enum {
/* For 0-255, we use the rdtype value as counter indices */
rdtypecounter_dlv = 256, /* for dns_rdatatype_dlv */
@ -58,7 +61,9 @@ enum {
/* The following are used for rdataset */
rdtypenxcounter_max = rdtypecounter_max * 2,
rdtypecounter_nxdomain = rdtypenxcounter_max,
rdatasettypecounter_max = rdtypecounter_nxdomain + 1
/* stale counters offset */
rdtypecounter_stale = rdtypecounter_nxdomain + 1,
rdatasettypecounter_max = rdtypecounter_stale * 2
};
struct dns_stats {
@ -119,7 +124,7 @@ dns_stats_detach(dns_stats_t **statsp) {
* Create methods
*/
static isc_result_t
create_stats(isc_mem_t *mctx, dns_statstype_t type, int ncounters,
create_stats(isc_mem_t *mctx, dns_statstype_t type, int ncounters,
dns_stats_t **statsp)
{
dns_stats_t *stats;
@ -176,7 +181,7 @@ dns_rdatasetstats_create(isc_mem_t *mctx, dns_stats_t **statsp) {
REQUIRE(statsp != NULL && *statsp == NULL);
return (create_stats(mctx, dns_statstype_rdataset,
(rdtypecounter_max * 2) + 1, statsp));
rdatasettypecounter_max, statsp));
}
isc_result_t
@ -236,10 +241,19 @@ update_rdatasetstats(dns_stats_t *stats, dns_rdatastatstype_t rrsettype,
counter += rdtypecounter_max;
}
if (increment)
if (increment) {
if ((DNS_RDATASTATSTYPE_ATTR(rrsettype) &
DNS_RDATASTATSTYPE_ATTR_STALE) != 0) {
isc_stats_decrement(stats->counters, counter);
counter += rdtypecounter_stale;
}
isc_stats_increment(stats->counters, counter);
else
} else {
if ((DNS_RDATASTATSTYPE_ATTR(rrsettype) &
DNS_RDATASTATSTYPE_ATTR_STALE) != 0)
counter += rdtypecounter_stale;
isc_stats_decrement(stats->counters, counter);
}
}
void
@ -259,6 +273,7 @@ dns_rdatasetstats_decrement(dns_stats_t *stats, dns_rdatastatstype_t rrsettype)
update_rdatasetstats(stats, rrsettype, ISC_FALSE);
}
void
dns_opcodestats_increment(dns_stats_t *stats, dns_opcode_t code) {
REQUIRE(DNS_STATS_VALID(stats) && stats->type == dns_statstype_opcode);
@ -321,17 +336,35 @@ dns_rdatatypestats_dump(dns_stats_t *stats, dns_rdatatypestats_dumper_t dump_fn,
static void
rdataset_dumpcb(isc_statscounter_t counter, isc_uint64_t value, void *arg) {
rdatadumparg_t *rdatadumparg = arg;
unsigned int attributes;
if (counter < rdtypecounter_max) {
dump_rdentry(counter, value, 0, rdatadumparg->fn,
rdatadumparg->arg);
} else if (counter < rdtypenxcounter_max) {
dump_rdentry(counter - rdtypecounter_max, value,
DNS_RDATASTATSTYPE_ATTR_NXRRSET,
rdatadumparg->fn, rdatadumparg->arg);
} else {
} else if (counter < rdtypecounter_nxdomain) {
counter -= rdtypecounter_max;
attributes = DNS_RDATASTATSTYPE_ATTR_NXRRSET;
dump_rdentry(counter, value, attributes, rdatadumparg->fn,
rdatadumparg->arg);
} else if (counter == rdtypecounter_nxdomain) {
dump_rdentry(0, value, DNS_RDATASTATSTYPE_ATTR_NXDOMAIN,
rdatadumparg->fn, rdatadumparg->arg);
} else if (counter < rdtypecounter_stale + rdtypecounter_max) {
counter -= rdtypecounter_stale;
attributes = DNS_RDATASTATSTYPE_ATTR_STALE;
dump_rdentry(counter, value, attributes, rdatadumparg->fn,
rdatadumparg->arg);
} else if (counter < rdtypecounter_stale + rdtypecounter_nxdomain) {
counter -= rdtypecounter_stale + rdtypecounter_max;
attributes = DNS_RDATASTATSTYPE_ATTR_NXRRSET |
DNS_RDATASTATSTYPE_ATTR_STALE;
dump_rdentry(counter, value, attributes, rdatadumparg->fn,
rdatadumparg->arg);
} else {
attributes = DNS_RDATASTATSTYPE_ATTR_NXDOMAIN |
DNS_RDATASTATSTYPE_ATTR_STALE;
dump_rdentry(0, value, attributes, rdatadumparg->fn,
rdatadumparg->arg);
}
}

View file

@ -39,13 +39,13 @@ LIBS = @LIBS@ @ATFLIBS@
OBJS = dnstest.@O@
SRCS = dnstest.c master_test.c dbiterator_test.c time_test.c \
private_test.c update_test.c zonemgr_test.c zt_test.c \
dbdiff_test.c nsec3_test.c dispatch_test.c
dbdiff_test.c nsec3_test.c dispatch_test.c rdatasetstats_test.c
SUBDIRS =
TARGETS = master_test@EXEEXT@ dbiterator_test@EXEEXT@ time_test@EXEEXT@ \
private_test@EXEEXT@ update_test@EXEEXT@ zonemgr_test@EXEEXT@ \
zt_test@EXEEXT@ dbversion_test@EXEEXT@ dbdiff_test@EXEEXT@ \
nsec3_test@EXEEXT@ dispatch_test@EXEEXT@
nsec3_test@EXEEXT@ dispatch_test@EXEEXT@ rdatasetstats_test@EXEEXT@
@BIND9_MAKE_RULES@
@ -110,6 +110,11 @@ dispatch_test@EXEEXT@: dispatch_test.@O@ dnstest.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS}
dispatch_test.@O@ dnstest.@O@ ${DNSLIBS} \
${ISCLIBS} ${LIBS}
rdatasetstats_test@EXEEXT@: rdatasetstats_test.@O@ dnstest.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS}
${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
rdatasetstats_test.@O@ dnstest.@O@ ${DNSLIBS} \
${ISCLIBS} ${LIBS}
unit::
sh ${top_srcdir}/unit/unittest.sh

View file

@ -0,0 +1,174 @@
/*
* Copyright (C) 2011, 2012 Internet Systems Consortium, Inc. ("ISC")
*
* Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL ISC 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$ */
/*! \file */
#include <config.h>
#include <atf-c.h>
#include <unistd.h>
#include <dns/stats.h>
#include "dnstest.h"
/*
* Helper functions
*/
static void
set_typestats(dns_stats_t *stats, dns_rdatatype_t type,
isc_boolean_t stale)
{
dns_rdatastatstype_t which;
unsigned int attributes;
attributes = 0;
if (stale) attributes |= DNS_RDATASTATSTYPE_ATTR_STALE;
which = DNS_RDATASTATSTYPE_VALUE(type, attributes);
dns_rdatasetstats_increment(stats, which);
attributes = DNS_RDATASTATSTYPE_ATTR_NXRRSET;
if (stale) attributes |= DNS_RDATASTATSTYPE_ATTR_STALE;
which = DNS_RDATASTATSTYPE_VALUE(type, attributes);
dns_rdatasetstats_increment(stats, which);
}
static void
set_nxdomainstats(dns_stats_t *stats, isc_boolean_t stale) {
dns_rdatastatstype_t which;
unsigned int attributes;
attributes = DNS_RDATASTATSTYPE_ATTR_NXDOMAIN;
if (stale) attributes |= DNS_RDATASTATSTYPE_ATTR_STALE;
which = DNS_RDATASTATSTYPE_VALUE(0, attributes);
dns_rdatasetstats_increment(stats, which);
}
static void
checkit1(dns_rdatastatstype_t which, isc_uint64_t value, void *arg) {
unsigned int attributes;
#if debug
unsigned int type;
#endif
UNUSED(which);
UNUSED(arg);
attributes = DNS_RDATASTATSTYPE_ATTR(which);
#if debug
type = DNS_RDATASTATSTYPE_BASE(which);
fprintf(stderr, "%s%s%s%s/%u, %u\n",
attributes & DNS_RDATASTATSTYPE_ATTR_OTHERTYPE ? "O" : " ",
attributes & DNS_RDATASTATSTYPE_ATTR_NXRRSET ? "!" : " ",
attributes & DNS_RDATASTATSTYPE_ATTR_STALE ? "#" : " ",
attributes & DNS_RDATASTATSTYPE_ATTR_NXDOMAIN ? "X" : " ",
type, (unsigned)value);
#endif
if ((attributes & DNS_RDATASTATSTYPE_ATTR_STALE) == 0)
ATF_REQUIRE_EQ(value, 1);
else
ATF_REQUIRE_EQ(value, 0);
}
static void
checkit2(dns_rdatastatstype_t which, isc_uint64_t value, void *arg) {
unsigned int attributes;
#if debug
unsigned int type;
#endif
UNUSED(which);
UNUSED(arg);
attributes = DNS_RDATASTATSTYPE_ATTR(which);
#if debug
type = DNS_RDATASTATSTYPE_BASE(which);
fprintf(stderr, "%s%s%s%s/%u, %u\n",
attributes & DNS_RDATASTATSTYPE_ATTR_OTHERTYPE ? "O" : " ",
attributes & DNS_RDATASTATSTYPE_ATTR_NXRRSET ? "!" : " ",
attributes & DNS_RDATASTATSTYPE_ATTR_STALE ? "#" : " ",
attributes & DNS_RDATASTATSTYPE_ATTR_NXDOMAIN ? "X" : " ",
type, (unsigned)value);
#endif
if ((attributes & DNS_RDATASTATSTYPE_ATTR_STALE) == 0)
ATF_REQUIRE_EQ(value, 0);
else
ATF_REQUIRE_EQ(value, 1);
}
/*
* Individual unit tests
*/
ATF_TC(rdatasetstats);
ATF_TC_HEAD(rdatasetstats, tc) {
atf_tc_set_md_var(tc, "descr", "test that rdatasetstats counters are properly set");
}
ATF_TC_BODY(rdatasetstats, tc) {
unsigned int i;
dns_stats_t *stats = NULL;
isc_result_t result;
UNUSED(tc);
result = dns_test_begin(NULL, ISC_TRUE);
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
result = dns_rdatasetstats_create(mctx, &stats);
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
/* First 256 types. */
for (i = 0; i <= 255; i++)
set_typestats(stats, (dns_rdatatype_t)i, ISC_FALSE);
/* Specials */
set_typestats(stats, dns_rdatatype_dlv, ISC_FALSE);
set_typestats(stats, (dns_rdatatype_t)1000, ISC_FALSE);
set_nxdomainstats(stats, ISC_FALSE);
/*
* Check that all counters are set to appropriately.
*/
dns_rdatasetstats_dump(stats, checkit1, NULL, 1);
/* First 256 types. */
for (i = 0; i <= 255; i++)
set_typestats(stats, (dns_rdatatype_t)i, ISC_TRUE);
/* Specials */
set_typestats(stats, dns_rdatatype_dlv, ISC_TRUE);
set_typestats(stats, (dns_rdatatype_t)1000, ISC_TRUE);
set_nxdomainstats(stats, ISC_TRUE);
/*
* Check that all counters are set to appropriately.
*/
dns_rdatasetstats_dump(stats, checkit2, NULL, 1);
dns_stats_detach(&stats);
dns_test_end();
}
/*
* Main
*/
ATF_TP_ADD_TCS(tp) {
ATF_TP_ADD_TC(tp, rdatasetstats);
return (atf_no_error());
}