diff --git a/bin/delv/delv.c b/bin/delv/delv.c index 6ddef282d0..6e2370e060 100644 --- a/bin/delv/delv.c +++ b/bin/delv/delv.c @@ -98,7 +98,7 @@ static dns_dispatch_t *dispatch4 = NULL; static dns_dispatch_t *dispatch6 = NULL; static dns_db_t *roothints = NULL; static isc_stats_t *resstats = NULL; -static dns_stats_t *resquerystats = NULL; +static isc_statsmulti_t *resquerystats = NULL; static FILE *logfp = NULL; /* Managers */ @@ -2177,7 +2177,7 @@ run_server(void *arg) { dns_rdatatypestats_create(isc_g_mctx, &resquerystats); dns_resolver_setquerystats(view->resolver, resquerystats); - dns_stats_detach(&resquerystats); + isc_statsmulti_detach(&resquerystats); dns_view_freeze(view); diff --git a/bin/named/server.c b/bin/named/server.c index 70efe66b08..4b9138453d 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -3635,7 +3635,7 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config, bool empty_zones_enable; const cfg_obj_t *disablelist = NULL; isc_stats_t *resstats = NULL; - dns_stats_t *resquerystats = NULL; + isc_statsmulti_t *resquerystats = NULL; isc_histomulti_t *resqueryinrttstats = NULL; isc_histomulti_t *resqueryoutrttstats = NULL; bool auto_root = false; @@ -5465,7 +5465,7 @@ cleanup: isc_stats_detach(&resstats); } if (resquerystats != NULL) { - dns_stats_detach(&resquerystats); + isc_statsmulti_detach(&resquerystats); } if (resqueryinrttstats != NULL) { isc_histomulti_detach(&resqueryinrttstats); @@ -10054,12 +10054,12 @@ named_server_resetstatscommand(named_server_t *server, isc_lex_t *lex, } if (recursive_high_water) { - isc_stats_set(ns_stats_get(server->sctx->nsstats), 0, - ns_statscounter_recurshighwater); + ns_stats_reset_highwater(server->sctx->nshighwaterstats, + ns_highwater_recursive); } if (tcp_high_water) { - isc_stats_set(ns_stats_get(server->sctx->nsstats), 0, - ns_statscounter_tcphighwater); + ns_stats_reset_highwater(server->sctx->nshighwaterstats, + ns_highwater_tcp); } return ISC_R_SUCCESS; @@ -11539,9 +11539,9 @@ named_server_status(named_server_t *server, isc_buffer_t *text) { CHECK(putstr(text, line)); snprintf(line, sizeof(line), "recursive high-water: %u\n", - (unsigned int)ns_stats_get_counter( - server->sctx->nsstats, - ns_statscounter_recurshighwater)); + (unsigned int)ns_stats_get_highwater( + server->sctx->nshighwaterstats, + ns_highwater_recursive)); CHECK(putstr(text, line)); snprintf(line, sizeof(line), "tcp clients: %u/%u\n", @@ -11550,8 +11550,8 @@ named_server_status(named_server_t *server, isc_buffer_t *text) { CHECK(putstr(text, line)); snprintf(line, sizeof(line), "TCP high-water: %u\n", - (unsigned int)ns_stats_get_counter( - server->sctx->nsstats, ns_statscounter_tcphighwater)); + (unsigned int)ns_stats_get_highwater( + server->sctx->nshighwaterstats, ns_highwater_tcp)); CHECK(putstr(text, line)); reload_status = atomic_load(&server->reload_status); diff --git a/bin/named/statschannel.c b/bin/named/statschannel.c index 56b473cf3d..17b33d7cf8 100644 --- a/bin/named/statschannel.c +++ b/bin/named/statschannel.c @@ -140,6 +140,7 @@ user_zonetype(dns_zone_t *zone) { * below so that they'll be less susceptible to counter name changes. */ static const char *nsstats_desc[ns_statscounter_max]; +static const char *nshighwaterstats_desc[ns_highwater_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]; @@ -153,6 +154,7 @@ static const char *dnstapstats_desc[dns_dnstapcounter_max]; static const char *gluecachestats_desc[dns_gluecachestatscounter_max]; #if defined(EXTENDED_STATS) static const char *nsstats_xmldesc[ns_statscounter_max]; +static const char *nshighwaterstats_xmldesc[ns_highwater_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]; @@ -167,18 +169,19 @@ static const char *gluecachestats_xmldesc[dns_gluecachestatscounter_max]; static const char *queryrttinstats_xmldesc[dns_queryrttcounter_in_max]; static const char *queryrttoutstats_xmldesc[dns_queryrttcounter_in_max]; #else /* if defined(EXTENDED_STATS) */ -#define nsstats_xmldesc NULL -#define resstats_xmldesc NULL -#define adbstats_xmldesc NULL -#define zonestats_xmldesc NULL -#define sockstats_xmldesc NULL -#define dnssecstats_xmldesc NULL -#define udpinsizestats_xmldesc NULL -#define udpoutsizestats_xmldesc NULL -#define tcpinsizestats_xmldesc NULL -#define tcpoutsizestats_xmldesc NULL -#define dnstapstats_xmldesc NULL -#define gluecachestats_xmldesc NULL +#define nsstats_xmldesc NULL +#define nshighwaterstats_xmldesc NULL +#define resstats_xmldesc NULL +#define adbstats_xmldesc NULL +#define zonestats_xmldesc NULL +#define sockstats_xmldesc NULL +#define dnssecstats_xmldesc NULL +#define udpinsizestats_xmldesc NULL +#define udpoutsizestats_xmldesc NULL +#define tcpinsizestats_xmldesc NULL +#define tcpoutsizestats_xmldesc NULL +#define dnstapstats_xmldesc NULL +#define gluecachestats_xmldesc NULL #endif /* EXTENDED_STATS */ #define TRY0(a) \ @@ -194,6 +197,7 @@ static const char *queryrttoutstats_xmldesc[dns_queryrttcounter_in_max]; * nsstats_desc[nsstats_index[0]] will be the description that is shown first. */ static int nsstats_index[ns_statscounter_max]; +static int nshighwaterstats_index[ns_highwater_max]; static int resstats_index[dns_resstatscounter_max]; static int adbstats_index[dns_adbstats_max]; static int zonestats_index[dns_zonestatscounter_max]; @@ -328,8 +332,6 @@ init_desc(void) { SET_NSSTATDESC(invalidsig, "requests with invalid signature", "ReqBadSIG"); SET_NSSTATDESC(requesttcp, "TCP requests received", "ReqTCP"); - SET_NSSTATDESC(tcphighwater, "TCP connection high-water", - "TCPConnHighWater"); SET_NSSTATDESC(authrej, "auth queries rejected", "AuthQryRej"); SET_NSSTATDESC(recurserej, "recursive queries rejected", "RecQryRej"); SET_NSSTATDESC(xfrrej, "transfer requests rejected", "XfrRej"); @@ -368,8 +370,6 @@ init_desc(void) { SET_NSSTATDESC(updatebadprereq, "updates rejected due to prerequisite failure", "UpdateBadPrereq"); - SET_NSSTATDESC(recurshighwater, "Recursive clients high-water", - "RecursHighwater"); SET_NSSTATDESC(recursclients, "recursing clients", "RecursClients"); SET_NSSTATDESC(dns64, "queries answered by DNS64", "DNS64"); SET_NSSTATDESC(ratedropped, "responses dropped for rate limits", @@ -440,6 +440,32 @@ init_desc(void) { INSIST(i == ns_statscounter_max); + /* Initialize highwater statistics */ + for (i = 0; i < ns_highwater_max; i++) { + nshighwaterstats_desc[i] = NULL; + } +#if defined(EXTENDED_STATS) + for (i = 0; i < ns_highwater_max; i++) { + nshighwaterstats_xmldesc[i] = NULL; + } +#endif /* if defined(EXTENDED_STATS) */ + +#define SET_NSHIGHWATERSTATDESC(counterid, desc, xmldesc) \ + do { \ + set_desc(ns_highwater_##counterid, ns_highwater_max, desc, \ + nshighwaterstats_desc, xmldesc, \ + nshighwaterstats_xmldesc); \ + nshighwaterstats_index[i++] = ns_highwater_##counterid; \ + } while (0) + + i = 0; + SET_NSHIGHWATERSTATDESC(tcp, "TCP connection high-water", + "TCPConnHighWater"); + SET_NSHIGHWATERSTATDESC(recursive, "Recursive clients high-water", + "RecursHighwater"); + + INSIST(i == ns_highwater_max); + /* Initialize resolver statistics */ for (i = 0; i < dns_resstatscounter_max; i++) { resstats_desc[i] = NULL; @@ -738,6 +764,9 @@ init_desc(void) { for (i = 0; i < ns_statscounter_max; i++) { INSIST(nsstats_desc[i] != NULL); } + for (i = 0; i < ns_highwater_max; i++) { + INSIST(nshighwaterstats_desc[i] != NULL); + } for (i = 0; i < dns_resstatscounter_max; i++) { INSIST(resstats_desc[i] != NULL); } @@ -871,6 +900,25 @@ dump_stats(isc_stats_t *stats, isc_statsformat_t type, void *arg, values, options); } +static isc_result_t +dump_statsmulti(isc_statsmulti_t *stats, isc_statsformat_t type, void *arg, + const char *category, const char **desc, int ncounters, + int *indices, uint64_t *values, int options) { + stats_dumparg_t dumparg; + unsigned int multioptions = 0; + + dumparg.type = type; + dumparg.ncounters = ncounters; + dumparg.counterindices = indices; + dumparg.countervalues = values; + + memset(values, 0, sizeof(values[0]) * ncounters); + isc_statsmulti_dump(stats, generalstat_dump, &dumparg, multioptions); + + return dump_counters(type, arg, category, desc, ncounters, indices, + values, options); +} + #if defined(EXTENDED_STATS) static isc_result_t dump_histo(isc_histomulti_t *hm, isc_statsformat_t type, void *arg, @@ -1416,7 +1464,7 @@ zone_xmlrender(dns_zone_t *zone, void *arg) { if (statlevel == dns_zonestat_full) { isc_stats_t *zonestats; isc_stats_t *gluecachestats; - dns_stats_t *rcvquerystats; + isc_statsmulti_t *rcvquerystats; dns_stats_t *dnssecsignstats; uint64_t nsstat_values[ns_statscounter_max]; uint64_t gluecachestats_values[dns_gluecachestatscounter_max]; @@ -1901,10 +1949,18 @@ generatexml(named_server_t *server, uint32_t flags, int *buflen, TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type", ISC_XMLCHAR "nsstat")); - CHECK(dump_stats(ns_stats_get(server->sctx->nsstats), + CHECK(dump_statsmulti(server->sctx->nsstats, + isc_statsformat_xml, writer, NULL, + nsstats_xmldesc, ns_statscounter_max, + nsstats_index, nsstat_values, + ISC_STATSMULTIDUMP_VERBOSE)); + + /* Add highwater stats to the same nsstat section */ + uint64_t nshighwaterstat_values[ns_highwater_max]; + CHECK(dump_stats(server->sctx->nshighwaterstats, isc_statsformat_xml, writer, NULL, - nsstats_xmldesc, ns_statscounter_max, - nsstats_index, nsstat_values, + nshighwaterstats_xmldesc, ns_highwater_max, + nshighwaterstats_index, nshighwaterstat_values, ISC_STATSDUMP_VERBOSE)); TRY0(xmlTextWriterEndElement(writer)); /* /nsstat */ @@ -2086,7 +2142,7 @@ generatexml(named_server_t *server, uint32_t flags, int *buflen, STATS_XML_XFRINS)) != 0)) { isc_stats_t *istats = NULL; - dns_stats_t *dstats = NULL; + isc_statsmulti_t *dstats = NULL; dns_adb_t *adb = NULL; isc_histomulti_t *hmpin = NULL, *hmpout = NULL; @@ -2127,7 +2183,7 @@ generatexml(named_server_t *server, uint32_t flags, int *buflen, &dumparg, 0); CHECK(dumparg.result); } - dns_stats_detach(&dstats); + isc_statsmulti_detach(&dstats); TRY0(xmlTextWriterEndElement(writer)); /* */ @@ -2492,7 +2548,7 @@ zone_jsonrender(dns_zone_t *zone, void *arg) { if (statlevel == dns_zonestat_full) { isc_stats_t *zonestats; isc_stats_t *gluecachestats; - dns_stats_t *rcvquerystats; + isc_statsmulti_t *rcvquerystats; dns_stats_t *dnssecsignstats; uint64_t nsstat_values[ns_statscounter_max]; uint64_t gluecachestats_values[dns_gluecachestatscounter_max]; @@ -3027,10 +3083,22 @@ generatejson(named_server_t *server, size_t *msglen, const char **msg, dumparg.result = ISC_R_SUCCESS; dumparg.arg = counters; - result = dump_stats(ns_stats_get(server->sctx->nsstats), + result = dump_statsmulti(server->sctx->nsstats, + isc_statsformat_json, counters, NULL, + nsstats_xmldesc, ns_statscounter_max, + nsstats_index, nsstat_values, 0); + if (result != ISC_R_SUCCESS) { + json_object_put(counters); + goto cleanup; + } + + /* Add highwater stats to the same nsstats section */ + uint64_t nshighwaterstat_values[ns_highwater_max]; + result = dump_stats(server->sctx->nshighwaterstats, isc_statsformat_json, counters, NULL, - nsstats_xmldesc, ns_statscounter_max, - nsstats_index, nsstat_values, 0); + nshighwaterstats_xmldesc, ns_highwater_max, + nshighwaterstats_index, + nshighwaterstat_values, 0); if (result != ISC_R_SUCCESS) { json_object_put(counters); goto cleanup; @@ -3160,7 +3228,7 @@ generatejson(named_server_t *server, size_t *msglen, const char **msg, if ((flags & STATS_JSON_SERVER) != 0) { json_object *res = NULL; - dns_stats_t *dstats = NULL; + isc_statsmulti_t *dstats = NULL; isc_stats_t *istats = NULL; res = json_object_new_object(); @@ -3209,18 +3277,19 @@ generatejson(named_server_t *server, size_t *msglen, const char **msg, json_object_object_add(res, "qtypes", counters); - dns_stats_detach(&dstats); + isc_statsmulti_detach(&dstats); } - dstats = dns_db_getrrsetstats(view->cachedb); - if (dstats != NULL) { + dns_stats_t *rrsetstats = + dns_db_getrrsetstats(view->cachedb); + if (rrsetstats != NULL) { counters = json_object_new_object(); CHECKMEM(counters); dumparg.arg = counters; dumparg.result = ISC_R_SUCCESS; dns_rdatasetstats_dump( - dstats, rdatasetstats_dump, + rrsetstats, rdatasetstats_dump, &dumparg, 0); if (dumparg.result != ISC_R_SUCCESS) { json_object_put(counters); @@ -4099,7 +4168,7 @@ named_stats_dump(named_server_t *server, FILE *fp) { fprintf(fp, "++ Outgoing Queries ++\n"); ISC_LIST_FOREACH(server->viewlist, view, link) { - dns_stats_t *dstats = NULL; + isc_statsmulti_t *dstats = NULL; dns_resolver_getquerystats(view->resolver, &dstats); if (dstats == NULL) { continue; @@ -4110,13 +4179,19 @@ named_stats_dump(named_server_t *server, FILE *fp) { fprintf(fp, "[View: %s]\n", view->name); } dns_rdatatypestats_dump(dstats, rdtypestat_dump, &dumparg, 0); - dns_stats_detach(&dstats); + isc_statsmulti_detach(&dstats); } fprintf(fp, "++ Name Server Statistics ++\n"); - (void)dump_stats(ns_stats_get(server->sctx->nsstats), - isc_statsformat_file, fp, NULL, nsstats_desc, - ns_statscounter_max, nsstats_index, nsstat_values, 0); + (void)dump_statsmulti(server->sctx->nsstats, isc_statsformat_file, fp, + NULL, nsstats_desc, ns_statscounter_max, + nsstats_index, nsstat_values, 0); + + /* Add highwater stats to the same Name Server Statistics section */ + uint64_t nshighwaterstat_values[ns_highwater_max]; + (void)dump_stats(server->sctx->nshighwaterstats, isc_statsformat_file, + fp, NULL, nshighwaterstats_desc, ns_highwater_max, + nshighwaterstats_index, nshighwaterstat_values, 0); fprintf(fp, "++ Zone Maintenance Statistics ++\n"); (void)dump_stats(server->zonestats, isc_statsformat_file, fp, NULL, diff --git a/bin/named/zoneconf.c b/bin/named/zoneconf.c index 0e422d33ed..515e184913 100644 --- a/bin/named/zoneconf.c +++ b/bin/named/zoneconf.c @@ -989,7 +989,7 @@ named_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig, dns_masterformat_t masterformat; const dns_master_style_t *masterstyle = &dns_master_style_default; isc_stats_t *zoneqrystats; - dns_stats_t *rcvquerystats; + isc_statsmulti_t *rcvquerystats; dns_stats_t *dnssecsignstats; dns_zonestat_level_t statlevel = dns_zonestat_none; dns_ttl_t maxttl = 0; /* unlimited */ @@ -1237,7 +1237,7 @@ named_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig, } if (rcvquerystats != NULL) { - dns_stats_detach(&rcvquerystats); + isc_statsmulti_detach(&rcvquerystats); } if (dnssecsignstats != NULL) { diff --git a/lib/dns/include/dns/resolver.h b/lib/dns/include/dns/resolver.h index 6ec13fc631..fc73fca716 100644 --- a/lib/dns/include/dns/resolver.h +++ b/lib/dns/include/dns/resolver.h @@ -53,6 +53,7 @@ #include #include #include +#include #include #include @@ -599,7 +600,7 @@ dns_resolver_incstats(dns_resolver_t *res, isc_statscounter_t counter); */ void -dns_resolver_setquerystats(dns_resolver_t *res, dns_stats_t *stats); +dns_resolver_setquerystats(dns_resolver_t *res, isc_statsmulti_t *stats); /*%< * Set a statistics counter set of rdata type, 'stats', for 'res'. Once the * statistic set is installed, the resolver will count outgoing queries @@ -611,7 +612,7 @@ dns_resolver_setquerystats(dns_resolver_t *res, dns_stats_t *stats); */ void -dns_resolver_getquerystats(dns_resolver_t *res, dns_stats_t **statsp); +dns_resolver_getquerystats(dns_resolver_t *res, isc_statsmulti_t **statsp); /*%< * Get the rdatatype statistics counter set for 'res'. If a statistics set is * set '*statsp' will be attached to the set; otherwise, '*statsp' will be diff --git a/lib/dns/include/dns/stats.h b/lib/dns/include/dns/stats.h index 0bbdde4638..ed0e987898 100644 --- a/lib/dns/include/dns/stats.h +++ b/lib/dns/include/dns/stats.h @@ -18,6 +18,7 @@ #include #include +#include #include #include @@ -285,7 +286,7 @@ dns_generalstats_create(isc_mem_t *mctx, dns_stats_t **statsp, int ncounters); */ void -dns_rdatatypestats_create(isc_mem_t *mctx, dns_stats_t **statsp); +dns_rdatatypestats_create(isc_mem_t *mctx, isc_statsmulti_t **statsp); /*%< * Create a statistics counter structure per rdatatype. * @@ -307,7 +308,7 @@ dns_rdatasetstats_create(isc_mem_t *mctx, dns_stats_t **statsp); */ void -dns_opcodestats_create(isc_mem_t *mctx, dns_stats_t **statsp); +dns_opcodestats_create(isc_mem_t *mctx, isc_statsmulti_t **statsp); /*%< * Create a statistics counter structure per opcode. * @@ -318,7 +319,7 @@ dns_opcodestats_create(isc_mem_t *mctx, dns_stats_t **statsp); */ void -dns_rcodestats_create(isc_mem_t *mctx, dns_stats_t **statsp); +dns_rcodestats_create(isc_mem_t *mctx, isc_statsmulti_t **statsp); /*%< * Create a statistics counter structure per assigned rcode. * @@ -373,12 +374,13 @@ dns_generalstats_increment(dns_stats_t *stats, isc_statscounter_t counter); */ void -dns_rdatatypestats_increment(dns_stats_t *stats, dns_rdatatype_t type); +dns_rdatatypestats_increment(isc_statsmulti_t *stats, dns_rdatatype_t type); /*%< * Increment the statistics counter for 'type'. * * Requires: - *\li 'stats' is a valid dns_stats_t created by dns_rdatatypestats_create(). + *\li 'stats' is a valid isc_statsmulti_t created by + * dns_rdatatypestats_create(). */ void @@ -403,21 +405,21 @@ dns_rdatasetstats_decrement(dns_stats_t *stats, dns_rdatastatstype_t rrsettype); */ void -dns_opcodestats_increment(dns_stats_t *stats, dns_opcode_t code); +dns_opcodestats_increment(isc_statsmulti_t *stats, dns_opcode_t code); /*%< * Increment the statistics counter for 'code'. * * Requires: - *\li 'stats' is a valid dns_stats_t created by dns_opcodestats_create(). + *\li 'stats' is a valid isc_statsmulti_t created by dns_opcodestats_create(). */ void -dns_rcodestats_increment(dns_stats_t *stats, dns_rcode_t code); +dns_rcodestats_increment(isc_statsmulti_t *stats, dns_rcode_t code); /*%< * Increment the statistics counter for 'code'. * * Requires: - *\li 'stats' is a valid dns_stats_t created by dns_rcodestats_create(). + *\li 'stats' is a valid isc_statsmulti_t created by dns_rcodestats_create(). */ void @@ -457,8 +459,9 @@ dns_generalstats_dump(dns_stats_t *stats, dns_generalstats_dumper_t dump_fn, */ void -dns_rdatatypestats_dump(dns_stats_t *stats, dns_rdatatypestats_dumper_t dump_fn, - void *arg, unsigned int options); +dns_rdatatypestats_dump(isc_statsmulti_t *stats, + dns_rdatatypestats_dumper_t dump_fn, void *arg, + unsigned int options); /*%< * Dump the current statistics counters in a specified way. For each counter * in stats, dump_fn is called with the corresponding type in the form of @@ -467,7 +470,8 @@ dns_rdatatypestats_dump(dns_stats_t *stats, dns_rdatatypestats_dumper_t dump_fn, * the ISC_STATSDUMP_VERBOSE flag, even such counters are dumped. * * Requires: - *\li 'stats' is a valid dns_stats_t created by dns_generalstats_create(). + *\li 'stats' is a valid isc_statsmulti_t created by + * dns_rdatatypestats_create(). */ void @@ -500,7 +504,7 @@ dns_dnssecsignstats_dump(dns_stats_t *stats, dnssecsignstats_type_t operation, */ void -dns_opcodestats_dump(dns_stats_t *stats, dns_opcodestats_dumper_t dump_fn, +dns_opcodestats_dump(isc_statsmulti_t *stats, dns_opcodestats_dumper_t dump_fn, void *arg, unsigned int options); /*%< * Dump the current statistics counters in a specified way. For each counter @@ -510,11 +514,11 @@ dns_opcodestats_dump(dns_stats_t *stats, dns_opcodestats_dumper_t dump_fn, * such counters are dumped. * * Requires: - *\li 'stats' is a valid dns_stats_t created by dns_generalstats_create(). + *\li 'stats' is a valid isc_statsmulti_t created by dns_opcodestats_create(). */ void -dns_rcodestats_dump(dns_stats_t *stats, dns_rcodestats_dumper_t dump_fn, +dns_rcodestats_dump(isc_statsmulti_t *stats, dns_rcodestats_dumper_t dump_fn, void *arg, unsigned int options); /*%< * Dump the current statistics counters in a specified way. For each counter @@ -524,5 +528,5 @@ dns_rcodestats_dump(dns_stats_t *stats, dns_rcodestats_dumper_t dump_fn, * such counters are dumped. * * Requires: - *\li 'stats' is a valid dns_stats_t created by dns_generalstats_create(). + *\li 'stats' is a valid isc_statsmulti_t created by dns_rcodestats_create(). */ diff --git a/lib/dns/include/dns/zone.h b/lib/dns/include/dns/zone.h index 5964e69ead..04719e4f8e 100644 --- a/lib/dns/include/dns/zone.h +++ b/lib/dns/include/dns/zone.h @@ -25,6 +25,7 @@ #include #include +#include #include #include @@ -1966,7 +1967,7 @@ void dns_zone_setrequeststats(dns_zone_t *zone, isc_stats_t *stats); void -dns_zone_setrcvquerystats(dns_zone_t *zone, dns_stats_t *stats); +dns_zone_setrcvquerystats(dns_zone_t *zone, isc_statsmulti_t *stats); void dns_zone_setdnssecsignstats(dns_zone_t *zone, dns_stats_t *stats); @@ -1984,7 +1985,7 @@ dns_zone_setdnssecsignstats(dns_zone_t *zone, dns_stats_t *stats); isc_stats_t * dns_zone_getrequeststats(dns_zone_t *zone); -dns_stats_t * +isc_statsmulti_t * dns_zone_getrcvquerystats(dns_zone_t *zone); dns_stats_t * diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c index bf800ff067..f6e7c8055a 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -597,7 +597,7 @@ struct dns_resolver { unsigned int maxqueries; isc_result_t quotaresp[2]; isc_stats_t *stats; - dns_stats_t *querystats; + isc_statsmulti_t *querystats; isc_histomulti_t *queryinrttstats; isc_histomulti_t *queryoutrttstats; @@ -9642,7 +9642,7 @@ dns_resolver__destroy(dns_resolver_t *res) { isc_histomulti_detach(&res->queryinrttstats); } if (res->querystats != NULL) { - dns_stats_detach(&res->querystats); + isc_statsmulti_detach(&res->querystats); } if (res->stats != NULL) { isc_stats_detach(&res->stats); @@ -10866,20 +10866,20 @@ dns_resolver_incstats(dns_resolver_t *res, isc_statscounter_t counter) { } void -dns_resolver_setquerystats(dns_resolver_t *res, dns_stats_t *stats) { +dns_resolver_setquerystats(dns_resolver_t *res, isc_statsmulti_t *stats) { REQUIRE(VALID_RESOLVER(res)); REQUIRE(res->querystats == NULL); - dns_stats_attach(stats, &res->querystats); + isc_statsmulti_attach(stats, &res->querystats); } void -dns_resolver_getquerystats(dns_resolver_t *res, dns_stats_t **statsp) { +dns_resolver_getquerystats(dns_resolver_t *res, isc_statsmulti_t **statsp) { REQUIRE(VALID_RESOLVER(res)); REQUIRE(statsp != NULL && *statsp == NULL); if (res->querystats != NULL) { - dns_stats_attach(res->querystats, statsp); + isc_statsmulti_attach(res->querystats, statsp); } } diff --git a/lib/dns/stats.c b/lib/dns/stats.c index 3560312cb8..cb60fcd10f 100644 --- a/lib/dns/stats.c +++ b/lib/dns/stats.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -189,15 +190,10 @@ dns_generalstats_create(isc_mem_t *mctx, dns_stats_t **statsp, int ncounters) { } void -dns_rdatatypestats_create(isc_mem_t *mctx, dns_stats_t **statsp) { +dns_rdatatypestats_create(isc_mem_t *mctx, isc_statsmulti_t **statsp) { REQUIRE(statsp != NULL && *statsp == NULL); - /* - * Create rdtype statistics for the first 255 RRtypes, - * plus one additional for other RRtypes. - */ - create_stats(mctx, dns_statstype_rdtype, RDTYPECOUNTER_MAXTYPE + 1, - statsp); + isc_statsmulti_create(mctx, statsp, RDTYPECOUNTER_MAXTYPE + 1); } void @@ -209,18 +205,17 @@ dns_rdatasetstats_create(isc_mem_t *mctx, dns_stats_t **statsp) { } void -dns_opcodestats_create(isc_mem_t *mctx, dns_stats_t **statsp) { +dns_opcodestats_create(isc_mem_t *mctx, isc_statsmulti_t **statsp) { REQUIRE(statsp != NULL && *statsp == NULL); - create_stats(mctx, dns_statstype_opcode, 16, statsp); + isc_statsmulti_create(mctx, statsp, 16); } void -dns_rcodestats_create(isc_mem_t *mctx, dns_stats_t **statsp) { +dns_rcodestats_create(isc_mem_t *mctx, isc_statsmulti_t **statsp) { REQUIRE(statsp != NULL && *statsp == NULL); - create_stats(mctx, dns_statstype_rcode, dns_rcode_badcookie + 1, - statsp); + isc_statsmulti_create(mctx, statsp, dns_rcode_badcookie + 1); } void @@ -254,13 +249,13 @@ rdatatype2counter(dns_rdatatype_t type) { } void -dns_rdatatypestats_increment(dns_stats_t *stats, dns_rdatatype_t type) { +dns_rdatatypestats_increment(isc_statsmulti_t *stats, dns_rdatatype_t type) { isc_statscounter_t counter; - REQUIRE(DNS_STATS_VALID(stats) && stats->type == dns_statstype_rdtype); + REQUIRE(stats != NULL); counter = rdatatype2counter(type); - isc_stats_increment(stats->counters, counter); + isc_statsmulti_increment(stats, counter); } static void @@ -332,18 +327,18 @@ dns_rdatasetstats_decrement(dns_stats_t *stats, } void -dns_opcodestats_increment(dns_stats_t *stats, dns_opcode_t code) { - REQUIRE(DNS_STATS_VALID(stats) && stats->type == dns_statstype_opcode); +dns_opcodestats_increment(isc_statsmulti_t *stats, dns_opcode_t code) { + REQUIRE(stats != NULL); - isc_stats_increment(stats->counters, (isc_statscounter_t)code); + isc_statsmulti_increment(stats, (isc_statscounter_t)code); } void -dns_rcodestats_increment(dns_stats_t *stats, dns_rcode_t code) { - REQUIRE(DNS_STATS_VALID(stats) && stats->type == dns_statstype_rcode); +dns_rcodestats_increment(isc_statsmulti_t *stats, dns_rcode_t code) { + REQUIRE(stats != NULL); if (code <= dns_rcode_badcookie) { - isc_stats_increment(stats->counters, (isc_statscounter_t)code); + isc_statsmulti_increment(stats, (isc_statscounter_t)code); } } @@ -460,14 +455,15 @@ rdatatype_dumpcb(isc_statscounter_t counter, uint64_t value, void *arg) { } void -dns_rdatatypestats_dump(dns_stats_t *stats, dns_rdatatypestats_dumper_t dump_fn, - void *arg0, unsigned int options) { +dns_rdatatypestats_dump(isc_statsmulti_t *stats, + dns_rdatatypestats_dumper_t dump_fn, void *arg0, + unsigned int options) { rdatadumparg_t arg; - REQUIRE(DNS_STATS_VALID(stats) && stats->type == dns_statstype_rdtype); + REQUIRE(stats != NULL); arg.fn = dump_fn; arg.arg = arg0; - isc_stats_dump(stats->counters, rdatatype_dumpcb, &arg, options); + isc_statsmulti_dump(stats, rdatatype_dumpcb, &arg, options); } static void @@ -584,25 +580,25 @@ rcode_dumpcb(isc_statscounter_t counter, uint64_t value, void *arg) { } void -dns_opcodestats_dump(dns_stats_t *stats, dns_opcodestats_dumper_t dump_fn, +dns_opcodestats_dump(isc_statsmulti_t *stats, dns_opcodestats_dumper_t dump_fn, void *arg0, unsigned int options) { opcodedumparg_t arg; - REQUIRE(DNS_STATS_VALID(stats) && stats->type == dns_statstype_opcode); + REQUIRE(stats != NULL); arg.fn = dump_fn; arg.arg = arg0; - isc_stats_dump(stats->counters, opcode_dumpcb, &arg, options); + isc_statsmulti_dump(stats, opcode_dumpcb, &arg, options); } void -dns_rcodestats_dump(dns_stats_t *stats, dns_rcodestats_dumper_t dump_fn, +dns_rcodestats_dump(isc_statsmulti_t *stats, dns_rcodestats_dumper_t dump_fn, void *arg0, unsigned int options) { rcodedumparg_t arg; - REQUIRE(DNS_STATS_VALID(stats) && stats->type == dns_statstype_rcode); + REQUIRE(stats != NULL); arg.fn = dump_fn; arg.arg = arg0; - isc_stats_dump(stats->counters, rcode_dumpcb, &arg, options); + isc_statsmulti_dump(stats, rcode_dumpcb, &arg, options); } diff --git a/lib/dns/zone.c b/lib/dns/zone.c index 741e88a588..ea3ccb1c16 100644 --- a/lib/dns/zone.c +++ b/lib/dns/zone.c @@ -387,7 +387,7 @@ struct dns_zone { dns_zonestat_level_t statlevel; bool requeststats_on; isc_stats_t *requeststats; - dns_stats_t *rcvquerystats; + isc_statsmulti_t *rcvquerystats; dns_stats_t *dnssecsignstats; dns_isselffunc_t isself; void *isselfarg; @@ -1201,7 +1201,7 @@ dns__zone_free(dns_zone_t *zone) { isc_stats_detach(&zone->requeststats); } if (zone->rcvquerystats != NULL) { - dns_stats_detach(&zone->rcvquerystats); + isc_statsmulti_detach(&zone->rcvquerystats); } if (zone->dnssecsignstats != NULL) { dns_stats_detach(&zone->dnssecsignstats); @@ -18990,13 +18990,13 @@ dns_zone_setrequeststats(dns_zone_t *zone, isc_stats_t *stats) { } void -dns_zone_setrcvquerystats(dns_zone_t *zone, dns_stats_t *stats) { +dns_zone_setrcvquerystats(dns_zone_t *zone, isc_statsmulti_t *stats) { REQUIRE(DNS_ZONE_VALID(zone)); LOCK_ZONE(zone); if (zone->requeststats_on && stats != NULL) { if (zone->rcvquerystats == NULL) { - dns_stats_attach(stats, &zone->rcvquerystats); + isc_statsmulti_attach(stats, &zone->rcvquerystats); zone->requeststats_on = true; } } @@ -19042,7 +19042,7 @@ dns_zone_getrequeststats(dns_zone_t *zone) { * Return the received query stats bucket * see note from dns_zone_getrequeststats() */ -dns_stats_t * +isc_statsmulti_t * dns_zone_getrcvquerystats(dns_zone_t *zone) { if (zone->requeststats_on) { return zone->rcvquerystats; diff --git a/lib/isc/include/isc/statsmulti.h b/lib/isc/include/isc/statsmulti.h new file mode 100644 index 0000000000..7785662d84 --- /dev/null +++ b/lib/isc/include/isc/statsmulti.h @@ -0,0 +1,120 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#pragma once + +/*! \file isc/statsmulti.h */ + +#include + +#include + +typedef struct isc_statsmulti isc_statsmulti_t; /*%< Statistics Multi */ + +/*%< + * Flag(s) for isc_statsmulti_dump(). + */ +#define ISC_STATSMULTIDUMP_VERBOSE 0x00000001 /*%< dump 0-value counters */ + +/*%< + * Dump callback type. + */ +typedef void (*isc_statsmulti_dumper_t)(isc_statscounter_t, uint64_t, void *); + +void +isc_statsmulti_create(isc_mem_t *mctx, isc_statsmulti_t **statsp, + int ncounters); +/*%< + * Create a statistics counter structure for additive counters. + * All counters are additive (sum across threads). + * + * Requires: + *\li 'mctx' must be a valid memory context. + * + *\li 'statsp' != NULL && '*statsp' == NULL. + */ + +void +isc_statsmulti_attach(isc_statsmulti_t *stats, isc_statsmulti_t **statsp); +/*%< + * Attach to a statistics set. + * + * Requires: + *\li 'stats' is a valid isc_statsmulti_t. + * + *\li 'statsp' != NULL && '*statsp' == NULL + */ + +void +isc_statsmulti_detach(isc_statsmulti_t **statsp); +/*%< + * Detaches from the statistics set. + * + * Requires: + *\li 'statsp' != NULL and '*statsp' is a valid isc_statsmulti_t. + */ + +void +isc_statsmulti_increment(isc_statsmulti_t *stats, isc_statscounter_t counter); +/*%< + * Increment the counter-th counter of stats. + * + * Requires: + *\li 'stats' is a valid isc_statsmulti_t. + * + *\li counter is less than ncounters. + */ + +void +isc_statsmulti_decrement(isc_statsmulti_t *stats, isc_statscounter_t counter); +/*%< + * Decrement the counter-th counter of stats. + * + * Requires: + *\li 'stats' is a valid isc_statsmulti_t. + * + *\li counter is less than ncounters. + */ + +void +isc_statsmulti_dump(isc_statsmulti_t *stats, isc_statsmulti_dumper_t dump_fn, + void *arg, unsigned int options); +/*%< + * Dump the current statistics counters in a specified way. For each counter + * in stats, dump_fn is called with its current value and the given argument + * arg. By default counters that have a value of 0 is skipped; if options has + * the ISC_STATSMULTIDUMP_VERBOSE flag, even such counters are dumped. + * + * Requires: + *\li 'stats' is a valid isc_statsmulti_t. + */ + +isc_statscounter_t +isc_statsmulti_get_counter(isc_statsmulti_t *stats, isc_statscounter_t counter); +/*%< + * Returns value currently stored in counter. + * + * Requires: + *\li 'stats' is a valid isc_statsmulti_t. + * + *\li counter is less than ncounters. + */ + +void +isc_statsmulti_clear(isc_statsmulti_t *stats); +/*%< + * Set all counters to zero. + * + * Requires: + *\li 'stats' is a valid isc_statsmulti_t. + */ diff --git a/lib/isc/meson.build b/lib/isc/meson.build index f2c164a5b7..a99c3450f9 100644 --- a/lib/isc/meson.build +++ b/lib/isc/meson.build @@ -123,6 +123,7 @@ isc_srcset.add( 'signal.c', 'sockaddr.c', 'stats.c', + 'statsmulti.c', 'stdio.c', 'stdtime.c', 'string.c', diff --git a/lib/isc/statsmulti.c b/lib/isc/statsmulti.c new file mode 100644 index 0000000000..70f9918262 --- /dev/null +++ b/lib/isc/statsmulti.c @@ -0,0 +1,187 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/*! \file */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ISC_STATSMULTI_MAGIC ISC_MAGIC('S', 'M', 'u', 'l') +#define ISC_STATSMULTI_VALID(x) ISC_MAGIC_VALID(x, ISC_STATSMULTI_MAGIC) + +/* + * Same constraint as stats.c + */ +STATIC_ASSERT(sizeof(isc_statscounter_t) <= sizeof(uint64_t), + "Exported statistics must fit into the statistic counter size"); + +struct isc_statsmulti { + unsigned int magic; + isc_mem_t *mctx; + isc_refcount_t references; + int n_counters; + int per_thread_capacity; + int num_threads_plus_one; + isc_atomic_statscounter_t *counters; +}; + +static int +to_index(isc_statsmulti_t *stats, isc_tid_t tid, + isc_statscounter_t internal_counter) { + int thread_id = tid + 1; + if (thread_id >= stats->num_threads_plus_one) { + thread_id = 0; + } + return thread_id * stats->per_thread_capacity + internal_counter; +} + +void +isc_statsmulti_create(isc_mem_t *mctx, isc_statsmulti_t **statsp, + int ncounters) { + REQUIRE(statsp != NULL && *statsp == NULL); + + size_t size_in_bytes = sizeof(isc_atomic_statscounter_t) * ncounters; + size_t rounded_up = (size_in_bytes + 63) & ~63; /* Round up to next + multiple of 64 */ + int per_thread_capacity = rounded_up / + sizeof(isc_atomic_statscounter_t); + int num_threads_plus_one = isc_tid_count() + 1; + + isc_statsmulti_t *stats = isc_mem_get(mctx, sizeof(*stats)); + *stats = (isc_statsmulti_t){ + .magic = ISC_STATSMULTI_MAGIC, + .counters = isc_mem_cget( + mctx, per_thread_capacity * num_threads_plus_one, + sizeof(isc_atomic_statscounter_t)), + .mctx = isc_mem_ref(mctx), + .n_counters = ncounters, + .num_threads_plus_one = num_threads_plus_one, + .per_thread_capacity = per_thread_capacity, + .references = ISC_REFCOUNT_INITIALIZER(1), + + }; + *statsp = stats; +} + +void +isc_statsmulti_attach(isc_statsmulti_t *stats, isc_statsmulti_t **statsp) { + REQUIRE(ISC_STATSMULTI_VALID(stats)); + REQUIRE(statsp != NULL && *statsp == NULL); + + isc_refcount_increment(&stats->references); + *statsp = stats; +} + +void +isc_statsmulti_detach(isc_statsmulti_t **statsp) { + isc_statsmulti_t *stats; + + REQUIRE(statsp != NULL && ISC_STATSMULTI_VALID(*statsp)); + + stats = *statsp; + *statsp = NULL; + + if (isc_refcount_decrement(&stats->references) == 1) { + isc_refcount_destroy(&stats->references); + size_t alloc_size = stats->per_thread_capacity * + stats->num_threads_plus_one * + sizeof(isc_atomic_statscounter_t); + isc_mem_put(stats->mctx, stats->counters, alloc_size); + isc_mem_putanddetach(&stats->mctx, stats, sizeof(*stats)); + } +} + +void +isc_statsmulti_increment(isc_statsmulti_t *stats, isc_statscounter_t counter) { + REQUIRE(ISC_STATSMULTI_VALID(stats)); + REQUIRE(counter < stats->n_counters); + + int index = to_index(stats, isc_tid(), counter); + if (isc_tid() == -1) { + atomic_fetch_add_relaxed(&stats->counters[index], 1); + } else { + isc_atomic_statscounter_t *ptr = &stats->counters[index]; + atomic_store_relaxed(ptr, atomic_load_relaxed(ptr) + 1); + } +} + +void +isc_statsmulti_decrement(isc_statsmulti_t *stats, isc_statscounter_t counter) { + REQUIRE(ISC_STATSMULTI_VALID(stats)); + REQUIRE(counter < stats->n_counters); + + int index = to_index(stats, isc_tid(), counter); + if (isc_tid() == -1) { + atomic_fetch_sub_relaxed(&stats->counters[index], 1); + } else { + isc_atomic_statscounter_t *ptr = &stats->counters[index]; + int_fast64_t tmp = atomic_load_relaxed(ptr); + atomic_store_relaxed(ptr, tmp - 1); + } +} + +void +isc_statsmulti_dump(isc_statsmulti_t *stats, isc_statsmulti_dumper_t dump_fn, + void *arg, unsigned int options) { + REQUIRE(ISC_STATSMULTI_VALID(stats)); + + for (int counter = 0; counter < stats->n_counters; counter++) { + isc_statscounter_t total = isc_statsmulti_get_counter(stats, + counter); + + if ((options & ISC_STATSMULTIDUMP_VERBOSE) == 0 && total == 0) { + continue; + } + dump_fn((isc_statscounter_t)counter, total, arg); + } +} + +isc_statscounter_t +isc_statsmulti_get_counter(isc_statsmulti_t *stats, + isc_statscounter_t counter) { + REQUIRE(ISC_STATSMULTI_VALID(stats)); + REQUIRE(counter < stats->n_counters); + + int idx_0 = to_index(stats, 0, counter); + isc_statscounter_t total = atomic_load_acquire(&stats->counters[idx_0]); + + for (int thread = 1; thread < stats->num_threads_plus_one; thread++) { + int index = to_index(stats, thread, counter); + total += atomic_load_relaxed(&stats->counters[index]); + } + + return total; +} + +void +isc_statsmulti_clear(isc_statsmulti_t *stats) { + REQUIRE(ISC_STATSMULTI_VALID(stats)); + + for (int idx = 0; + idx < stats->per_thread_capacity * stats->num_threads_plus_one; + idx++) + { + atomic_store_release(&stats->counters[idx], 0); + } +} diff --git a/lib/ns/client.c b/lib/ns/client.c index c0a5649a3b..6bdcbc3e62 100644 --- a/lib/ns/client.c +++ b/lib/ns/client.c @@ -2515,7 +2515,7 @@ ns__client_tcpconn(isc_nmhandle_t *handle, isc_result_t result, void *arg) { } tcpquota = isc_quota_getused(&sctx->tcpquota); - ns_stats_update_if_greater(sctx->nsstats, ns_statscounter_tcphighwater, + ns_stats_update_if_greater(sctx->nshighwaterstats, ns_highwater_tcp, tcpquota); return ISC_R_SUCCESS; diff --git a/lib/ns/include/ns/server.h b/lib/ns/include/ns/server.h index 32f4e1d66b..b5bbb391a6 100644 --- a/lib/ns/include/ns/server.h +++ b/lib/ns/include/ns/server.h @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -120,10 +121,11 @@ struct ns_server { ns_matchview_t matchingview; /*% Stats counters */ - ns_stats_t *nsstats; - dns_stats_t *rcvquerystats; - dns_stats_t *opcodestats; - dns_stats_t *rcodestats; + isc_statsmulti_t *nsstats; + isc_stats_t *nshighwaterstats; + isc_statsmulti_t *rcvquerystats; + isc_statsmulti_t *opcodestats; + isc_statsmulti_t *rcodestats; isc_histomulti_t *udpinstats4; isc_histomulti_t *udpoutstats4; diff --git a/lib/ns/include/ns/stats.h b/lib/ns/include/ns/stats.h index 496e4cd9a5..c242f2c19c 100644 --- a/lib/ns/include/ns/stats.h +++ b/lib/ns/include/ns/stats.h @@ -17,6 +17,7 @@ #include #include +#include #include @@ -107,50 +108,54 @@ enum { ns_statscounter_prefetch = 64, ns_statscounter_keytagopt = 65, - ns_statscounter_tcphighwater = 66, + ns_statscounter_reclimitdropped = 66, - ns_statscounter_reclimitdropped = 67, + ns_statscounter_updatequota = 67, + ns_statscounter_dot = 68, + ns_statscounter_doh = 69, + ns_statscounter_dohplain = 70, - ns_statscounter_updatequota = 68, + ns_statscounter_proxyudp = 71, + ns_statscounter_proxytcp = 72, + ns_statscounter_proxydot = 73, + ns_statscounter_proxydoh = 74, + ns_statscounter_proxydohplain = 75, + ns_statscounter_encryptedproxydot = 76, + ns_statscounter_encryptedproxydoh = 77, - ns_statscounter_recurshighwater = 69, + ns_statscounter_max = 78, +}; - ns_statscounter_dot = 70, - ns_statscounter_doh = 71, - ns_statscounter_dohplain = 72, +/*% + * Highwater statistics counters. Used as isc_statscounter_t values + * for the separate highwater stats structure. + */ +enum { + ns_highwater_tcp = 0, + ns_highwater_recursive = 1, - ns_statscounter_proxyudp = 73, - ns_statscounter_proxytcp = 74, - ns_statscounter_proxydot = 75, - ns_statscounter_proxydoh = 76, - ns_statscounter_proxydohplain = 77, - ns_statscounter_encryptedproxydot = 78, - ns_statscounter_encryptedproxydoh = 79, - - ns_statscounter_max = 80, + ns_highwater_max = 2, }; void -ns_stats_attach(ns_stats_t *stats, ns_stats_t **statsp); +ns_stats_create(isc_mem_t *mctx, isc_statsmulti_t **statsp, + isc_stats_t **hwstatsp); void -ns_stats_detach(ns_stats_t **statsp); +ns_stats_increment(isc_statsmulti_t *stats, isc_statscounter_t counter); void -ns_stats_create(isc_mem_t *mctx, int ncounters, ns_stats_t **statsp); - -isc_statscounter_t -ns_stats_increment(ns_stats_t *stats, isc_statscounter_t counter); +ns_stats_decrement(isc_statsmulti_t *stats, isc_statscounter_t counter); void -ns_stats_decrement(ns_stats_t *stats, isc_statscounter_t counter); - -isc_stats_t * -ns_stats_get(ns_stats_t *stats); - -void -ns_stats_update_if_greater(ns_stats_t *stats, isc_statscounter_t counter, +ns_stats_update_if_greater(isc_stats_t *hwstats, isc_statscounter_t counter, isc_statscounter_t value); isc_statscounter_t -ns_stats_get_counter(ns_stats_t *stats, isc_statscounter_t counter); +ns_stats_get_counter(isc_statsmulti_t *stats, isc_statscounter_t counter); + +isc_statscounter_t +ns_stats_get_highwater(isc_stats_t *hwstats, isc_statscounter_t counter); + +void +ns_stats_reset_highwater(isc_stats_t *hwstats, isc_statscounter_t counter); diff --git a/lib/ns/query.c b/lib/ns/query.c index 441a12fe5b..f0ef5c7a47 100644 --- a/lib/ns/query.c +++ b/lib/ns/query.c @@ -546,7 +546,7 @@ inc_stats(ns_client_t *client, isc_statscounter_t counter) { dns_rdatatype_t qtype; dns_rdataset_t *rdataset; isc_stats_t *zonestats; - dns_stats_t *querystats = NULL; + isc_statsmulti_t *querystats = NULL; ns_stats_increment(client->manager->sctx->nsstats, counter); @@ -2587,7 +2587,6 @@ free_fresp(ns_client_t *client, dns_fetchresponse_t **frespp) { static isc_result_t recursionquotatype_attach(ns_client_t *client, bool soft_limit) { - isc_statscounter_t recurscount; isc_result_t result; result = isc_quota_acquire(&client->manager->sctx->recursionquota); @@ -2610,12 +2609,13 @@ recursionquotatype_attach(ns_client_t *client, bool soft_limit) { return result; } - recurscount = ns_stats_increment(client->manager->sctx->nsstats, - ns_statscounter_recursclients); + ns_stats_increment(client->manager->sctx->nsstats, + ns_statscounter_recursclients); + isc_statscounter_t recurscount = ns_stats_get_counter( + client->manager->sctx->nsstats, ns_statscounter_recursclients); - ns_stats_update_if_greater(client->manager->sctx->nsstats, - ns_statscounter_recurshighwater, - recurscount + 1); + ns_stats_update_if_greater(client->manager->sctx->nshighwaterstats, + ns_highwater_recursive, recurscount); return result; } diff --git a/lib/ns/server.c b/lib/ns/server.c index 857c6d0b6a..7152970d99 100644 --- a/lib/ns/server.c +++ b/lib/ns/server.c @@ -70,7 +70,7 @@ ns_server_create(isc_mem_t *mctx, ns_matchview_t matchingview, ISC_LIST_INIT(sctx->http_quotas); isc_mutex_init(&sctx->http_quotas_lock); - ns_stats_create(mctx, ns_statscounter_max, &sctx->nsstats); + ns_stats_create(mctx, &sctx->nsstats, &sctx->nshighwaterstats); dns_rdatatypestats_create(mctx, &sctx->rcvquerystats); @@ -162,17 +162,21 @@ ns_server_detach(ns_server_t **sctxp) { } if (sctx->nsstats != NULL) { - ns_stats_detach(&sctx->nsstats); + isc_statsmulti_detach(&sctx->nsstats); + } + + if (sctx->nshighwaterstats != NULL) { + isc_stats_detach(&sctx->nshighwaterstats); } if (sctx->rcvquerystats != NULL) { - dns_stats_detach(&sctx->rcvquerystats); + isc_statsmulti_detach(&sctx->rcvquerystats); } if (sctx->opcodestats != NULL) { - dns_stats_detach(&sctx->opcodestats); + isc_statsmulti_detach(&sctx->opcodestats); } if (sctx->rcodestats != NULL) { - dns_stats_detach(&sctx->rcodestats); + isc_statsmulti_detach(&sctx->rcodestats); } if (sctx->udpinstats4 != NULL) { diff --git a/lib/ns/stats.c b/lib/ns/stats.c index 6bc7c1f346..c380d3594c 100644 --- a/lib/ns/stats.c +++ b/lib/ns/stats.c @@ -13,103 +13,65 @@ /*! \file */ -#include #include -#include #include +#include #include #include -#define NS_STATS_MAGIC ISC_MAGIC('N', 's', 't', 't') -#define NS_STATS_VALID(x) ISC_MAGIC_VALID(x, NS_STATS_MAGIC) - -struct ns_stats { - /*% Unlocked */ - unsigned int magic; - isc_mem_t *mctx; - isc_stats_t *counters; - isc_refcount_t references; -}; - void -ns_stats_attach(ns_stats_t *stats, ns_stats_t **statsp) { - REQUIRE(NS_STATS_VALID(stats)); +ns_stats_create(isc_mem_t *mctx, isc_statsmulti_t **statsp, + isc_stats_t **hwstatsp) { REQUIRE(statsp != NULL && *statsp == NULL); + REQUIRE(hwstatsp != NULL && *hwstatsp == NULL); - isc_refcount_increment(&stats->references); - - *statsp = stats; -} - -void -ns_stats_detach(ns_stats_t **statsp) { - ns_stats_t *stats; - - REQUIRE(statsp != NULL && NS_STATS_VALID(*statsp)); - - stats = *statsp; - *statsp = NULL; - - if (isc_refcount_decrement(&stats->references) == 1) { - isc_stats_detach(&stats->counters); - isc_refcount_destroy(&stats->references); - isc_mem_putanddetach(&stats->mctx, stats, sizeof(*stats)); - } -} - -void -ns_stats_create(isc_mem_t *mctx, int ncounters, ns_stats_t **statsp) { - REQUIRE(statsp != NULL && *statsp == NULL); - - ns_stats_t *stats = isc_mem_get(mctx, sizeof(*stats)); - stats->counters = NULL; - - isc_refcount_init(&stats->references, 1); - - isc_stats_create(mctx, &stats->counters, ncounters); - - stats->magic = NS_STATS_MAGIC; - stats->mctx = NULL; - isc_mem_attach(mctx, &stats->mctx); - *statsp = stats; + isc_statsmulti_create(mctx, statsp, ns_statscounter_max); + isc_stats_create(mctx, hwstatsp, ns_highwater_max); } /*% * Increment/Decrement methods */ -isc_statscounter_t -ns_stats_increment(ns_stats_t *stats, isc_statscounter_t counter) { - REQUIRE(NS_STATS_VALID(stats)); +void +ns_stats_increment(isc_statsmulti_t *stats, isc_statscounter_t counter) { + REQUIRE(stats != NULL); - return isc_stats_increment(stats->counters, counter); + isc_statsmulti_increment(stats, counter); } void -ns_stats_decrement(ns_stats_t *stats, isc_statscounter_t counter) { - REQUIRE(NS_STATS_VALID(stats)); +ns_stats_decrement(isc_statsmulti_t *stats, isc_statscounter_t counter) { + REQUIRE(stats != NULL); - isc_stats_decrement(stats->counters, counter); -} - -isc_stats_t * -ns_stats_get(ns_stats_t *stats) { - REQUIRE(NS_STATS_VALID(stats)); - - return stats->counters; + isc_statsmulti_decrement(stats, counter); } void -ns_stats_update_if_greater(ns_stats_t *stats, isc_statscounter_t counter, +ns_stats_update_if_greater(isc_stats_t *hwstats, isc_statscounter_t counter, isc_statscounter_t value) { - REQUIRE(NS_STATS_VALID(stats)); + REQUIRE(hwstats != NULL); - isc_stats_update_if_greater(stats->counters, counter, value); + isc_stats_update_if_greater(hwstats, counter, value); } isc_statscounter_t -ns_stats_get_counter(ns_stats_t *stats, isc_statscounter_t counter) { - REQUIRE(NS_STATS_VALID(stats)); +ns_stats_get_counter(isc_statsmulti_t *stats, isc_statscounter_t counter) { + REQUIRE(stats != NULL); - return isc_stats_get_counter(stats->counters, counter); + return isc_statsmulti_get_counter(stats, counter); +} + +isc_statscounter_t +ns_stats_get_highwater(isc_stats_t *hwstats, isc_statscounter_t counter) { + REQUIRE(hwstats != NULL); + + return isc_stats_get_counter(hwstats, counter); +} + +void +ns_stats_reset_highwater(isc_stats_t *hwstats, isc_statscounter_t counter) { + REQUIRE(hwstats != NULL); + + isc_stats_set(hwstats, 0, counter); } diff --git a/tests/isc/stats_test.c b/tests/isc/stats_test.c index 36071e7165..cfbd823498 100644 --- a/tests/isc/stats_test.c +++ b/tests/isc/stats_test.c @@ -22,10 +22,16 @@ #define UNIT_TESTING #include +#include +#include #include +#include #include #include #include +#include +#include +#include #include #include @@ -92,9 +98,102 @@ ISC_RUN_TEST_IMPL(isc_stats_basic) { isc_stats_detach(&stats); } +/* test statsmulti */ +ISC_RUN_TEST_IMPL(isc_statsmulti_basic) { + isc_statsmulti_t *stats = NULL; + + /* Create with 3 additive counters */ + isc_statsmulti_create(isc_g_mctx, &stats, 3); + + /* Test increment on additive counters */ + for (int i = 0; i < 3; i++) { + isc_statsmulti_increment(stats, i); + assert_int_equal(isc_statsmulti_get_counter(stats, i), 1); + isc_statsmulti_increment(stats, i); + assert_int_equal(isc_statsmulti_get_counter(stats, i), 2); + } + + /* Test decrement on additive counters */ + for (int i = 0; i < 3; i++) { + isc_statsmulti_decrement(stats, i); + assert_int_equal(isc_statsmulti_get_counter(stats, i), 1); + isc_statsmulti_decrement(stats, i); + assert_int_equal(isc_statsmulti_get_counter(stats, i), 0); + } + + /* Test clear */ + isc_statsmulti_increment(stats, 0); + isc_statsmulti_increment(stats, 1); + isc_statsmulti_clear(stats); + for (int i = 0; i < 3; i++) { + assert_int_equal(isc_statsmulti_get_counter(stats, i), 0); + } + + isc_statsmulti_detach(&stats); +} + +/* test statsmulti with multiple threads */ +static isc_statsmulti_t *mt_stats = NULL; +static atomic_uint_fast32_t mt_workers_completed = 0; +static int mt_counter_id = 0; /* Global counter ID */ + +#define MT_INCREMENTS_PER_THREAD 100000 + +static void +mt_increment_worker(void *arg ISC_ATTR_UNUSED) { + /* Do exactly 100,000 increments */ + for (int i = 0; i < MT_INCREMENTS_PER_THREAD; i++) { + isc_statsmulti_increment(mt_stats, mt_counter_id); + } + + /* Signal completion and check if we're the last one */ + uint32_t completed = atomic_fetch_add(&mt_workers_completed, 1) + 1; + if (completed == isc_loopmgr_nloops()) { + /* Last worker shuts down the loop manager */ + isc_loopmgr_shutdown(); + } +} + +static void +mt_setup_workers(void *arg ISC_ATTR_UNUSED) { + /* Start workers on each loop */ + for (size_t i = 0; i < isc_loopmgr_nloops(); i++) { + isc_async_run(isc_loop_get(i), mt_increment_worker, NULL); + } +} + +ISC_RUN_TEST_IMPL(isc_statsmulti_multithread) { + atomic_store(&mt_workers_completed, 0); + + /* Create stats with 1 additive counter */ + isc_statsmulti_create(isc_g_mctx, &mt_stats, 1); + + isc_loop_setup(isc_loop_main(), mt_setup_workers, NULL); + isc_loopmgr_run(); + + /* Check results - should be exactly threads * increments per thread */ + uint64_t actual_count = isc_statsmulti_get_counter(mt_stats, 0); + uint64_t expected_total = (uint64_t)isc_loopmgr_nloops() * + MT_INCREMENTS_PER_THREAD; + + /* Verify no increments were lost */ + assert_int_equal(actual_count, expected_total); + assert_true(actual_count > 0); + + /* Verify all workers completed */ + assert_int_equal(atomic_load(&mt_workers_completed), + isc_loopmgr_nloops()); + + /* Cleanup */ + isc_statsmulti_detach(&mt_stats); +} + ISC_TEST_LIST_START ISC_TEST_ENTRY(isc_stats_basic) +ISC_TEST_ENTRY(isc_statsmulti_basic) +ISC_TEST_ENTRY_CUSTOM(isc_statsmulti_multithread, setup_loopmgr, + teardown_loopmgr) ISC_TEST_LIST_END