diff --git a/CHANGES b/CHANGES index 85590e63dc..f94f7924b8 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,29 @@ +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] diff --git a/bin/named/bind9.xsl b/bin/named/bind9.xsl index 8063cc666a..4b9837c154 100644 --- a/bin/named/bind9.xsl +++ b/bin/named/bind9.xsl @@ -233,6 +233,47 @@ div.statcounter br {
+
+

ADB Statistics (Common)

+ +
+
+
+
+
+
+
+ + +
+

ADB Statistics for View

+ +
+
+
+
+
+
+
+
+ +
+ + + + + + + + + + + + +
Cache Statistics for View
+
+
+ @@ -388,11 +429,17 @@ div.statcounter br { + + + +
Tasks Ready + +

- + @@ -400,6 +447,7 @@ div.statcounter br { + @@ -418,6 +466,9 @@ div.statcounter br { +
TasksTasks
IDReferences State QuantumEvents
+ +
diff --git a/bin/named/bind9.xsl.h b/bin/named/bind9.xsl.h index 19a58ff17c..a1db05928b 100644 --- a/bin/named/bind9.xsl.h +++ b/bin/named/bind9.xsl.h @@ -238,6 +238,47 @@ static char xslmsg[] = "\n" "
\n" "\n" + "
\n" + "

ADB Statistics (Common)

\n" + " \n" + "
\n" + "
\n" + "
\n" + "
\n" + "
\n" + "
\n" + "
\n" + "\n" + " \n" + "
\n" + "

ADB Statistics for View

\n" + " \n" + "
\n" + "
\n" + "
\n" + "
\n" + "
\n" + "
\n" + "
\n" + "
\n" + "\n" + "
\n" + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "
Cache Statistics for View
\n" + "
\n" + "
\n" + "\n" " \n" " \n" " \n" @@ -393,11 +434,17 @@ static char xslmsg[] = " \n" " \n" " \n" + " \n" + " \n" + " \n" + " \n" "
Tasks Ready\n" + " \n" + "
\n" "
\n" " \n" " \n" - " \n" + " \n" " \n" " \n" " \n" @@ -405,6 +452,7 @@ static char xslmsg[] = " \n" " \n" " \n" + " \n" " \n" " \n" " \n" @@ -423,6 +471,9 @@ static char xslmsg[] = " \n" + " \n" " \n" " \n" "
TasksTasks
IDReferencesStateQuantumEvents
\n" " \n" " \n" + " \n" + "
\n" diff --git a/bin/named/client.c b/bin/named/client.c index ae13795f01..1891be7ec4 100644 --- a/bin/named/client.c +++ b/bin/named/client.c @@ -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 diff --git a/bin/named/include/named/server.h b/bin/named/include/named/server.h index 45bcdc425b..a0f76550f0 100644 --- a/bin/named/include/named/server.h +++ b/bin/named/include/named/server.h @@ -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 diff --git a/bin/named/query.c b/bin/named/query.c index abf28eee93..7e50097803 100644 --- a/bin/named/query.c +++ b/bin/named/query.c @@ -30,6 +30,7 @@ #include #include +#include #include #include #include @@ -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"); diff --git a/bin/named/server.c b/bin/named/server.c index ccde9ce538..c6375f8514 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -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. diff --git a/bin/named/statschannel.c b/bin/named/statschannel.c index c87ef67ec6..7331c16976 100644 --- a/bin/named/statschannel.c +++ b/bin/named/statschannel.c @@ -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, + isc_statsformat_xml, writer, + "adbstat", adbstats_xmldesc, + dns_adbstats_max, + adbstats_index, adbstat_values, + ISC_STATSDUMP_VERBOSE); + if (result != ISC_R_SUCCESS) + goto error; + } + TRY0(xmlTextWriterEndElement(writer)); /* view */ view = ISC_LIST_NEXT(view, link); @@ -873,7 +930,7 @@ generatexml(ns_server_t *server, int *buflen, xmlChar **buf) { goto error; TRY0(xmlTextWriterEndElement(writer)); /* queries-in */ - result = dump_counters(server->nsstats, statsformat_xml, writer, + result = dump_counters(server->nsstats, isc_statsformat_xml, writer, "nsstat", nsstats_xmldesc, dns_nsstatscounter_max, nsstats_index, nsstat_values, @@ -881,7 +938,7 @@ generatexml(ns_server_t *server, int *buflen, xmlChar **buf) { if (result != ISC_R_SUCCESS) goto error; - result = dump_counters(server->zonestats, statsformat_xml, writer, + result = dump_counters(server->zonestats, isc_statsformat_xml, writer, "zonestat", zonestats_xmldesc, dns_zonestatscounter_max, zonestats_index, zonestat_values, ISC_STATSDUMP_VERBOSE); @@ -892,14 +949,14 @@ generatexml(ns_server_t *server, int *buflen, xmlChar **buf) { * Most of the common resolver statistics entries are 0, so we don't * use the verbose dump here. */ - result = dump_counters(server->resolverstats, statsformat_xml, writer, + result = dump_counters(server->resolverstats, isc_statsformat_xml, writer, "resstat", resstats_xmldesc, dns_resstatscounter_max, resstats_index, resstat_values, 0); if (result != ISC_R_SUCCESS) goto error; - result = dump_counters(server->sockstats, statsformat_xml, writer, + result = dump_counters(server->sockstats, isc_statsformat_xml, writer, "sockstat", sockstats_xmldesc, isc_sockstatscounter_max, sockstats_index, sockstat_values, ISC_STATSDUMP_VERBOSE); @@ -1332,13 +1389,14 @@ ns_stats_dump(ns_server_t *server, FILE *fp) { stats_dumparg_t dumparg; 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]; RUNTIME_CHECK(isc_once_do(&once, init_desc) == ISC_R_SUCCESS); /* Set common fields */ - dumparg.type = statsformat_file; + dumparg.type = isc_statsformat_file; dumparg.arg = fp; isc_stdtime_get(&now); @@ -1366,19 +1424,19 @@ ns_stats_dump(ns_server_t *server, FILE *fp) { } fprintf(fp, "++ Name Server Statistics ++\n"); - (void) dump_counters(server->nsstats, statsformat_file, fp, NULL, + (void) dump_counters(server->nsstats, isc_statsformat_file, fp, NULL, nsstats_desc, dns_nsstatscounter_max, nsstats_index, nsstat_values, 0); fprintf(fp, "++ Zone Maintenance Statistics ++\n"); - (void) dump_counters(server->zonestats, statsformat_file, fp, NULL, + (void) dump_counters(server->zonestats, isc_statsformat_file, fp, NULL, zonestats_desc, dns_zonestatscounter_max, zonestats_index, zonestat_values, 0); fprintf(fp, "++ Resolver Statistics ++\n"); fprintf(fp, "[Common]\n"); - (void) dump_counters(server->resolverstats, statsformat_file, fp, NULL, - resstats_desc, dns_resstatscounter_max, + (void) dump_counters(server->resolverstats, isc_statsformat_file, fp, + NULL, resstats_desc, dns_resstatscounter_max, resstats_index, resstat_values, 0); for (view = ISC_LIST_HEAD(server->viewlist); view != NULL; @@ -1389,19 +1447,37 @@ ns_stats_dump(ns_server_t *server, FILE *fp) { fprintf(fp, "[View: default]\n"); else fprintf(fp, "[View: %s]\n", view->name); - (void) dump_counters(view->resstats, statsformat_file, fp, NULL, - resstats_desc, dns_resstatscounter_max, - resstats_index, resstat_values, 0); + (void) dump_counters(view->resstats, isc_statsformat_file, fp, + NULL, resstats_desc, + dns_resstatscounter_max, resstats_index, + resstat_values, 0); + } + + fprintf(fp, "++ Cache Statistics ++\n"); + for (view = ISC_LIST_HEAD(server->viewlist); + view != NULL; + view = ISC_LIST_NEXT(view, link)) { + if (strcmp(view->name, "_default") == 0) + fprintf(fp, "[View: default]\n"); + else + fprintf(fp, "[View: %s (Cache: %s)]\n", view->name, + dns_cache_getname(view->cache)); + /* + * Avoid dumping redundant statistics when the cache is shared. + */ + if (dns_view_iscacheshared(view)) + continue; + dns_cache_dumpstats(view->cache, fp); } fprintf(fp, "++ Cache DB RRsets ++\n"); for (view = ISC_LIST_HEAD(server->viewlist); view != NULL; view = ISC_LIST_NEXT(view, link)) { - dns_stats_t *cachestats; + dns_stats_t *cacherrstats; - cachestats = dns_db_getrrsetstats(view->cachedb); - if (cachestats == NULL) + cacherrstats = dns_db_getrrsetstats(view->cachedb); + if (cacherrstats == NULL) continue; if (strcmp(view->name, "_default") == 0) fprintf(fp, "[View: default]\n"); @@ -1415,12 +1491,27 @@ ns_stats_dump(ns_server_t *server, FILE *fp) { */ continue; } - dns_rdatasetstats_dump(cachestats, rdatasetstats_dump, &dumparg, - 0); + dns_rdatasetstats_dump(cacherrstats, rdatasetstats_dump, + &dumparg, 0); + } + + fprintf(fp, "++ ADB stats ++\n"); + for (view = ISC_LIST_HEAD(server->viewlist); + view != NULL; + view = ISC_LIST_NEXT(view, link)) { + if (view->adbstats == NULL) + continue; + if (strcmp(view->name, "_default") == 0) + fprintf(fp, "[View: default]\n"); + else + fprintf(fp, "[View: %s]\n", view->name); + (void) dump_counters(view->adbstats, isc_statsformat_file, fp, + NULL, adbstats_desc, dns_adbstats_max, + adbstats_index, adbstat_values, 0); } fprintf(fp, "++ Socket I/O Statistics ++\n"); - (void) dump_counters(server->sockstats, statsformat_file, fp, NULL, + (void) dump_counters(server->sockstats, isc_statsformat_file, fp, NULL, sockstats_desc, isc_sockstatscounter_max, sockstats_index, sockstat_values, 0); @@ -1443,8 +1534,8 @@ ns_stats_dump(ns_server_t *server, FILE *fp) { fprintf(fp, " (view: %s)", view->name); fprintf(fp, "]\n"); - (void) dump_counters(zonestats, statsformat_file, fp, - NULL, nsstats_desc, + (void) dump_counters(zonestats, isc_statsformat_file, + fp, NULL, nsstats_desc, dns_nsstatscounter_max, nsstats_index, nsstat_values, 0); } diff --git a/bin/tests/system/conf.sh.in b/bin/tests/system/conf.sh.in index 9e13baea6e..b146b0dce2 100644 --- a/bin/tests/system/conf.sh.in +++ b/bin/tests/system/conf.sh.in @@ -57,8 +57,8 @@ SUBDIRS="acl allow_query addzone autosign builtin cacheclean checkconf dname dns64 dnssec forward glue gost ixfr inline limits logfileconfig lwresd masterfile masterformat metadata notify nsupdate pending pkcs11 redirect resolver rndc rpz rrsetorder - sortlist smartsign staticstub stub tkey tsig tsiggss unknown - upforwd views xfer xferquota zonechecks" + sortlist smartsign staticstub statistics stub tkey tsig tsiggss + unknown upforwd views xfer xferquota zonechecks" # PERL will be an empty string if no perl interpreter was found. PERL=@PERL@ diff --git a/bin/tests/system/rndc/tests.sh b/bin/tests/system/rndc/tests.sh index cfdce0ae3e..8549397ddf 100644 --- a/bin/tests/system/rndc/tests.sh +++ b/bin/tests/system/rndc/tests.sh @@ -14,7 +14,7 @@ # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. -# $Id: tests.sh,v 1.4 2011/06/10 01:32:37 each Exp $ +# $Id: tests.sh,v 1.4.154.1 2012/01/04 20:05:03 smann Exp $ SYSTEMTESTTOP=.. . $SYSTEMTESTTOP/conf.sh @@ -225,5 +225,13 @@ $DIGCMD frozen.nil. TXT | grep 'frozen addition' >/dev/null || ret=1 if [ $ret != 0 ]; then echo "I:failed"; fi status=`expr $status + $ret` +# temp test +echo "I:dumping stats" +$RNDCCMD stats +echo "I: verifying adb records in named.stats" +grep "ADB stats" ns2/named.stats > /dev/null || ret=1 +if [ $ret != 0 ]; then echo "I:failed"; fi +status=`expr $status + $ret` + echo "I:exit status: $status" exit $status diff --git a/bin/tests/system/statistics/ans4/ans.pl b/bin/tests/system/statistics/ans4/ans.pl new file mode 100644 index 0000000000..0938d69876 --- /dev/null +++ b/bin/tests/system/statistics/ans4/ans.pl @@ -0,0 +1,113 @@ +#!/usr/bin/perl -w +# +# Copyright (C) 2004, 2007, 2009, 2010 Internet Systems Consortium, Inc. ("ISC") +# Copyright (C) 2000, 2001 Internet Software Consortium. +# +# 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$ + +# +# Ad hoc name server +# + +use IO::File; +use IO::Socket; +use Net::DNS; +use Net::DNS::Packet; + +my $sock = IO::Socket::INET->new(LocalAddr => "10.53.0.4", + LocalPort => 5300, Proto => "udp") or die "$!"; + +my $pidf = new IO::File "ans.pid", "w" or die "cannot open pid file: $!"; +print $pidf "$$\n" or die "cannot write pid file: $!"; +$pidf->close or die "cannot close pid file: $!"; +sub rmpid { unlink "ans.pid"; exit 1; }; + +$SIG{INT} = \&rmpid; +$SIG{TERM} = \&rmpid; + +for (;;) { + $sock->recv($buf, 512); + + print "**** request from " , $sock->peerhost, " port ", $sock->peerport, "\n"; + + my ($packet, $err) = new Net::DNS::Packet(\$buf, 0); + $err and die $err; + + print "REQUEST:\n"; + $packet->print; + + $packet->header->qr(1); + + my @questions = $packet->question; + my $qname = $questions[0]->qname; + my $qtype = $questions[0]->qtype; + + my $donotrespond = 0; + + if ($qname eq "foo.info") { + $donotrespond = 1; + } elsif ($qname eq "cname1.example.com") { + # Data for the "cname + other data / 1" test + $packet->push("answer", new Net::DNS::RR("cname1.example.com 300 CNAME cname1.example.com")); + $packet->push("answer", new Net::DNS::RR("cname1.example.com 300 A 1.2.3.4")); + } elsif ($qname eq "cname2.example.com") { + # Data for the "cname + other data / 2" test: same RRs in opposite order + $packet->push("answer", new Net::DNS::RR("cname2.example.com 300 A 1.2.3.4")); + $packet->push("answer", new Net::DNS::RR("cname2.example.com 300 CNAME cname2.example.com")); + } elsif ($qname eq "www.example.org" || $qname eq "www.example.net" || + $qname eq "badcname.example.org" || + $qname eq "goodcname.example.org" || + $qname eq "foo.baddname.example.org" || + $qname eq "foo.gooddname.example.org") { + # Data for address/alias filtering. + $packet->header->aa(1); + if ($qtype eq "A") { + $packet->push("answer", + new Net::DNS::RR($qname . + " 300 A 192.0.2.1")); + } elsif ($qtype eq "AAAA") { + $packet->push("answer", + new Net::DNS::RR($qname . + " 300 AAAA 2001:db8:beef::1")); + } + } elsif ($qname eq "badcname.example.net" || + $qname eq "goodcname.example.net") { + # Data for CNAME/DNAME filtering. We need to make one-level + # delegation to avoid automatic acceptance for subdomain aliases + $packet->push("authority", new Net::DNS::RR("example.net 300 NS ns.example.net")); + $packet->push("additional", new Net::DNS::RR("ns.example.net 300 A 10.53.0.3")); + } elsif ($qname =~ /^nodata\.example\.net$/i) { + $packet->header->aa(1); + } elsif ($qname =~ /^nxdomain\.example\.net$/i) { + $packet->header->aa(1); + $packet->header->rcode(NXDOMAIN); + } elsif ($qname =~ /sub\.example\.org/) { + # Data for CNAME/DNAME filtering. The final answers are + # expected to be accepted regardless of the filter setting. + $packet->push("authority", new Net::DNS::RR("sub.example.org 300 NS ns.sub.example.org")); + $packet->push("additional", new Net::DNS::RR("ns.sub.example.org 300 A 10.53.0.3")); + } else { + # Data for the "bogus referrals" test + $packet->push("authority", new Net::DNS::RR("below.www.example.com 300 NS ns.below.www.example.com")); + $packet->push("additional", new Net::DNS::RR("ns.below.www.example.com 300 A 10.53.0.3")); + } + + if ($donotrespond == 0) { + $sock->send($packet->data); + print "RESPONSE:\n"; + $packet->print; + print "\n"; + } +} diff --git a/bin/tests/system/statistics/clean.sh b/bin/tests/system/statistics/clean.sh new file mode 100644 index 0000000000..0755060851 --- /dev/null +++ b/bin/tests/system/statistics/clean.sh @@ -0,0 +1,29 @@ +#!/bin/sh +# +# Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") +# Copyright (C) 2000, 2001 Internet Software Consortium. +# +# 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$ + +# +# Clean up after zone transfer tests. +# + +rm -f ns3/example.bk +rm -f ns3/internal.bk +rm -f */named.memstats +rm -f */named.run +rm -f */named.stats +rm -f dig.out* diff --git a/bin/tests/system/statistics/ns1/named.conf b/bin/tests/system/statistics/ns1/named.conf new file mode 100644 index 0000000000..247e59c94e --- /dev/null +++ b/bin/tests/system/statistics/ns1/named.conf @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 Internet Software Consortium. + * + * 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$ */ + +controls { /* empty */ }; + +options { + query-source address 10.53.0.1; + notify-source 10.53.0.1; + transfer-source 10.53.0.1; + port 5300; + pid-file "named.pid"; + listen-on { 10.53.0.1; }; + listen-on-v6 { none; }; + recursion no; + notify yes; +}; + +zone "." { + type master; + file "root.db"; +}; + +zone "example.info." { + type master; + file "example-info.db"; +}; diff --git a/bin/tests/system/statistics/ns1/root.db b/bin/tests/system/statistics/ns1/root.db new file mode 100644 index 0000000000..f28b0ad899 --- /dev/null +++ b/bin/tests/system/statistics/ns1/root.db @@ -0,0 +1,30 @@ +; Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") +; Copyright (C) 2000, 2001 Internet Software Consortium. +; +; 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$ + +$TTL 300 +. IN SOA gson.nominum.com. a.root.servers.nil. ( + 2000042100 ; serial + 600 ; refresh + 600 ; retry + 1200 ; expire + 600 ; minimum + ) +. NS a.root-servers.nil. +a.root-servers.nil. A 10.53.0.1 + +example. NS ns2.example. +ns2.example. A 10.53.0.2 diff --git a/bin/tests/system/statistics/ns2/example.db b/bin/tests/system/statistics/ns2/example.db new file mode 100644 index 0000000000..db2c9b64b2 --- /dev/null +++ b/bin/tests/system/statistics/ns2/example.db @@ -0,0 +1,34 @@ +; Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") +; Copyright (C) 2000, 2001 Internet Software Consortium. +; +; 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: example.db,v 1.1.2.1 2012/01/06 22:40:47 smann Exp $ + +$ORIGIN . +$TTL 300 ; 5 minutes +example IN SOA mname1. . ( + 1 ; serial + 20 ; refresh (20 seconds) + 20 ; retry (20 seconds) + 1814400 ; expire (3 weeks) + 3600 ; minimum (1 hour) + ) +example. NS ns2.example. +ns2.example. A 10.53.0.2 + +$ORIGIN example. +a A 10.0.0.1 + MX 10 mail.example. + +mail A 10.0.0.2 diff --git a/bin/tests/system/statistics/ns2/internal.db b/bin/tests/system/statistics/ns2/internal.db new file mode 100644 index 0000000000..8f27e43e39 --- /dev/null +++ b/bin/tests/system/statistics/ns2/internal.db @@ -0,0 +1,36 @@ +; Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") +; Copyright (C) 2000, 2001 Internet Software Consortium. +; +; 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: internal.db,v 1.1.2.1 2012/01/06 22:40:47 smann Exp $ + +$ORIGIN . +$TTL 300 ; 5 minutes +example IN SOA mname1. . ( + 2 ; serial + 20 ; refresh (20 seconds) + 20 ; retry (20 seconds) + 1814400 ; expire (3 weeks) + 3600 ; minimum (1 hour) + ) +example. NS ns2.example. +ns2.example. A 10.53.0.2 +example. NS ns3.example. +ns3.example. A 10.53.0.3 + +$ORIGIN example. +a A 10.1.0.1 + MX 10 intmail.example. + +intmail A 10.1.0.2 diff --git a/bin/tests/system/statistics/ns2/named.conf b/bin/tests/system/statistics/ns2/named.conf new file mode 100644 index 0000000000..e9cf3e90b1 --- /dev/null +++ b/bin/tests/system/statistics/ns2/named.conf @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 Internet Software Consortium. + * + * 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$ */ + +controls { /* empty */ }; + +options { + query-source address 10.53.0.2; + notify-source 10.53.0.2; + transfer-source 10.53.0.2; + port 5300; + pid-file "named.pid"; + listen-on { 10.53.0.2; }; + listen-on-v6 { none; }; + recursion yes; + notify yes; +}; + +#statistics-channels { inet * port 8888 allow { any; }; }; + +include "../../common/controls.conf"; + +zone "." { + type hint; + file "../../common/root.hint"; +}; + +zone "example" { + type master; + file "example.db"; + allow-update { any; }; +}; diff --git a/bin/tests/system/statistics/ns3/internal.db b/bin/tests/system/statistics/ns3/internal.db new file mode 100644 index 0000000000..c5ecc7c64e --- /dev/null +++ b/bin/tests/system/statistics/ns3/internal.db @@ -0,0 +1,34 @@ +; Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") +; Copyright (C) 2000, 2001 Internet Software Consortium. +; +; 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$ + +$ORIGIN . +$TTL 300 ; 5 minutes +example IN SOA mname1. . ( + 1 ; serial + 20 ; refresh (20 seconds) + 20 ; retry (20 seconds) + 1814400 ; expire (3 weeks) + 3600 ; minimum (1 hour) + ) +example. NS ns3.example. +ns3.example. A 10.53.0.3 + +$ORIGIN example. +a A 10.1.0.1 + MX 10 intmail.example. + +intmail A 10.1.0.2 diff --git a/bin/tests/system/statistics/ns3/named.conf b/bin/tests/system/statistics/ns3/named.conf new file mode 100644 index 0000000000..abbe5ca53a --- /dev/null +++ b/bin/tests/system/statistics/ns3/named.conf @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 Internet Software Consortium. + * + * 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$ */ + +controls { /* empty */ }; + +options { + query-source address 10.53.0.3; + notify-source 10.53.0.3; + transfer-source 10.53.0.3; + port 5300; + directory "."; + pid-file "named.pid"; + listen-on { 10.53.0.3; }; + listen-on-v6 { none; }; + recursion yes; + notify yes; +}; + +#statistics-channels { inet * port 8888 allow { any; }; }; + +key rndc_key { + secret "1234abcd8765"; + algorithm hmac-md5; +}; + +controls { + inet 10.53.0.3 port 9953 allow { any; } keys { rndc_key; }; +}; + +zone "." { + type hint; + file "root.hint"; +}; + +zone "example" { + type master; + allow-update { any; }; + file "internal.db"; +}; + + diff --git a/bin/tests/system/statistics/ns3/root.hint b/bin/tests/system/statistics/ns3/root.hint new file mode 100644 index 0000000000..7a325e08d0 --- /dev/null +++ b/bin/tests/system/statistics/ns3/root.hint @@ -0,0 +1,20 @@ +; Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") +; Copyright (C) 2000, 2001 Internet Software Consortium. +; +; 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$ + +$TTL 999999 +. IN NS d.root-servers.nil. +d.root-servers.nil. IN A 10.53.0.4 diff --git a/bin/tests/system/statistics/tests.sh b/bin/tests/system/statistics/tests.sh new file mode 100644 index 0000000000..d522641c53 --- /dev/null +++ b/bin/tests/system/statistics/tests.sh @@ -0,0 +1,108 @@ +#!/bin/sh +# +# Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") +# Copyright (C) 2000, 2001 Internet Software Consortium. +# +# 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: tests.sh,v 1.1.4.11 2012/02/01 16:54:32 each Exp $ + +SYSTEMTESTTOP=.. +. $SYSTEMTESTTOP/conf.sh + +DIGOPTS="+tcp +noadd +nosea +nostat +noquest +nocomm +nocmd" +DIGCMD="$DIG $DIGOPTS -p 5300" +RNDCCMD="$RNDC -p 9953 -c ../common/rndc.conf" + +status=0 +ret=0 +echo "I:fetching a.example from ns2's initial configuration" +$DIGCMD +noauth a.example. @10.53.0.2 any > dig.out.ns2.1 || ret=1 +if [ $ret != 0 ]; then echo "I: failed"; fi +status=`expr $status + $ret` + +ret=0 +echo "I:verifying adb records in named.stats" +$RNDCCMD -s 10.53.0.2 stats > /dev/null 2>&1 +echo "I: checking for 1 entry in adb hash table" +grep "1 Addresses in hash table" ns2/named.stats > /dev/null || ret=1 +if [ $ret != 0 ]; then echo "I:failed"; fi +status=`expr $status + $ret` + +ret=0 +echo "I: verifying cache statistics in named.stats" +grep "Cache Statistics" ns2/named.stats > /dev/null || ret=1 +if [ $ret != 0 ]; then echo "I:failed"; fi +status=`expr $status + $ret` + +ret=0 +echo "I: checking for 2 entries in adb hash table" +$DIGCMD a.example.info. @10.53.0.2 any > /dev/null 2>&1 +$RNDCCMD -s 10.53.0.2 stats > /dev/null 2>&1 +grep "2 Addresses in hash table" ns2/named.stats > /dev/null || ret=1 +if [ $ret != 0 ]; then echo "I: failed"; fi +status=`expr $status + $ret` + +ret=0 +echo "I:dumping initial stats for ns3" +rm -f ns3/named.stats +$RNDCCMD -s 10.53.0.3 stats > /dev/null 2>&1 +[ -f ns3/named.stats ] || ret=1 +nsock0=`grep "UDP/IPv4 sockets active" ns3/named.stats | awk '{print $1}'` +echo "I:sending queries to ns3" +$DIGCMD +tries=2 +time=1 +recurse @10.53.0.3 foo.info. any > /dev/null 2>&1 +#$DIGCMD +tries=2 +time=1 +recurse @10.53.0.3 foo.info. any +echo "I:dumping updated stats for ns3" +rm -f ns3/named.stats +$RNDCCMD -s 10.53.0.3 stats > /dev/null 2>&1 +[ -f ns3/named.stats ] || ret=1 +if [ $ret != 0 ]; then echo "I: failed"; fi +status=`expr $status + $ret` + +ret=0 +echo "I: verifying recursing clients output" +grep "2 recursing clients" ns3/named.stats > /dev/null || ret=1 +if [ $ret != 0 ]; then echo "I: failed"; fi +status=`expr $status + $ret` + +ret=0 +echo "I: verifying active fetches output" +grep "1 active fetches" ns3/named.stats > /dev/null || ret=1 +if [ $ret != 0 ]; then echo "I: failed"; fi +status=`expr $status + $ret` + +ret=0 +echo "I: verifying active sockets output" +nsock1=`grep "UDP/IPv4 sockets active" ns3/named.stats | awk '{print $1}'` +[ "$nsock0" -eq 2 ] || ret=1 +[ "$nsock1" -eq 3 ] || ret=1 +if [ $ret != 0 ]; then echo "I: failed"; fi +status=`expr $status + $ret` + +ret=0 +# there should be 1 UDP and no TCP queries. As the TCP counter is zero +# no status line is emitted. +echo "I: verifying queries in progress" +grep "1 UDP queries in progress" ns3/named.stats > /dev/null || ret=1 +grep "TCP queries in progress" ns3/named.stats > /dev/null && ret=1 +if [ $ret != 0 ]; then echo "I: failed"; fi +status=`expr $status + $ret` + +ret=0 +echo "I: verifying bucket size output" +grep "bucket size" ns3/named.stats > /dev/null || ret=1 +if [ $ret != 0 ]; then echo "I: failed"; fi +status=`expr $status + $ret` + +echo "I:exit status: $status" +exit $status diff --git a/lib/dns/adb.c b/lib/dns/adb.c index 8d17d82985..608fb3a37c 100644 --- a/lib/dns/adb.c +++ b/lib/dns/adb.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: adb.c,v 1.264 2011/12/05 17:10:51 each Exp $ */ +/* $Id: adb.c,v 1.264.16.1 2011/12/22 07:48:27 marka Exp $ */ /*! \file * @@ -474,6 +474,27 @@ inc_stats(dns_adb_t *adb, isc_statscounter_t counter) { isc_stats_increment(adb->view->resstats, counter); } +/*% + * Set adb-related statistics counters. + */ +static inline void +set_adbstat(dns_adb_t *adb, isc_uint64_t val, isc_statscounter_t counter) { + if (adb->view->adbstats != NULL) + isc_stats_set(adb->view->adbstats, val, counter); +} + +static inline void +dec_adbstats(dns_adb_t *adb, isc_statscounter_t counter) { + if (adb->view->adbstats != NULL) + isc_stats_increment(adb->view->adbstats, counter); +} + +static inline void +inc_adbstats(dns_adb_t *adb, isc_statscounter_t counter) { + if (adb->view->adbstats != NULL) + isc_stats_increment(adb->view->adbstats, counter); +} + static inline dns_ttl_t ttlclamp(dns_ttl_t ttl) { if (ttl < ADB_CACHE_MINIMUM) @@ -619,6 +640,8 @@ grow_entries(isc_task_t *task, isc_event_t *ev) { adb->entry_refcnt = newentry_refcnt; adb->nentries = n; + set_adbstat(adb, adb->nentries, dns_adbstats_nentries); + /* * Only on success do we set adb->growentries_sent to ISC_FALSE. * This will prevent us being continuously being called on error. @@ -771,6 +794,8 @@ grow_names(isc_task_t *task, isc_event_t *ev) { adb->name_refcnt = newname_refcnt; adb->nnames = n; + set_adbstat(adb, adb->nnames, dns_adbstats_nnames); + /* * Only on success do we set adb->grownames_sent to ISC_FALSE. * This will prevent us being continuously being called on error. @@ -1627,6 +1652,7 @@ new_adbname(dns_adb_t *adb, dns_name_t *dnsname) { LOCK(&adb->namescntlock); adb->namescnt++; + inc_adbstats(adb, dns_adbstats_namescnt); if (!adb->grownames_sent && adb->namescnt > (adb->nnames * 8)) { isc_event_t *event = &adb->grownames; inc_adb_irefcnt(adb); @@ -1660,6 +1686,7 @@ free_adbname(dns_adb_t *adb, dns_adbname_t **name) { isc_mempool_put(adb->nmp, n); LOCK(&adb->namescntlock); adb->namescnt--; + dec_adbstats(adb, dns_adbstats_namescnt); UNLOCK(&adb->namescntlock); } @@ -1751,6 +1778,7 @@ new_adbentry(dns_adb_t *adb) { ISC_LINK_INIT(e, plink); LOCK(&adb->entriescntlock); adb->entriescnt++; + inc_adbstats(adb, dns_adbstats_entriescnt); if (!adb->growentries_sent && adb->entriescnt > (adb->nentries * 8)) { isc_event_t *event = &adb->growentries; @@ -1788,6 +1816,7 @@ free_adbentry(dns_adb_t *adb, dns_adbentry_t **entry) { isc_mempool_put(adb->emp, e); LOCK(&adb->entriescntlock); adb->entriescnt--; + dec_adbstats(adb, dns_adbstats_entriescnt); UNLOCK(&adb->entriescntlock); } @@ -2559,6 +2588,12 @@ dns_adb_create(isc_mem_t *mem, dns_view_t *view, isc_timermgr_t *timermgr, goto fail3; isc_task_setname(adb->task, "ADB", adb); + result = isc_stats_create(adb->mctx, &view->adbstats, dns_adbstats_max); + if (result != ISC_R_SUCCESS) + goto fail3; + set_adbstat(adb, adb->nentries, dns_adbstats_nentries); + set_adbstat(adb, adb->nnames, dns_adbstats_nnames); + /* * Normal return. */ diff --git a/lib/dns/cache.c b/lib/dns/cache.c index 7ba944b7bc..82030594b2 100644 --- a/lib/dns/cache.c +++ b/lib/dns/cache.c @@ -22,7 +22,9 @@ #include #include +#include #include +#include #include #include #include @@ -39,6 +41,7 @@ #include #include #include +#include #include "rbtdb.h" @@ -137,6 +140,7 @@ struct dns_cache { int db_argc; char **db_argv; isc_uint32_t size; + isc_stats_t *stats; /* Locked by 'filelock'. */ char *filename; @@ -237,10 +241,16 @@ dns_cache_create3(isc_mem_t *cmctx, isc_mem_t *hmctx, isc_taskmgr_t *taskmgr, cache->live_tasks = 0; cache->rdclass = rdclass; + cache->stats = NULL; + result = isc_stats_create(cmctx, &cache->stats, + dns_cachestatscounter_max); + if (result != ISC_R_SUCCESS) + goto cleanup_filelock; + cache->db_type = isc_mem_strdup(cmctx, db_type); if (cache->db_type == NULL) { result = ISC_R_NOMEMORY; - goto cleanup_filelock; + goto cleanup_stats; } /* @@ -309,6 +319,11 @@ dns_cache_create3(isc_mem_t *cmctx, isc_mem_t *hmctx, isc_taskmgr_t *taskmgr, if (result != ISC_R_SUCCESS) goto cleanup_db; + result = dns_db_setcachestats(cache->db, cache->stats); + if (result != ISC_R_SUCCESS) + goto cleanup_db; + + *cachep = cache; return (ISC_R_SUCCESS); @@ -325,6 +340,8 @@ dns_cache_create3(isc_mem_t *cmctx, isc_mem_t *hmctx, isc_taskmgr_t *taskmgr, isc_mem_free(cmctx, cache->db_type); cleanup_filelock: DESTROYLOCK(&cache->filelock); + cleanup_stats: + isc_stats_detach(&cache->stats); cleanup_lock: DESTROYLOCK(&cache->lock); cleanup_mem: @@ -387,6 +404,9 @@ cache_free(dns_cache_t *cache) { if (cache->name != NULL) isc_mem_free(cache->mctx, cache->name); + if (cache->stats != NULL) + isc_stats_detach(&cache->stats); + DESTROYLOCK(&cache->lock); DESTROYLOCK(&cache->filelock); @@ -1279,3 +1299,145 @@ dns_cache_flushnode(dns_cache_t *cache, dns_name_t *name, dns_db_detach(&db); return (result); } + +isc_stats_t * +dns_cache_getstats(dns_cache_t *cache) { + REQUIRE(VALID_CACHE(cache)); + return (cache->stats); +} + +/* + * XXX: Much of the following code has been copied in from statschannel.c. + * We should refactor this into a generic function in stats.c that can be + * called from both places. + */ +typedef struct +cache_dumparg { + 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; +} cache_dumparg_t; + +static void +getcounter(isc_statscounter_t counter, isc_uint64_t val, void *arg) { + cache_dumparg_t *dumparg = arg; + + REQUIRE(counter < dumparg->ncounters); + dumparg->countervalues[counter] = val; +} + +static void +getcounters(isc_stats_t *stats, isc_statsformat_t type, int ncounters, + int *indices, isc_uint64_t *values) +{ + cache_dumparg_t dumparg; + + memset(values, 0, sizeof(values[0]) * ncounters); + + dumparg.type = type; + dumparg.ncounters = ncounters; + dumparg.counterindices = indices; + dumparg.countervalues = values; + + isc_stats_dump(stats, getcounter, &dumparg, ISC_STATSDUMP_VERBOSE); +} + +void +dns_cache_dumpstats(dns_cache_t *cache, FILE *fp) { + int indices[dns_cachestatscounter_max]; + isc_uint64_t values[dns_cachestatscounter_max]; + + REQUIRE(VALID_CACHE(cache)); + + getcounters(cache->stats, isc_statsformat_file, + dns_cachestatscounter_max, indices, values); + + fprintf(fp, "%20" ISC_PRINT_QUADFORMAT "u %s\n", + values[dns_cachestatscounter_hits], + "cache hits"); + fprintf(fp, "%20" ISC_PRINT_QUADFORMAT "u %s\n", + values[dns_cachestatscounter_misses], + "cache misses"); + fprintf(fp, "%20" ISC_PRINT_QUADFORMAT "u %s\n", + values[dns_cachestatscounter_queryhits], + "cache hits (from query)"); + fprintf(fp, "%20" ISC_PRINT_QUADFORMAT "u %s\n", + values[dns_cachestatscounter_querymisses], + "cache misses (from query)"); + fprintf(fp, "%20" ISC_PRINT_QUADFORMAT "u %s\n", + values[dns_cachestatscounter_deletelru], + "cache records deleted due to memory exhaustion"); + fprintf(fp, "%20" ISC_PRINT_QUADFORMAT "u %s\n", + values[dns_cachestatscounter_deletettl], + "cache records deleted due to TTL expiration"); + fprintf(fp, "%20u %s\n", dns_db_nodecount(cache->db), + "cache database nodes"); + fprintf(fp, "%20u %s\n", dns_db_hashsize(cache->db), + "cache database hash buckets"); + + fprintf(fp, "%20u %s\n", (unsigned int) isc_mem_total(cache->mctx), + "cache tree memory total"); + fprintf(fp, "%20u %s\n", (unsigned int) isc_mem_inuse(cache->mctx), + "cache tree memory in use"); + fprintf(fp, "%20u %s\n", (unsigned int) isc_mem_maxinuse(cache->mctx), + "cache tree highest memory in use"); + + fprintf(fp, "%20u %s\n", (unsigned int) isc_mem_total(cache->hmctx), + "cache heap memory total"); + fprintf(fp, "%20u %s\n", (unsigned int) isc_mem_inuse(cache->hmctx), + "cache heap memory in use"); + fprintf(fp, "%20u %s\n", (unsigned int) isc_mem_maxinuse(cache->hmctx), + "cache heap highest memory in use"); +} + +#ifdef HAVE_LIBXML2 +static void +renderstat(const char *name, isc_uint64_t value, xmlTextWriterPtr writer) { + xmlTextWriterStartElement(writer, ISC_XMLCHAR "cachestat"); + xmlTextWriterStartElement(writer, ISC_XMLCHAR "name"); + xmlTextWriterWriteString(writer, ISC_XMLCHAR name); + xmlTextWriterEndElement(writer); /* name */ + xmlTextWriterStartElement(writer, ISC_XMLCHAR "value"); + xmlTextWriterWriteFormatString(writer, + "%" ISC_PRINT_QUADFORMAT "u", value); + xmlTextWriterEndElement(writer); /* value */ + xmlTextWriterEndElement(writer); /* cachestat */ +} + +void +dns_cache_renderxml(dns_cache_t *cache, xmlTextWriterPtr writer) { + int indices[dns_cachestatscounter_max]; + isc_uint64_t values[dns_cachestatscounter_max]; + + REQUIRE(VALID_CACHE(cache)); + + getcounters(cache->stats, isc_statsformat_file, + dns_cachestatscounter_max, indices, values); + renderstat("CacheHits", + values[dns_cachestatscounter_hits], writer); + renderstat("CacheMisses", + values[dns_cachestatscounter_misses], writer); + renderstat("QueryHits", + values[dns_cachestatscounter_queryhits], writer); + renderstat("QueryMisses", + values[dns_cachestatscounter_querymisses], writer); + renderstat("DeleteLRU", + values[dns_cachestatscounter_deletelru], writer); + renderstat("DeleteTTL", + values[dns_cachestatscounter_deletettl], writer); + + renderstat("CacheNodes", dns_db_nodecount(cache->db), writer); + renderstat("CacheBuckets", dns_db_hashsize(cache->db), writer); + + renderstat("TreeMemTotal", isc_mem_total(cache->mctx), writer); + renderstat("TreeMemInUse", isc_mem_inuse(cache->mctx), writer); + renderstat("TreeMemMax", isc_mem_maxinuse(cache->mctx), writer); + + renderstat("HeapMemTotal", isc_mem_total(cache->hmctx), writer); + renderstat("HeapMemInUse", isc_mem_inuse(cache->hmctx), writer); + renderstat("HeapMemMax", isc_mem_maxinuse(cache->hmctx), writer); +} +#endif diff --git a/lib/dns/db.c b/lib/dns/db.c index e7e4bf154f..6c0f05da47 100644 --- a/lib/dns/db.c +++ b/lib/dns/db.c @@ -879,6 +879,16 @@ dns_db_nodecount(dns_db_t *db) { return ((db->methods->nodecount)(db)); } +unsigned int +dns_db_hashsize(dns_db_t *db) { + REQUIRE(DNS_DB_VALID(db)); + + if (db->methods->hashsize == NULL) + return (ISC_R_NOTIMPLEMENTED); + + return ((db->methods->hashsize)(db)); +} + void dns_db_settask(dns_db_t *db, isc_task_t *task) { REQUIRE(DNS_DB_VALID(db)); @@ -965,6 +975,16 @@ dns_db_getrrsetstats(dns_db_t *db) { return (NULL); } +isc_result_t +dns_db_setcachestats(dns_db_t *db, isc_stats_t *stats) { + REQUIRE(DNS_DB_VALID(db)); + + if (db->methods->setcachestats != NULL) + return ((db->methods->setcachestats)(db, stats)); + + return (ISC_R_NOTIMPLEMENTED); +} + isc_result_t dns_db_getnsec3parameters(dns_db_t *db, dns_dbversion_t *version, dns_hash_t *hash, isc_uint8_t *flags, diff --git a/lib/dns/dispatch.c b/lib/dns/dispatch.c index 50ea25c442..6a2584780f 100644 --- a/lib/dns/dispatch.c +++ b/lib/dns/dispatch.c @@ -371,6 +371,12 @@ inc_stats(dns_dispatchmgr_t *mgr, isc_statscounter_t counter) { isc_stats_increment(mgr->stats, counter); } +static inline void +dec_stats(dns_dispatchmgr_t *mgr, isc_statscounter_t counter) { + if (mgr->stats != NULL) + isc_stats_decrement(mgr->stats, counter); +} + static void dispatch_log(dns_dispatch_t *disp, int level, const char *fmt, ...) ISC_FORMAT_PRINTF(3, 4); @@ -3360,6 +3366,10 @@ dns_dispatch_addresponse2(dns_dispatch_t *disp, isc_sockaddr_t *dest, ISC_LIST_APPEND(qid->qid_table[bucket], res, link); UNLOCK(&qid->lock); + inc_stats(disp->mgr, (qid == disp->mgr->qid) ? + dns_resstatscounter_disprequdp : + dns_resstatscounter_dispreqtcp); + request_log(disp, res, LVL(90), "attached to task %p", res->task); @@ -3377,6 +3387,10 @@ dns_dispatch_addresponse2(dns_dispatch_t *disp, isc_sockaddr_t *dest, disp->refcount--; disp->requests--; + dec_stats(disp->mgr, (qid == disp->mgr->qid) ? + dns_resstatscounter_disprequdp : + dns_resstatscounter_dispreqtcp); + UNLOCK(&disp->lock); isc_task_detach(&res->task); isc_mempool_put(disp->mgr->rpool, res); @@ -3463,6 +3477,9 @@ dns_dispatch_removeresponse(dns_dispentry_t **resp, INSIST(disp->requests > 0); disp->requests--; + dec_stats(disp->mgr, (qid == disp->mgr->qid) ? + dns_resstatscounter_disprequdp : + dns_resstatscounter_dispreqtcp); INSIST(disp->refcount > 0); disp->refcount--; if (disp->refcount == 0) { diff --git a/lib/dns/ecdb.c b/lib/dns/ecdb.c index fa08f0860c..e890503162 100644 --- a/lib/dns/ecdb.c +++ b/lib/dns/ecdb.c @@ -578,7 +578,9 @@ static dns_dbmethods_t ecdb_methods = { NULL, /* rpz_enabled */ NULL, /* rpz_findips */ NULL, /* findnodeext */ - NULL /* findext */ + NULL, /* findext */ + NULL, /* setcachestats */ + NULL /* hashsize */ }; static isc_result_t diff --git a/lib/dns/include/dns/cache.h b/lib/dns/include/dns/cache.h index 419111b930..a73916b813 100644 --- a/lib/dns/include/dns/cache.h +++ b/lib/dns/include/dns/cache.h @@ -50,6 +50,7 @@ ***/ #include +#include #include #include @@ -312,6 +313,26 @@ dns_cache_flushname(dns_cache_t *cache, dns_name_t *name); *\li other error returns. */ +isc_stats_t * +dns_cache_getstats(dns_cache_t *cache); +/* + * Return a pointer to the stats collection object for 'cache' + */ + +void +dns_cache_dumpstats(dns_cache_t *cache, FILE *fp); +/* + * Dump cache statistics and status in text to 'fp' + */ + +#ifdef HAVE_LIBXML2 +void +dns_cache_renderxml(dns_cache_t *cache, xmlTextWriterPtr writer); +/* + * Render cache statistics and status in XML for 'writer'. + */ +#endif /* HAVE_LIBXML2 */ + ISC_LANG_ENDDECLS #endif /* DNS_CACHE_H */ diff --git a/lib/dns/include/dns/db.h b/lib/dns/include/dns/db.h index 48b5a26eab..af46965798 100644 --- a/lib/dns/include/dns/db.h +++ b/lib/dns/include/dns/db.h @@ -57,6 +57,7 @@ #include #include #include +#include #include #include @@ -194,6 +195,8 @@ typedef struct dns_dbmethods { dns_clientinfo_t *clientinfo, dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset); + isc_result_t (*setcachestats)(dns_db_t *db, isc_stats_t *stats); + unsigned int (*hashsize)(dns_db_t *db); } dns_dbmethods_t; typedef isc_result_t @@ -1337,6 +1340,21 @@ dns_db_nodecount(dns_db_t *db); * \li The number of nodes in the database */ +unsigned int +dns_db_hashsize(dns_db_t *db); +/*%< + * For database implementations using a hash table, report the + * current number of buckets. + * + * Requires: + * + * \li 'db' is a valid database. + * + * Returns: + * \li The number of buckets in the database's hash table, or + * ISC_R_NOTIMPLEMENTED. + */ + void dns_db_settask(dns_db_t *db, isc_task_t *task); /*%< @@ -1531,7 +1549,22 @@ dns_db_getrrsetstats(dns_db_t *db); * * Requires: * - * \li 'db' is a valid database (zone or cache). + * \li 'db' is a valid database (cache only). + * + * Returns: + * \li when available, a pointer to a statistics object created by + * dns_rdatasetstats_create(); otherwise NULL. + */ + +isc_result_t +dns_db_setcachestats(dns_db_t *db, isc_stats_t *stats); +/*%< + * Set the location in which to collect cache statistics. + * This option may not exist depending on the DB implementation. + * + * Requires: + * + * \li 'db' is a valid database (cache only). * * Returns: * \li when available, a pointer to a statistics object created by diff --git a/lib/dns/include/dns/rbt.h b/lib/dns/include/dns/rbt.h index 3e9dc88657..d0a1ef9818 100644 --- a/lib/dns/include/dns/rbt.h +++ b/lib/dns/include/dns/rbt.h @@ -632,6 +632,15 @@ dns_rbt_nodecount(dns_rbt_t *rbt); * \li rbt is a valid rbt manager. */ +unsigned int +dns_rbt_hashsize(dns_rbt_t *rbt); +/*%< + * Obtain the current number of buckets in the 'rbt' hash table. + * + * Requires: + * \li rbt is a valid rbt manager. + */ + void dns_rbt_destroy(dns_rbt_t **rbtp); isc_result_t diff --git a/lib/dns/include/dns/stats.h b/lib/dns/include/dns/stats.h index bc77d1e9c5..aa0aaf7676 100644 --- a/lib/dns/include/dns/stats.h +++ b/lib/dns/include/dns/stats.h @@ -61,8 +61,12 @@ enum { dns_resstatscounter_queryrtt3 = 27, dns_resstatscounter_queryrtt4 = 28, dns_resstatscounter_queryrtt5 = 29, + dns_resstatscounter_nfetch = 30, + dns_resstatscounter_disprequdp = 31, + dns_resstatscounter_dispreqtcp = 32, + dns_resstatscounter_buckets = 33, - dns_resstatscounter_max = 30, + dns_resstatscounter_max = 34, /*% * Zone statistics counters. @@ -83,9 +87,31 @@ enum { dns_zonestatscounter_max = 13, + /* + * Adb statistics values. + */ + dns_adbstats_nentries = 0, + dns_adbstats_entriescnt = 1, + dns_adbstats_nnames = 2, + dns_adbstats_namescnt = 3, + + dns_adbstats_max = 4, + + /* + * Cache statistics values. + */ + dns_cachestatscounter_hits = 1, + dns_cachestatscounter_misses = 2, + dns_cachestatscounter_queryhits = 3, + dns_cachestatscounter_querymisses = 4, + dns_cachestatscounter_deletelru = 5, + dns_cachestatscounter_deletettl = 6, + + dns_cachestatscounter_max = 7, + /*% - * Query statistics counters (obsolete). - */ + * Query statistics counters (obsolete). + */ dns_statscounter_success = 0, /*%< Successful lookup */ dns_statscounter_referral = 1, /*%< Referral result */ dns_statscounter_nxrrset = 2, /*%< NXRRSET result */ diff --git a/lib/dns/include/dns/view.h b/lib/dns/include/dns/view.h index bb42d84726..603819a267 100644 --- a/lib/dns/include/dns/view.h +++ b/lib/dns/include/dns/view.h @@ -108,6 +108,7 @@ struct dns_view { isc_event_t resevent; isc_event_t adbevent; isc_event_t reqevent; + isc_stats_t * adbstats; isc_stats_t * resstats; dns_stats_t * resquerystats; isc_boolean_t cacheshared; @@ -953,6 +954,31 @@ dns_view_freezezones(dns_view_t *view, isc_boolean_t freeze); * \li 'view' is valid. */ +void +dns_view_setadbstats(dns_view_t *view, isc_stats_t *stats); +/*%< + * Set a adb statistics set 'stats' for 'view'. + * + * Requires: + * \li 'view' is valid and is not frozen. + * + *\li stats is a valid statistics supporting adb statistics + * (see dns/stats.h). + */ + +void +dns_view_getadbstats(dns_view_t *view, isc_stats_t **statsp); +/*%< + * Get the adb statistics counter set for 'view'. If a statistics set is + * set '*statsp' will be attached to the set; otherwise, '*statsp' will be + * untouched. + * + * Requires: + * \li 'view' is valid and is not frozen. + * + *\li 'statsp' != NULL && '*statsp' != NULL + */ + void dns_view_setresstats(dns_view_t *view, isc_stats_t *stats); /*%< diff --git a/lib/dns/rbt.c b/lib/dns/rbt.c index 4e033d66ed..e3618efddb 100644 --- a/lib/dns/rbt.c +++ b/lib/dns/rbt.c @@ -310,6 +310,12 @@ dns_rbt_nodecount(dns_rbt_t *rbt) { return (rbt->nodecount); } +unsigned int +dns_rbt_hashsize(dns_rbt_t *rbt) { + REQUIRE(VALID_RBT(rbt)); + return (rbt->hashsize); +} + static inline isc_result_t chain_name(dns_rbtnodechain_t *chain, dns_name_t *name, isc_boolean_t include_chain_end) diff --git a/lib/dns/rbtdb.c b/lib/dns/rbtdb.c index 5bae6c48e1..3d85e995f2 100644 --- a/lib/dns/rbtdb.c +++ b/lib/dns/rbtdb.c @@ -367,6 +367,13 @@ typedef enum { typedef struct dns_rbtdb dns_rbtdb_t; +/* Reason for expiring a record from cache */ +typedef enum { + expire_lru, + expire_ttl, + expire_flush +} expire_t; + typedef struct rbtdb_version { /* Not locked */ rbtdb_serial_t serial; @@ -411,6 +418,7 @@ struct dns_rbtdb { rbtdb_nodelock_t * node_locks; dns_rbtnode_t * origin_node; dns_stats_t * rrsetstats; /* cache DB only */ + isc_stats_t * cachestats; /* cache DB only */ /* Locked by lock. */ unsigned int active; isc_refcount_t references; @@ -530,7 +538,7 @@ static inline isc_boolean_t need_headerupdate(rdatasetheader_t *header, static void update_header(dns_rbtdb_t *rbtdb, rdatasetheader_t *header, isc_stdtime_t now); static void expire_header(dns_rbtdb_t *rbtdb, rdatasetheader_t *header, - isc_boolean_t tree_locked); + isc_boolean_t tree_locked, expire_t reason); static void overmem_purge(dns_rbtdb_t *rbtdb, unsigned int locknum_start, isc_stdtime_t now, isc_boolean_t tree_locked); static isc_result_t resign_insert(dns_rbtdb_t *rbtdb, int idx, @@ -695,6 +703,26 @@ free_rbtdb_callback(isc_task_t *task, isc_event_t *event) { free_rbtdb(rbtdb, ISC_TRUE, event); } +static void +update_cachestats(dns_rbtdb_t *rbtdb, isc_result_t result) { + INSIST(IS_CACHE(rbtdb)); + + switch (result) { + case ISC_R_SUCCESS: + case DNS_R_CNAME: + case DNS_R_DNAME: + case DNS_R_DELEGATION: + case DNS_R_NCACHENXDOMAIN: + case DNS_R_NCACHENXRRSET: + isc_stats_increment(rbtdb->cachestats, + dns_cachestatscounter_hits); + break; + default: + isc_stats_increment(rbtdb->cachestats, + dns_cachestatscounter_misses); + } +} + static void update_rrsetstats(dns_rbtdb_t *rbtdb, rdatasetheader_t *header, isc_boolean_t increment) @@ -968,6 +996,8 @@ free_rbtdb(dns_rbtdb_t *rbtdb, isc_boolean_t log, isc_event_t *event) { if (rbtdb->rrsetstats != NULL) dns_stats_detach(&rbtdb->rrsetstats); + if (rbtdb->cachestats != NULL) + isc_stats_detach(&rbtdb->cachestats); #ifdef BIND9 if (rbtdb->rpz_cidr != NULL) @@ -5102,6 +5132,7 @@ cache_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version, dns_rbtnodechain_reset(&search.chain); + update_cachestats(search.rbtdb, result); return (result); } @@ -5711,6 +5742,8 @@ cache_findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, result = DNS_R_NCACHENXRRSET; } + update_cachestats(rbtdb, result); + return (result); } @@ -6542,7 +6575,8 @@ addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, header = isc_heap_element(rbtdb->heaps[rbtnode->locknum], 1); if (header && header->rdh_ttl <= now - RBTDB_VIRTUAL) - expire_header(rbtdb, header, tree_locked); + expire_header(rbtdb, header, tree_locked, + expire_ttl); /* * If we've been holding a write lock on the tree just for @@ -7172,6 +7206,22 @@ nodecount(dns_db_t *db) { return (count); } +static unsigned int +hashsize(dns_db_t *db) { + dns_rbtdb_t *rbtdb; + unsigned int count; + + rbtdb = (dns_rbtdb_t *)db; + + REQUIRE(VALID_RBTDB(rbtdb)); + + RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_read); + count = dns_rbt_hashsize(rbtdb->tree); + RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_read); + + return (count); +} + static void settask(dns_db_t *db, isc_task_t *task) { dns_rbtdb_t *rbtdb; @@ -7390,6 +7440,18 @@ resigned(dns_db_t *db, dns_rdataset_t *rdataset, dns_dbversion_t *version) RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_write); } +static isc_result_t +setcachestats(dns_db_t *db, isc_stats_t *stats) { + dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db; + + REQUIRE(VALID_RBTDB(rbtdb)); + REQUIRE(IS_CACHE(rbtdb)); /* current restriction */ + REQUIRE(stats != NULL); + + isc_stats_attach(stats, &rbtdb->cachestats); + return (ISC_R_SUCCESS); +} + static dns_stats_t * getrrsetstats(dns_db_t *db) { dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db; @@ -7445,7 +7507,9 @@ static dns_dbmethods_t zone_methods = { NULL, #endif NULL, - NULL + NULL, + NULL, + hashsize }; static dns_dbmethods_t cache_methods = { @@ -7488,7 +7552,9 @@ static dns_dbmethods_t cache_methods = { NULL, NULL, NULL, - NULL + NULL, + setcachestats, + hashsize }; isc_result_t @@ -7566,6 +7632,8 @@ dns_rbtdb_create goto cleanup_tree_lock; } + rbtdb->cachestats = NULL; + rbtdb->rrsetstats = NULL; if (IS_CACHE(rbtdb)) { result = dns_rdatasetstats_create(mctx, &rbtdb->rrsetstats); @@ -8106,7 +8174,7 @@ rdataset_expire(dns_rdataset_t *rdataset) { header--; NODE_LOCK(&rbtdb->node_locks[rbtnode->locknum].lock, isc_rwlocktype_write); - expire_header(rbtdb, header, ISC_FALSE); + expire_header(rbtdb, header, ISC_FALSE, expire_flush); NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock, isc_rwlocktype_write); } @@ -9283,7 +9351,8 @@ overmem_purge(dns_rbtdb_t *rbtdb, unsigned int locknum_start, header = isc_heap_element(rbtdb->heaps[locknum], 1); if (header && header->rdh_ttl <= now - RBTDB_VIRTUAL) { - expire_header(rbtdb, header, tree_locked); + expire_header(rbtdb, header, tree_locked, + expire_ttl); purgecount--; } @@ -9300,7 +9369,8 @@ overmem_purge(dns_rbtdb_t *rbtdb, unsigned int locknum_start, */ ISC_LIST_UNLINK(rbtdb->rdatasets[locknum], header, link); - expire_header(rbtdb, header, tree_locked); + expire_header(rbtdb, header, tree_locked, + expire_lru); purgecount--; } @@ -9311,7 +9381,7 @@ overmem_purge(dns_rbtdb_t *rbtdb, unsigned int locknum_start, static void expire_header(dns_rbtdb_t *rbtdb, rdatasetheader_t *header, - isc_boolean_t tree_locked) + isc_boolean_t tree_locked, expire_t reason) { set_ttl(rbtdb, header, 0); header->attributes |= RDATASET_ATTR_STALE; @@ -9332,5 +9402,22 @@ expire_header(dns_rbtdb_t *rbtdb, rdatasetheader_t *header, isc_rwlocktype_write, tree_locked ? isc_rwlocktype_write : isc_rwlocktype_none, ISC_FALSE); + + if (rbtdb->cachestats == NULL) + return; + + switch (reason) { + case expire_ttl: + isc_stats_increment(rbtdb->cachestats, + dns_cachestatscounter_deletettl); + break; + case expire_lru: + isc_stats_increment(rbtdb->cachestats, + dns_cachestatscounter_deletelru); + break; + default: + break; + } + } } diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c index acef820c7e..48dcedf5a0 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -471,6 +471,12 @@ inc_stats(dns_resolver_t *res, isc_statscounter_t counter) { isc_stats_increment(res->view->resstats, counter); } +static inline void +dec_stats(dns_resolver_t *res, isc_statscounter_t counter) { + if (res->view->resstats != NULL) + isc_stats_decrement(res->view->resstats, counter); +} + static isc_result_t valcreate(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, dns_name_t *name, dns_rdatatype_t type, dns_rdataset_t *rdataset, @@ -3102,6 +3108,7 @@ fctx_unlink(fetchctx_t *fctx) { LOCK(&res->nlock); res->nfctx--; UNLOCK(&res->nlock); + dec_stats(res, dns_resstatscounter_nfetch); if (res->buckets[bucketnum].exiting && ISC_LIST_EMPTY(res->buckets[bucketnum].fctxs)) @@ -3725,6 +3732,7 @@ fctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type, LOCK(&res->nlock); res->nfctx++; UNLOCK(&res->nlock); + inc_stats(res, dns_resstatscounter_nfetch); *fctxp = fctx; @@ -7475,6 +7483,9 @@ dns_resolver_create(dns_view_t *view, res->zero_no_soa_ttl = ISC_FALSE; res->query_timeout = DEFAULT_QUERY_TIMEOUT; res->nbuckets = ntasks; + if (view->resstats != NULL) + isc_stats_set(view->resstats, ntasks, + dns_resstatscounter_buckets); res->activebuckets = ntasks; res->buckets = isc_mem_get(view->mctx, ntasks * sizeof(fctxbucket_t)); diff --git a/lib/dns/sdb.c b/lib/dns/sdb.c index 3dd1c46e51..9623bc1eab 100644 --- a/lib/dns/sdb.c +++ b/lib/dns/sdb.c @@ -1298,7 +1298,9 @@ static dns_dbmethods_t sdb_methods = { NULL, /* rpz_enabled */ NULL, /* rpz_findips */ findnodeext, - findext + findext, + NULL, /* setcachestats */ + NULL /* hashsize */ }; static isc_result_t diff --git a/lib/dns/sdlz.c b/lib/dns/sdlz.c index a9b95240c5..b39c111924 100644 --- a/lib/dns/sdlz.c +++ b/lib/dns/sdlz.c @@ -1263,7 +1263,9 @@ static dns_dbmethods_t sdlzdb_methods = { NULL, /* rpz_enabled */ NULL, /* rpz_findips */ findnodeext, - findext + findext, + NULL, /* setcachestats */ + NULL /* hashsize */ }; /* diff --git a/lib/dns/tests/master_test.c b/lib/dns/tests/master_test.c index bc9cddfb14..fb4d517b90 100644 --- a/lib/dns/tests/master_test.c +++ b/lib/dns/tests/master_test.c @@ -22,8 +22,11 @@ #include +#include #include +#include + #include #include #include diff --git a/lib/dns/view.c b/lib/dns/view.c index ae403b6d86..611e4871c9 100644 --- a/lib/dns/view.c +++ b/lib/dns/view.c @@ -149,6 +149,7 @@ dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass, view->delonly = NULL; view->rootdelonly = ISC_FALSE; view->rootexclude = NULL; + view->adbstats = NULL; view->resstats = NULL; view->resquerystats = NULL; view->cacheshared = ISC_FALSE; @@ -416,6 +417,8 @@ destroy(dns_view_t *view) { sizeof(dns_namelist_t) * DNS_VIEW_DELONLYHASH); view->rootexclude = NULL; } + if (view->adbstats != NULL) + isc_stats_detach(&view->adbstats); if (view->resstats != NULL) isc_stats_detach(&view->resstats); if (view->resquerystats != NULL) @@ -1682,6 +1685,24 @@ dns_view_freezezones(dns_view_t *view, isc_boolean_t value) { } #endif +void +dns_view_setadbstats(dns_view_t *view, isc_stats_t *stats) { + REQUIRE(DNS_VIEW_VALID(view)); + REQUIRE(!view->frozen); + REQUIRE(view->adbstats == NULL); + + isc_stats_attach(stats, &view->adbstats); +} + +void +dns_view_getadbstats(dns_view_t *view, isc_stats_t **statsp) { + REQUIRE(DNS_VIEW_VALID(view)); + REQUIRE(statsp != NULL && *statsp == NULL); + + if (view->adbstats != NULL) + isc_stats_attach(view->adbstats, statsp); +} + void dns_view_setresstats(dns_view_t *view, isc_stats_t *stats) { REQUIRE(DNS_VIEW_VALID(view)); diff --git a/lib/dns/win32/libdns.def b/lib/dns/win32/libdns.def index 37f9ae5d81..abf8052ba2 100644 --- a/lib/dns/win32/libdns.def +++ b/lib/dns/win32/libdns.def @@ -114,6 +114,7 @@ dns_db_getnsec3parameters dns_db_getoriginnode dns_db_getrrsetstats dns_db_getsoaserial +dns_db_hashsize dns_db_iscache dns_db_isdnssec dns_db_ispersistent @@ -132,6 +133,7 @@ dns_db_printnode dns_db_register dns_db_rpz_enabled dns_db_rpz_findips +dns_db_setcachestats dns_db_subtractrdataset dns_db_unregister dns_dbiterator_current @@ -493,6 +495,7 @@ dns_rbt_findname dns_rbt_findnode dns_rbt_formatnodename dns_rbt_fullnamefromnode +dns_rbt_hashsize dns_rbt_namefromnode dns_rbt_nodecount dns_rbt_printall diff --git a/lib/isc/include/isc/mem.h b/lib/isc/include/isc/mem.h index 5101ea3fed..07fcc1a58b 100644 --- a/lib/isc/include/isc/mem.h +++ b/lib/isc/include/isc/mem.h @@ -224,6 +224,8 @@ typedef struct isc_memmethods { void *water_arg, size_t hiwater, size_t lowater); void (*waterack)(isc_mem_t *ctx, int flag); size_t (*inuse)(isc_mem_t *mctx); + size_t (*maxinuse)(isc_mem_t *mctx); + size_t (*total)(isc_mem_t *mctx); isc_boolean_t (*isovermem)(isc_mem_t *mctx); isc_result_t (*mpcreate)(isc_mem_t *mctx, size_t size, isc_mempool_t **mpctxp); @@ -416,11 +418,25 @@ isc_mem_getquota(isc_mem_t *); size_t isc_mem_inuse(isc_mem_t *mctx); /*%< - * Get an estimate of the number of memory in use in 'mctx', in bytes. + * Get an estimate of the amount of memory in use in 'mctx', in bytes. * This includes quantization overhead, but does not include memory * allocated from the system but not yet used. */ +size_t +isc_mem_maxinuse(isc_mem_t *mctx); +/*%< + * Get an estimate of the largest amount of memory that has been in + * use in 'mctx' at any time. + */ + +size_t +isc_mem_total(isc_mem_t *mctx); +/*%< + * Get the total amount of memory in 'mctx', in bytes, including memory + * not yet used. + */ + isc_boolean_t isc_mem_isovermem(isc_mem_t *mctx); /*%< diff --git a/lib/isc/include/isc/namespace.h b/lib/isc/include/isc/namespace.h index cd4ec9ad16..444e814348 100644 --- a/lib/isc/include/isc/namespace.h +++ b/lib/isc/include/isc/namespace.h @@ -68,6 +68,8 @@ #define isc_mem_getquota isc__mem_getquota #define isc_mem_gettag isc__mem_gettag #define isc_mem_inuse isc__mem_inuse +#define isc_mem_maxinuse isc__mem_maxinuse +#define isc_mem_total isc__mem_total #define isc_mem_isovermem isc__mem_isovermem #define isc_mem_setname isc__mem_setname #define isc_mem_setwater isc__mem_setwater diff --git a/lib/isc/include/isc/socket.h b/lib/isc/include/isc/socket.h index d59ade659b..a54d7688a4 100644 --- a/lib/isc/include/isc/socket.h +++ b/lib/isc/include/isc/socket.h @@ -150,7 +150,13 @@ enum { isc_sockstatscounter_unixrecvfail = 50, isc_sockstatscounter_fdwatchrecvfail = 51, - isc_sockstatscounter_max = 52 + isc_sockstatscounter_udp4active = 52, + isc_sockstatscounter_udp6active = 53, + isc_sockstatscounter_tcp4active = 54, + isc_sockstatscounter_tcp6active = 55, + isc_sockstatscounter_unixactive = 56, + + isc_sockstatscounter_max = 57 }; /*** diff --git a/lib/isc/include/isc/stats.h b/lib/isc/include/isc/stats.h index 682eefdedf..4dd739ccd2 100644 --- a/lib/isc/include/isc/stats.h +++ b/lib/isc/include/isc/stats.h @@ -116,6 +116,26 @@ isc_stats_dump(isc_stats_t *stats, isc_stats_dumper_t dump_fn, void *arg, *\li 'stats' is a valid isc_stats_t. */ +void +isc_stats_set(isc_stats_t *stats, isc_uint64_t val, + isc_statscounter_t counter); +/*%< + * Set the given counter to the specfied value. + * + * Requires: + *\li 'stats' is a valid isc_stats_t. + */ + +void +isc_stats_set(isc_stats_t *stats, isc_uint64_t val, + isc_statscounter_t counter); +/*%< + * Set the given counter to the specfied value. + * + * Requires: + *\li 'stats' is a valid isc_stats_t. + */ + ISC_LANG_ENDDECLS #endif /* ISC_STATS_H */ diff --git a/lib/isc/include/isc/types.h b/lib/isc/include/isc/types.h index 8dbf67ed10..f2fe757b40 100644 --- a/lib/isc/include/isc/types.h +++ b/lib/isc/include/isc/types.h @@ -126,4 +126,10 @@ typedef enum { isc_resource_stacksize } isc_resource_t; +/*% Statistics formats (text file or XML) */ +typedef enum { + isc_statsformat_file, + isc_statsformat_xml +} isc_statsformat_t; + #endif /* ISC_TYPES_H */ diff --git a/lib/isc/mem.c b/lib/isc/mem.c index 5b4b16c570..fd9c3f94dd 100644 --- a/lib/isc/mem.c +++ b/lib/isc/mem.c @@ -270,6 +270,10 @@ ISC_MEMFUNC_SCOPE size_t isc__mem_getquota(isc_mem_t *ctx); ISC_MEMFUNC_SCOPE size_t isc__mem_inuse(isc_mem_t *ctx); +ISC_MEMFUNC_SCOPE size_t +isc__mem_maxinuse(isc_mem_t *ctx); +ISC_MEMFUNC_SCOPE size_t +isc__mem_total(isc_mem_t *ctx); ISC_MEMFUNC_SCOPE isc_boolean_t isc__mem_isovermem(isc_mem_t *ctx); ISC_MEMFUNC_SCOPE void @@ -348,6 +352,8 @@ static struct isc__memmethods { isc__mem_setwater, isc__mem_waterack, isc__mem_inuse, + isc__mem_maxinuse, + isc__mem_total, isc__mem_isovermem, isc__mempool_create } @@ -1737,6 +1743,36 @@ isc__mem_inuse(isc_mem_t *ctx0) { return (inuse); } +ISC_MEMFUNC_SCOPE size_t +isc__mem_maxinuse(isc_mem_t *ctx0) { + isc__mem_t *ctx = (isc__mem_t *)ctx0; + size_t maxinuse; + + REQUIRE(VALID_CONTEXT(ctx)); + MCTXLOCK(ctx, &ctx->lock); + + maxinuse = ctx->maxinuse; + + MCTXUNLOCK(ctx, &ctx->lock); + + return (maxinuse); +} + +ISC_MEMFUNC_SCOPE size_t +isc__mem_total(isc_mem_t *ctx0) { + isc__mem_t *ctx = (isc__mem_t *)ctx0; + size_t total; + + REQUIRE(VALID_CONTEXT(ctx)); + MCTXLOCK(ctx, &ctx->lock); + + total = ctx->total; + + MCTXUNLOCK(ctx, &ctx->lock); + + return (total); +} + ISC_MEMFUNC_SCOPE void isc__mem_setwater(isc_mem_t *ctx0, isc_mem_water_t water, void *water_arg, size_t hiwater, size_t lowater) diff --git a/lib/isc/mem_api.c b/lib/isc/mem_api.c index 85abb9b450..3eeebf13de 100644 --- a/lib/isc/mem_api.c +++ b/lib/isc/mem_api.c @@ -206,6 +206,20 @@ isc_mem_isovermem(isc_mem_t *mctx) { return (mctx->methods->isovermem(mctx)); } +size_t +isc_mem_maxinuse(isc_mem_t *mctx) { + REQUIRE(ISCAPI_MCTX_VALID(mctx)); + + return (mctx->methods->maxinuse(mctx)); +} + +size_t +isc_mem_total(isc_mem_t *mctx) { + REQUIRE(ISCAPI_MCTX_VALID(mctx)); + + return (mctx->methods->total(mctx)); +} + void isc_mem_setname(isc_mem_t *mctx, const char *name, void *tag) { REQUIRE(ISCAPI_MCTX_VALID(mctx)); diff --git a/lib/isc/stats.c b/lib/isc/stats.c index 8b624b2d47..a2b2a662e8 100644 --- a/lib/isc/stats.c +++ b/lib/isc/stats.c @@ -324,3 +324,31 @@ isc_stats_dump(isc_stats_t *stats, isc_stats_dumper_t dump_fn, dump_fn((isc_statscounter_t)i, stats->copiedcounters[i], arg); } } + +void +isc_stats_set(isc_stats_t *stats, isc_uint64_t val, + isc_statscounter_t counter) +{ + REQUIRE(ISC_STATS_VALID(stats)); + REQUIRE(counter < stats->ncounters); + +#ifdef ISC_RWLOCK_USEATOMIC + /* + * We use a "write" lock before "reading" the statistics counters as + * an exclusive lock. + */ + isc_rwlock_lock(&stats->counterlock, isc_rwlocktype_write); +#endif + +#if ISC_STATS_USEMULTIFIELDS + stats->counters[counter].hi = (val >> 32) & 0xffffffff; + stats->counters[counter].lo = val & 0xffffffff; +#else + stats->counters[counter] = val; +#endif + +#ifdef ISC_RWLOCK_USEATOMIC + isc_rwlock_unlock(&stats->counterlock, isc_rwlocktype_write); +#endif +} + diff --git a/lib/isc/task.c b/lib/isc/task.c index 227b29596c..5a6455de55 100644 --- a/lib/isc/task.c +++ b/lib/isc/task.c @@ -110,6 +110,7 @@ struct isc__task { unsigned int references; isc_eventlist_t events; isc_eventlist_t on_shutdown; + unsigned int nevents; unsigned int quantum; unsigned int flags; isc_stdtime_t now; @@ -153,6 +154,7 @@ struct isc__taskmgr { isc_condition_t paused; #endif /* ISC_PLATFORM_USETHREADS */ unsigned int tasks_running; + unsigned int tasks_ready; isc_boolean_t pause_requested; isc_boolean_t exclusive_requested; isc_boolean_t exiting; @@ -298,6 +300,7 @@ task_finished(isc__task_t *task) { isc__taskmgr_t *manager = task->manager; REQUIRE(EMPTY(task->events)); + REQUIRE(task->nevents == 0); REQUIRE(EMPTY(task->on_shutdown)); REQUIRE(task->references == 0); REQUIRE(task->state == task_state_done); @@ -351,6 +354,7 @@ isc__task_create(isc_taskmgr_t *manager0, unsigned int quantum, task->references = 1; INIT_LIST(task->events); INIT_LIST(task->on_shutdown); + task->nevents = 0; task->quantum = quantum; task->flags = 0; task->now = 0; @@ -436,6 +440,7 @@ task_shutdown(isc__task_t *task) { prev = PREV(event, ev_link); DEQUEUE(task->on_shutdown, event, ev_link); ENQUEUE(task->events, event, ev_link); + task->nevents++; } } @@ -547,6 +552,7 @@ task_send(isc__task_t *task, isc_event_t **eventp) { INSIST(task->state == task_state_ready || task->state == task_state_running); ENQUEUE(task->events, event, ev_link); + task->nevents++; *eventp = NULL; return (was_idle); @@ -660,6 +666,7 @@ dequeue_events(isc__task_t *task, void *sender, isc_eventtype_t first, (tag == NULL || event->ev_tag == tag) && (!purging || PURGE_OK(event))) { DEQUEUE(task->events, event, ev_link); + task->nevents--; ENQUEUE(*events, event, ev_link); count++; } @@ -745,6 +752,7 @@ isc__task_purgeevent(isc_task_t *task0, isc_event_t *event) { next_event = NEXT(curr_event, ev_link); if (curr_event == event && PURGE_OK(event)) { DEQUEUE(task->events, curr_event, ev_link); + task->nevents--; break; } } @@ -968,6 +976,7 @@ push_readyq(isc__taskmgr_t *manager, isc__task_t *task) { if ((task->flags & TASK_F_PRIVILEGED) != 0) ENQUEUE(manager->ready_priority_tasks, task, ready_priority_link); + manager->tasks_ready++; } static void @@ -977,6 +986,7 @@ dispatch(isc__taskmgr_t *manager) { unsigned int total_dispatch_count = 0; isc__tasklist_t new_ready_tasks; isc__tasklist_t new_priority_tasks; + unsigned int tasks_ready = 0; #endif /* USE_WORKER_THREADS */ REQUIRE(VALID_MANAGER(manager)); @@ -1083,6 +1093,7 @@ dispatch(isc__taskmgr_t *manager) { * have a task to do. We must reacquire the manager * lock before exiting the 'if (task != NULL)' block. */ + manager->tasks_ready--; manager->tasks_running++; UNLOCK(&manager->lock); @@ -1096,6 +1107,7 @@ dispatch(isc__taskmgr_t *manager) { if (!EMPTY(task->events)) { event = HEAD(task->events); DEQUEUE(task->events, event, ev_link); + task->nevents--; /* * Execute the event action. @@ -1235,6 +1247,7 @@ dispatch(isc__taskmgr_t *manager) { if ((task->flags & TASK_F_PRIVILEGED) != 0) ENQUEUE(new_priority_tasks, task, ready_priority_link); + tasks_ready++; #endif } } @@ -1258,6 +1271,7 @@ dispatch(isc__taskmgr_t *manager) { ISC_LIST_APPENDLIST(manager->ready_tasks, new_ready_tasks, ready_link); ISC_LIST_APPENDLIST(manager->ready_priority_tasks, new_priority_tasks, ready_priority_link); + manager->tasks_ready += tasks_ready; if (empty_readyq(manager)) manager->mode = isc_taskmgrmode_normal; #endif @@ -1393,6 +1407,7 @@ isc__taskmgr_create(isc_mem_t *mctx, unsigned int workers, INIT_LIST(manager->ready_tasks); INIT_LIST(manager->ready_priority_tasks); manager->tasks_running = 0; + manager->tasks_ready = 0; manager->exclusive_requested = ISC_FALSE; manager->pause_requested = ISC_FALSE; manager->exiting = ISC_FALSE; @@ -1761,6 +1776,10 @@ isc_taskmgr_renderxml(isc_taskmgr_t *mgr0, xmlTextWriterPtr writer) { xmlTextWriterWriteFormatString(writer, "%d", mgr->tasks_running); xmlTextWriterEndElement(writer); /* tasks-running */ + xmlTextWriterStartElement(writer, ISC_XMLCHAR "tasks-ready"); + xmlTextWriterWriteFormatString(writer, "%d", mgr->tasks_ready); + xmlTextWriterEndElement(writer); /* tasks-ready */ + xmlTextWriterEndElement(writer); /* thread-model */ xmlTextWriterStartElement(writer, ISC_XMLCHAR "tasks"); @@ -1793,6 +1812,10 @@ isc_taskmgr_renderxml(isc_taskmgr_t *mgr0, xmlTextWriterPtr writer) { xmlTextWriterWriteFormatString(writer, "%d", task->quantum); xmlTextWriterEndElement(writer); /* quantum */ + xmlTextWriterStartElement(writer, ISC_XMLCHAR "events"); + xmlTextWriterWriteFormatString(writer, "%d", task->nevents); + xmlTextWriterEndElement(writer); /* events */ + xmlTextWriterEndElement(writer); UNLOCK(&task->lock); diff --git a/lib/isc/unix/socket.c b/lib/isc/unix/socket.c index 057aa1e81d..9478340616 100644 --- a/lib/isc/unix/socket.c +++ b/lib/isc/unix/socket.c @@ -624,7 +624,8 @@ enum { STATID_ACCEPTFAIL = 6, STATID_ACCEPT = 7, STATID_SENDFAIL = 8, - STATID_RECVFAIL = 9 + STATID_RECVFAIL = 9, + STATID_ACTIVE = 10 }; static const isc_statscounter_t upd4statsindex[] = { isc_sockstatscounter_udp4open, @@ -636,7 +637,8 @@ static const isc_statscounter_t upd4statsindex[] = { -1, -1, isc_sockstatscounter_udp4sendfail, - isc_sockstatscounter_udp4recvfail + isc_sockstatscounter_udp4recvfail, + isc_sockstatscounter_udp4active }; static const isc_statscounter_t upd6statsindex[] = { isc_sockstatscounter_udp6open, @@ -648,7 +650,8 @@ static const isc_statscounter_t upd6statsindex[] = { -1, -1, isc_sockstatscounter_udp6sendfail, - isc_sockstatscounter_udp6recvfail + isc_sockstatscounter_udp6recvfail, + isc_sockstatscounter_udp6active }; static const isc_statscounter_t tcp4statsindex[] = { isc_sockstatscounter_tcp4open, @@ -660,7 +663,8 @@ static const isc_statscounter_t tcp4statsindex[] = { isc_sockstatscounter_tcp4acceptfail, isc_sockstatscounter_tcp4accept, isc_sockstatscounter_tcp4sendfail, - isc_sockstatscounter_tcp4recvfail + isc_sockstatscounter_tcp4recvfail, + isc_sockstatscounter_tcp4active }; static const isc_statscounter_t tcp6statsindex[] = { isc_sockstatscounter_tcp6open, @@ -672,7 +676,8 @@ static const isc_statscounter_t tcp6statsindex[] = { isc_sockstatscounter_tcp6acceptfail, isc_sockstatscounter_tcp6accept, isc_sockstatscounter_tcp6sendfail, - isc_sockstatscounter_tcp6recvfail + isc_sockstatscounter_tcp6recvfail, + isc_sockstatscounter_tcp6active }; static const isc_statscounter_t unixstatsindex[] = { isc_sockstatscounter_unixopen, @@ -684,7 +689,8 @@ static const isc_statscounter_t unixstatsindex[] = { isc_sockstatscounter_unixacceptfail, isc_sockstatscounter_unixaccept, isc_sockstatscounter_unixsendfail, - isc_sockstatscounter_unixrecvfail + isc_sockstatscounter_unixrecvfail, + isc_sockstatscounter_unixactive }; static const isc_statscounter_t fdwatchstatsindex[] = { -1, @@ -696,7 +702,8 @@ static const isc_statscounter_t fdwatchstatsindex[] = { -1, -1, isc_sockstatscounter_fdwatchsendfail, - isc_sockstatscounter_fdwatchrecvfail + isc_sockstatscounter_fdwatchrecvfail, + -1 }; #if defined(USE_KQUEUE) || defined(USE_EPOLL) || defined(USE_DEVPOLL) || \ @@ -803,6 +810,17 @@ inc_stats(isc_stats_t *stats, isc_statscounter_t counterid) { isc_stats_increment(stats, counterid); } +/*% + * Decrement socket-related statistics counters. + */ +static inline void +dec_stats(isc_stats_t *stats, isc_statscounter_t counterid) { + REQUIRE(counterid != -1); + + if (stats != NULL) + isc_stats_decrement(stats, counterid); +} + static inline isc_result_t watch_fd(isc__socketmgr_t *manager, int fd, int msg) { isc_result_t result = ISC_R_SUCCESS; @@ -1970,6 +1988,7 @@ closesocket(isc__socketmgr_t *manager, isc__socket_t *sock, int fd) { select_poke(manager, fd, SELECT_POKE_CLOSE); inc_stats(manager->stats, sock->statsindex[STATID_CLOSE]); + dec_stats(manager->stats, sock->statsindex[STATID_ACTIVE]); /* * update manager->maxfd here (XXX: this should be implemented more @@ -1997,6 +2016,7 @@ closesocket(isc__socketmgr_t *manager, isc__socket_t *sock, int fd) { manager->maxfd = manager->pipe_fds[0]; #endif } + UNLOCK(&manager->lock); #endif /* USE_SELECT */ } @@ -2313,6 +2333,7 @@ opensocket(isc__socketmgr_t *manager, isc__socket_t *sock, ISC_MSG_TOOMANYFDS, "socket: file descriptor exceeds limit (%d/%u)", sock->fd, manager->maxsocks); + inc_stats(manager->stats, sock->statsindex[STATID_OPENFAIL]); return (ISC_R_NORESOURCES); } @@ -2328,6 +2349,8 @@ opensocket(isc__socketmgr_t *manager, isc__socket_t *sock, "%s: %s", err, strbuf); /* fallthrough */ case ENOBUFS: + inc_stats(manager->stats, + sock->statsindex[STATID_OPENFAIL]); return (ISC_R_NORESOURCES); case EPROTONOSUPPORT: @@ -2338,6 +2361,8 @@ opensocket(isc__socketmgr_t *manager, isc__socket_t *sock, * EAFNOSUPPORT. */ case EINVAL: + inc_stats(manager->stats, + sock->statsindex[STATID_OPENFAIL]); return (ISC_R_FAMILYNOSUPPORT); default: @@ -2349,6 +2374,8 @@ opensocket(isc__socketmgr_t *manager, isc__socket_t *sock, ISC_MSG_FAILED, "failed"), strbuf); + inc_stats(manager->stats, + sock->statsindex[STATID_OPENFAIL]); return (ISC_R_UNEXPECTED); } } @@ -2359,6 +2386,7 @@ opensocket(isc__socketmgr_t *manager, isc__socket_t *sock, result = make_nonblock(sock->fd); if (result != ISC_R_SUCCESS) { (void)close(sock->fd); + inc_stats(manager->stats, sock->statsindex[STATID_OPENFAIL]); return (result); } @@ -2543,7 +2571,7 @@ opensocket(isc__socketmgr_t *manager, isc__socket_t *sock, setup_done: inc_stats(manager->stats, sock->statsindex[STATID_OPEN]); - + inc_stats(manager->stats, sock->statsindex[STATID_ACTIVE]); return (ISC_R_SUCCESS); } @@ -2590,7 +2618,6 @@ socket_create(isc_socketmgr_t *manager0, int pf, isc_sockettype_t type, result = opensocket(manager, sock, (isc__socket_t *)dup_socket); if (result != ISC_R_SUCCESS) { - inc_stats(manager->stats, sock->statsindex[STATID_OPENFAIL]); free_socket(&sock); return (result); } @@ -3298,6 +3325,7 @@ internal_accept(isc_task_t *me, isc_event_t *ev) { UNLOCK(&manager->lock); inc_stats(manager->stats, sock->statsindex[STATID_ACCEPT]); + inc_stats(manager->stats, sock->statsindex[STATID_ACTIVE]); } else { inc_stats(manager->stats, sock->statsindex[STATID_ACCEPTFAIL]); NEWCONNSOCK(dev)->references--;