Commit dd2a0a6d authored by Evan Hunt's avatar Evan Hunt

Merge statistics code (ATT SoW, rt24117)

This includes the following changes:

3326.	[func]		Added task list statistics: task model, worker
			threads, quantum, tasks running, tasks ready.
			[RT #27678]

3325.	[func]		Report cache statistics: memory use, number of
			nodes, number of hash buckets, hit and miss counts.
			[RT #27056]

3324.	[test]		Add better tests for ADB stats [RT #27057]

3323.	[func]		Report the number of buckets the resolver is using.
			[RT #27020]

3322.	[func]		Monitor the number of active TCP and UDP dispatches.
			[RT #27055]

3321.	[func]		Monitor the number of recursive fetches and the
			number of open sockets, and report these values in
			the statistics channel. [RT #27054]

3320.	[func]		Added support for monitoring of recursing client
			count. [RT #27009]

3319.	[func]		Added support for monitoring of ADB entry count and
			hash size. [RT #27057]
parent 4dd8c451
3326. [func] Added task list statistics: task model, worker
threads, quantum, tasks running, tasks ready.
[RT #27678]
3325. [func] Report cache statistics: memory use, number of
nodes, number of hash buckets, hit and miss counts.
[RT #27056]
3324. [test] Add better tests for ADB stats [RT #27057]
3323. [func] Report the number of buckets the resolver is using.
[RT #27020]
3322. [func] Monitor the number of active TCP and UDP dispatches.
[RT #27055]
3321. [func] Monitor the number of recursive fetches and the
number of open sockets, and report these values in
the statistics channel. [RT #27054]
3320. [func] Added support for monitoring of recursing client
count. [RT #27009]
3319. [func] Added support for monitoring of ADB entry count and
hash size. [RT #27057]
3318. [tuning] Reduce the amount of work performed while holding a
bucket lock when finshed with a fetch context.
[RT #29239]
......
......@@ -233,6 +233,47 @@ div.statcounter br {
<br />
<div class="statcounter">
<h2>ADB Statistics (Common)</h2>
<xsl:for-each select="server/adbstat">
<dl>
<dt><xsl:value-of select="name"/></dt>
<dd><xsl:value-of select="counter"/></dd>
</dl>
</xsl:for-each>
<br />
</div>
<xsl:for-each select="views/view">
<div class="statcounter">
<h2>ADB Statistics for View <xsl:value-of select="name"/></h2>
<xsl:for-each select="adbstat">
<dl>
<dt><xsl:value-of select="name"/></dt>
<dd><xsl:value-of select="counter"/></dd>
</dl>
</xsl:for-each>
<br />
</div>
</xsl:for-each>
<br />
<xsl:for-each select="views/view">
<table>
<tr class="rowh">
<th colspan="2">Cache Statistics for View <xsl:value-of select="name"/></th>
</tr>
<xsl:for-each select="cachestats/cachestat">
<tr class="lrow">
<td><xsl:value-of select="name"/></td>
<td><xsl:value-of select="value"/></td>
</tr>
</xsl:for-each>
</table>
<br/>
</xsl:for-each>
<xsl:for-each select="views/view">
<table>
<tr class="rowh">
......@@ -388,11 +429,17 @@ div.statcounter br {
<xsl:value-of select="taskmgr/thread-model/tasks-running"/>
</td>
</tr>
<tr class="lrow">
<td>Tasks Ready</td>
<td>
<xsl:value-of select="taskmgr/thread-model/tasks-ready"/>
</td>
</tr>
</table>
<br/>
<table>
<tr class="rowh">
<th colspan="5">Tasks</th>
<th colspan="6">Tasks</th>
</tr>
<tr class="rowh">
<th>ID</th>
......@@ -400,6 +447,7 @@ div.statcounter br {
<th>References</th>
<th>State</th>
<th>Quantum</th>
<th>Events</th>
</tr>
<xsl:for-each select="taskmgr/tasks/task">
<tr class="lrow">
......@@ -418,6 +466,9 @@ div.statcounter br {
<td>
<xsl:value-of select="quantum"/>
</td>
<td>
<xsl:value-of select="events"/>
</td>
</tr>
</xsl:for-each>
</table>
......
......@@ -238,6 +238,47 @@ static char xslmsg[] =
"\n"
" <br />\n"
"\n"
" <div class=\"statcounter\">\n"
" <h2>ADB Statistics (Common)</h2>\n"
" <xsl:for-each select=\"server/adbstat\">\n"
" <dl>\n"
" <dt><xsl:value-of select=\"name\"/></dt>\n"
" <dd><xsl:value-of select=\"counter\"/></dd>\n"
" </dl>\n"
" </xsl:for-each>\n"
" <br />\n"
" </div>\n"
"\n"
" <xsl:for-each select=\"views/view\">\n"
" <div class=\"statcounter\">\n"
" <h2>ADB Statistics for View <xsl:value-of select=\"name\"/></h2>\n"
" <xsl:for-each select=\"adbstat\">\n"
" <dl>\n"
" <dt><xsl:value-of select=\"name\"/></dt>\n"
" <dd><xsl:value-of select=\"counter\"/></dd>\n"
" </dl>\n"
" </xsl:for-each>\n"
" <br />\n"
" </div>\n"
" </xsl:for-each>\n"
"\n"
" <br />\n"
"\n"
" <xsl:for-each select=\"views/view\">\n"
" <table>\n"
" <tr class=\"rowh\">\n"
" <th colspan=\"2\">Cache Statistics for View <xsl:value-of select=\"name\"/></th>\n"
" </tr>\n"
" <xsl:for-each select=\"cachestats/cachestat\">\n"
" <tr class=\"lrow\">\n"
" <td><xsl:value-of select=\"name\"/></td>\n"
" <td><xsl:value-of select=\"value\"/></td>\n"
" </tr>\n"
" </xsl:for-each>\n"
" </table>\n"
" <br/>\n"
" </xsl:for-each>\n"
"\n"
" <xsl:for-each select=\"views/view\">\n"
" <table>\n"
" <tr class=\"rowh\">\n"
......@@ -393,11 +434,17 @@ static char xslmsg[] =
" <xsl:value-of select=\"taskmgr/thread-model/tasks-running\"/>\n"
" </td>\n"
" </tr>\n"
" <tr class=\"lrow\">\n"
" <td>Tasks Ready</td>\n"
" <td>\n"
" <xsl:value-of select=\"taskmgr/thread-model/tasks-ready\"/>\n"
" </td>\n"
" </tr>\n"
" </table>\n"
" <br/>\n"
" <table>\n"
" <tr class=\"rowh\">\n"
" <th colspan=\"5\">Tasks</th>\n"
" <th colspan=\"6\">Tasks</th>\n"
" </tr>\n"
" <tr class=\"rowh\">\n"
" <th>ID</th>\n"
......@@ -405,6 +452,7 @@ static char xslmsg[] =
" <th>References</th>\n"
" <th>State</th>\n"
" <th>Quantum</th>\n"
" <th>Events</th>\n"
" </tr>\n"
" <xsl:for-each select=\"taskmgr/tasks/task\">\n"
" <tr class=\"lrow\">\n"
......@@ -423,6 +471,9 @@ static char xslmsg[] =
" <td>\n"
" <xsl:value-of select=\"quantum\"/>\n"
" </td>\n"
" <td>\n"
" <xsl:value-of select=\"events\"/>\n"
" </td>\n"
" </tr>\n"
" </xsl:for-each>\n"
" </table>\n"
......
......@@ -670,8 +670,11 @@ ns_client_endrequest(ns_client_t *client) {
client->ednsversion = -1;
dns_message_reset(client->message, DNS_MESSAGE_INTENTPARSE);
if (client->recursionquota != NULL)
if (client->recursionquota != NULL) {
isc_quota_detach(&client->recursionquota);
isc_stats_decrement(ns_g_server->nsstats,
dns_nsstatscounter_recursclients);
}
/*
* Clear all client attributes that are specific to
......
......@@ -165,7 +165,9 @@ enum {
dns_nsstatscounter_updatefail = 34,
dns_nsstatscounter_updatebadprereq = 35,
dns_nsstatscounter_max = 36
dns_nsstatscounter_recursclients =36,
dns_nsstatscounter_max = 37
};
void
......
......@@ -30,6 +30,7 @@
#include <dns/adb.h>
#include <dns/byaddr.h>
#include <dns/cache.h>
#include <dns/db.h>
#include <dns/dlz.h>
#include <dns/dns64.h>
......@@ -1133,6 +1134,31 @@ query_isduplicate(ns_client_t *client, dns_name_t *name,
return (ISC_FALSE);
}
static void
update_cachestats(dns_cache_t *cache, isc_result_t result) {
isc_stats_t *cachestats = NULL;
if (cache == NULL)
return;
isc_stats_attach(dns_cache_getstats(cache), &cachestats);
switch (result) {
case ISC_R_SUCCESS:
case DNS_R_NCACHENXDOMAIN:
case DNS_R_NCACHENXRRSET:
case DNS_R_CNAME:
case DNS_R_DNAME:
case DNS_R_GLUE:
case DNS_R_ZONECUT:
isc_stats_increment(cachestats,
dns_cachestatscounter_queryhits);
break;
default:
isc_stats_increment(cachestats,
dns_cachestatscounter_querymisses);
}
isc_stats_detach(&cachestats);
}
static isc_result_t
query_addadditional(void *arg, dns_name_t *name, dns_rdatatype_t qtype) {
ns_client_t *client = arg;
......@@ -1264,6 +1290,8 @@ query_addadditional(void *arg, dns_name_t *name, dns_rdatatype_t qtype) {
DNS_DBFIND_GLUEOK | DNS_DBFIND_ADDITIONALOK,
client->now, &node, fname, &cm, &ci,
rdataset, sigrdataset);
update_cachestats(client->view->cache, result);
if (result == DNS_R_GLUE &&
validate(client, db, fname, rdataset, sigrdataset))
result = ISC_R_SUCCESS;
......@@ -1272,6 +1300,7 @@ query_addadditional(void *arg, dns_name_t *name, dns_rdatatype_t qtype) {
if (result == ISC_R_SUCCESS)
goto found;
if (dns_rdataset_isassociated(rdataset))
dns_rdataset_disassociate(rdataset);
if (sigrdataset != NULL && dns_rdataset_isassociated(sigrdataset))
......@@ -3727,6 +3756,10 @@ query_recurse(ns_client_t *client, dns_rdatatype_t qtype, dns_name_t *qname,
if (client->recursionquota == NULL) {
result = isc_quota_attach(&ns_g_server->recursionquota,
&client->recursionquota);
isc_stats_increment(ns_g_server->nsstats,
dns_nsstatscounter_recursclients);
if (result == ISC_R_SOFTQUOTA) {
static isc_stdtime_t last = 0;
isc_stdtime_t now;
......@@ -3773,6 +3806,8 @@ query_recurse(ns_client_t *client, dns_rdatatype_t qtype, dns_name_t *qname,
"ns_client_replace() failed: %s",
isc_result_totext(result));
isc_quota_detach(&client->recursionquota);
isc_stats_decrement(ns_g_server->nsstats,
dns_nsstatscounter_recursclients);
}
}
if (result != ISC_R_SUCCESS)
......@@ -5677,6 +5712,9 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
client->query.dboptions, client->now,
&node, fname, &cm, &ci, rdataset, sigrdataset);
if (db == client->view->cachedb)
update_cachestats(client->view->cache, result);
resume:
CTRACE("query_find: resume");
......
......@@ -2138,12 +2138,6 @@ configure_view(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
goto cleanup;
}
ndisp = 4 * ISC_MIN(ns_g_udpdisp, MAX_UDP_DISPATCH);
CHECK(dns_view_createresolver(view, ns_g_taskmgr, 31, ndisp,
ns_g_socketmgr, ns_g_timermgr,
resopts, ns_g_dispatchmgr,
dispatch4, dispatch6));
if (resstats == NULL) {
CHECK(isc_stats_create(mctx, &resstats,
dns_resstatscounter_max));
......@@ -2153,6 +2147,12 @@ configure_view(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
CHECK(dns_rdatatypestats_create(mctx, &resquerystats));
dns_view_setresquerystats(view, resquerystats);
ndisp = 4 * ISC_MIN(ns_g_udpdisp, MAX_UDP_DISPATCH);
CHECK(dns_view_createresolver(view, ns_g_taskmgr, 31, ndisp,
ns_g_socketmgr, ns_g_timermgr,
resopts, ns_g_dispatchmgr,
dispatch4, dispatch6));
/*
* Set the ADB cache size to 1/8th of the max-cache-size or
* MAX_ADB_SIZE_FOR_CACHESHARE when the cache is shared.
......
......@@ -14,7 +14,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: statschannel.c,v 1.28 2011/03/12 04:59:46 tbox Exp $ */
/* $Id: statschannel.c,v 1.28.224.1 2011/12/22 07:48:27 marka Exp $ */
/*! \file */
......@@ -62,16 +62,14 @@ struct ns_statschannel {
ISC_LINK(struct ns_statschannel) link;
};
typedef enum { statsformat_file, statsformat_xml } statsformat_t;
typedef struct
stats_dumparg {
statsformat_t type;
void *arg; /* type dependent argument */
int ncounters; /* used for general statistics */
int *counterindices; /* used for general statistics */
isc_uint64_t *countervalues; /* used for general statistics */
isc_result_t result;
isc_statsformat_t type;
void *arg; /* type dependent argument */
int ncounters; /* for general statistics */
int *counterindices; /* for general statistics */
isc_uint64_t *countervalues; /* for general statistics */
isc_result_t result;
} stats_dumparg_t;
static isc_once_t once = ISC_ONCE_INIT;
......@@ -83,16 +81,19 @@ static isc_once_t once = ISC_ONCE_INIT;
*/
static const char *nsstats_desc[dns_nsstatscounter_max];
static const char *resstats_desc[dns_resstatscounter_max];
static const char *adbstats_desc[dns_adbstats_max];
static const char *zonestats_desc[dns_zonestatscounter_max];
static const char *sockstats_desc[isc_sockstatscounter_max];
#ifdef HAVE_LIBXML2
static const char *nsstats_xmldesc[dns_nsstatscounter_max];
static const char *resstats_xmldesc[dns_resstatscounter_max];
static const char *adbstats_xmldesc[dns_adbstats_max];
static const char *zonestats_xmldesc[dns_zonestatscounter_max];
static const char *sockstats_xmldesc[isc_sockstatscounter_max];
#else
#define nsstats_xmldesc NULL
#define resstats_xmldesc NULL
#define adbstats_xmldesc NULL
#define zonestats_xmldesc NULL
#define sockstats_xmldesc NULL
#endif /* HAVE_LIBXML2 */
......@@ -108,6 +109,7 @@ static int nsstats_index[dns_nsstatscounter_max];
static int resstats_index[dns_resstatscounter_max];
static int zonestats_index[dns_zonestatscounter_max];
static int sockstats_index[isc_sockstatscounter_max];
static int adbstats_index[dns_adbstats_max];
static inline void
set_desc(int counter, int maxcounter, const char *fdesc, const char **fdescs,
......@@ -198,6 +200,8 @@ init_desc(void) {
SET_NSSTATDESC(updatebadprereq,
"updates rejected due to prerequisite failure",
"UpdateBadPrereq");
SET_NSSTATDESC(recursclients, "recursing clients",
"RecursClients");
INSIST(i == dns_nsstatscounter_max);
/* Initialize resolver statistics */
......@@ -234,6 +238,8 @@ init_desc(void) {
"QueryAbort");
SET_RESSTATDESC(dispsockfail, "failures in opening query sockets",
"QuerySockFail");
SET_RESSTATDESC(disprequdp, "UDP queries in progress", "QueryCurUDP");
SET_RESSTATDESC(dispreqtcp, "TCP queries in progress", "QueryCurTCP");
SET_RESSTATDESC(querytimeout, "query timeouts", "QueryTimeout");
SET_RESSTATDESC(gluefetchv4, "IPv4 NS address fetches", "GlueFetchv4");
SET_RESSTATDESC(gluefetchv6, "IPv6 NS address fetches", "GlueFetchv6");
......@@ -268,8 +274,32 @@ init_desc(void) {
SET_RESSTATDESC(queryrtt5, "queries with RTT > "
DNS_RESOLVER_QRYRTTCLASS4STR "ms",
"QryRTT" DNS_RESOLVER_QRYRTTCLASS4STR "+");
SET_RESSTATDESC(nfetch, "active fetches", "NumFetch");
SET_RESSTATDESC(buckets, "bucket size", "BucketSize");
INSIST(i == dns_resstatscounter_max);
/* Initialize adb statistics */
for (i = 0; i < dns_adbstats_max; i++)
adbstats_desc[i] = NULL;
#ifdef HAVE_LIBXML2
for (i = 0; i < dns_adbstats_max; i++)
adbstats_xmldesc[i] = NULL;
#endif
#define SET_ADBSTATDESC(id, desc, xmldesc) \
do { \
set_desc(dns_adbstats_ ## id, dns_adbstats_max, \
desc, adbstats_desc, xmldesc, adbstats_xmldesc); \
adbstats_index[i++] = dns_adbstats_ ## id; \
} while (0)
i = 0;
SET_ADBSTATDESC(nentries, "Address hash table size", "nentries");
SET_ADBSTATDESC(entriescnt, "Addresses in hash table", "entriescnt");
SET_ADBSTATDESC(nnames, "Name hash table size", "nnames");
SET_ADBSTATDESC(namescnt, "Names in hash table", "namescnt");
INSIST(i == dns_adbstats_max);
/* Initialize zone statistics */
for (i = 0; i < dns_zonestatscounter_max; i++)
zonestats_desc[i] = NULL;
......@@ -407,6 +437,12 @@ init_desc(void) {
"UnixRecvErr");
SET_SOCKSTATDESC(fdwatchrecvfail, "FDwatch recv errors",
"FDwatchRecvErr");
SET_SOCKSTATDESC(udp4active, "UDP/IPv4 sockets active", "UDP4Active");
SET_SOCKSTATDESC(udp6active, "UDP/IPv6 sockets active", "UDP6Active");
SET_SOCKSTATDESC(tcp4active, "TCP/IPv4 sockets active", "TCP4Active");
SET_SOCKSTATDESC(tcp6active, "TCP/IPv6 sockets active", "TCP6Active");
SET_SOCKSTATDESC(unixactive, "Unix domain sockets active",
"UnixActive");
INSIST(i == isc_sockstatscounter_max);
/* Sanity check */
......@@ -414,6 +450,8 @@ init_desc(void) {
INSIST(nsstats_desc[i] != NULL);
for (i = 0; i < dns_resstatscounter_max; i++)
INSIST(resstats_desc[i] != NULL);
for (i = 0; i < dns_adbstats_max; i++)
INSIST(adbstats_desc[i] != NULL);
for (i = 0; i < dns_zonestatscounter_max; i++)
INSIST(zonestats_desc[i] != NULL);
for (i = 0; i < isc_sockstatscounter_max; i++)
......@@ -423,6 +461,8 @@ init_desc(void) {
INSIST(nsstats_xmldesc[i] != NULL);
for (i = 0; i < dns_resstatscounter_max; i++)
INSIST(resstats_xmldesc[i] != NULL);
for (i = 0; i < dns_adbstats_max; i++)
INSIST(adbstats_xmldesc[i] != NULL);
for (i = 0; i < dns_zonestatscounter_max; i++)
INSIST(zonestats_xmldesc[i] != NULL);
for (i = 0; i < isc_sockstatscounter_max; i++)
......@@ -442,7 +482,7 @@ generalstat_dump(isc_statscounter_t counter, isc_uint64_t val, void *arg) {
}
static isc_result_t
dump_counters(isc_stats_t *stats, statsformat_t type, void *arg,
dump_counters(isc_stats_t *stats, isc_statsformat_t type, void *arg,
const char *category, const char **desc, int ncounters,
int *indices, isc_uint64_t *values, int options)
{
......@@ -475,12 +515,12 @@ dump_counters(isc_stats_t *stats, statsformat_t type, void *arg,
continue;
switch (dumparg.type) {
case statsformat_file:
case isc_statsformat_file:
fp = arg;
fprintf(fp, "%20" ISC_PRINT_QUADFORMAT "u %s\n",
value, desc[index]);
break;
case statsformat_xml:
case isc_statsformat_xml:
#ifdef HAVE_LIBXML2
writer = arg;
......@@ -542,11 +582,11 @@ rdtypestat_dump(dns_rdatastatstype_t type, isc_uint64_t val, void *arg) {
typestr = "Others";
switch (dumparg->type) {
case statsformat_file:
case isc_statsformat_file:
fp = dumparg->arg;
fprintf(fp, "%20" ISC_PRINT_QUADFORMAT "u %s\n", val, typestr);
break;
case statsformat_xml:
case isc_statsformat_xml:
#ifdef HAVE_LIBXML2
writer = dumparg->arg;
......@@ -603,12 +643,12 @@ rdatasetstats_dump(dns_rdatastatstype_t type, isc_uint64_t val, void *arg) {
nxrrset = ISC_TRUE;
switch (dumparg->type) {
case statsformat_file:
case isc_statsformat_file:
fp = dumparg->arg;
fprintf(fp, "%20" ISC_PRINT_QUADFORMAT "u %s%s\n", val,
nxrrset ? "!" : "", typestr);
break;
case statsformat_xml:
case isc_statsformat_xml:
#ifdef HAVE_LIBXML2
writer = dumparg->arg;
......@@ -652,11 +692,11 @@ opcodestat_dump(dns_opcode_t code, isc_uint64_t val, void *arg) {
codebuf[isc_buffer_usedlength(&b)] = '\0';
switch (dumparg->type) {
case statsformat_file:
case isc_statsformat_file:
fp = dumparg->arg;
fprintf(fp, "%20" ISC_PRINT_QUADFORMAT "u %s\n", val, codebuf);
break;
case statsformat_xml:
case isc_statsformat_xml:
#ifdef HAVE_LIBXML2
writer = dumparg->arg;
......@@ -724,10 +764,10 @@ zone_xmlrender(dns_zone_t *zone, void *arg) {
zonestats = dns_zone_getrequeststats(zone);
if (zonestats != NULL) {
TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters"));
result = dump_counters(zonestats, statsformat_xml, writer, NULL,
nsstats_xmldesc, dns_nsstatscounter_max,
nsstats_index, nsstat_values,
ISC_STATSDUMP_VERBOSE);
result = dump_counters(zonestats, isc_statsformat_xml, writer,
NULL, nsstats_xmldesc,
dns_nsstatscounter_max, nsstats_index,
nsstat_values, ISC_STATSDUMP_VERBOSE);
if (result != ISC_R_SUCCESS)
goto error;
TRY0(xmlTextWriterEndElement(writer)); /* counters */
......@@ -750,9 +790,10 @@ generatexml(ns_server_t *server, int *buflen, xmlChar **buf) {
int xmlrc;
dns_view_t *view;
stats_dumparg_t dumparg;
dns_stats_t *cachestats;
dns_stats_t *cacherrstats;
isc_uint64_t nsstat_values[dns_nsstatscounter_max];
isc_uint64_t resstat_values[dns_resstatscounter_max];
isc_uint64_t adbstat_values[dns_adbstats_max];
isc_uint64_t zonestat_values[dns_zonestatscounter_max];
isc_uint64_t sockstat_values[isc_sockstatscounter_max];
isc_result_t result;
......@@ -777,7 +818,7 @@ generatexml(ns_server_t *server, int *buflen, xmlChar **buf) {
ISC_XMLCHAR "2.2"));
/* Set common fields for statistics dump */
dumparg.type = statsformat_xml;
dumparg.type = isc_statsformat_xml;
dumparg.arg = writer;
/*
......@@ -809,9 +850,9 @@ generatexml(ns_server_t *server, int *buflen, xmlChar **buf) {
}
if (view->resstats != NULL) {
result = dump_counters(view->resstats, statsformat_xml,
writer, "resstat",
resstats_xmldesc,
result = dump_counters(view->resstats,
isc_statsformat_xml, writer,
"resstat", resstats_xmldesc,
dns_resstatscounter_max,
resstats_index, resstat_values,
ISC_STATSDUMP_VERBOSE);
......@@ -819,8 +860,8 @@ generatexml(ns_server_t *server, int *buflen, xmlChar **buf) {
goto error;
}
cachestats = dns_db_getrrsetstats(view->cachedb);
if (cachestats != NULL) {
cacherrstats = dns_db_getrrsetstats(view->cachedb);
if (cacherrstats != NULL) {
TRY0(xmlTextWriterStartElement(writer,
ISC_XMLCHAR "cache"));
TRY0(xmlTextWriterWriteAttribute(writer,
......@@ -828,13 +869,29 @@ generatexml(ns_server_t *server, int *buflen, xmlChar **buf) {
ISC_XMLCHAR
dns_cache_getname(view->cache)));
dumparg.result = ISC_R_SUCCESS;
dns_rdatasetstats_dump(cachestats, rdatasetstats_dump,
dns_rdatasetstats_dump(cacherrstats, rdatasetstats_dump,
&dumparg, 0);
if (dumparg.result != ISC_R_SUCCESS)
goto error;
TRY0(xmlTextWriterEndElement(writer)); /* cache */
}
TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR
"cachestats"));
dns_cache_renderxml(view->cache, writer);
TRY0(xmlTextWriterEndElement(writer)); /* cachestats */
if (view->adbstats != NULL) {
result = dump_counters(view->adbstats,