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 */
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);
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;
isc_stats_detach(&resstats);
}
if (resquerystats != NULL) {
- dns_stats_detach(&resquerystats);
+ isc_statsmulti_detach(&resquerystats);
}
if (resqueryinrttstats != NULL) {
isc_histomulti_detach(&resqueryinrttstats);
}
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;
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",
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);
* 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];
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];
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) \
* 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];
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");
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",
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;
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);
}
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,
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];
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 */
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;
&dumparg, 0);
CHECK(dumparg.result);
}
- dns_stats_detach(&dstats);
+ isc_statsmulti_detach(&dstats);
TRY0(xmlTextWriterEndElement(writer));
/* <resstats> */
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];
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;
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();
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);
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;
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,
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 */
}
if (rcvquerystats != NULL) {
- dns_stats_detach(&rcvquerystats);
+ isc_statsmulti_detach(&rcvquerystats);
}
if (dnssecsignstats != NULL) {
#include <isc/loop.h>
#include <isc/refcount.h>
#include <isc/stats.h>
+#include <isc/statsmulti.h>
#include <isc/tls.h>
#include <isc/types.h>
*/
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
*/
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
#include <inttypes.h>
#include <isc/histo.h>
+#include <isc/statsmulti.h>
#include <dns/resolver.h>
#include <dns/types.h>
*/
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.
*
*/
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.
*
*/
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.
*
*/
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
*/
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
*/
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
* 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
*/
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
* 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
* 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().
*/
#include <isc/formatcheck.h>
#include <isc/rwlock.h>
+#include <isc/statsmulti.h>
#include <isc/tls.h>
#include <dns/catz.h>
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);
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 *
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;
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);
}
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);
}
}
#include <isc/mem.h>
#include <isc/refcount.h>
#include <isc/stats.h>
+#include <isc/statsmulti.h>
#include <isc/util.h>
#include <dns/opcode.h>
}
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
}
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
}
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
}
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);
}
}
}
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
}
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);
}
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;
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);
}
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;
}
}
* 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;
--- /dev/null
+/*
+ * 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 <inttypes.h>
+
+#include <isc/types.h>
+
+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.
+ */
'signal.c',
'sockaddr.c',
'stats.c',
+ 'statsmulti.c',
'stdio.c',
'stdtime.c',
'string.c',
--- /dev/null
+/*
+ * 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 <inttypes.h>
+#include <string.h>
+
+#include <isc/atomic.h>
+#include <isc/buffer.h>
+#include <isc/magic.h>
+#include <isc/mem.h>
+#include <isc/os.h>
+#include <isc/refcount.h>
+#include <isc/stats.h>
+#include <isc/statsmulti.h>
+#include <isc/tid.h>
+#include <isc/util.h>
+
+#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);
+ }
+}
}
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;
#include <isc/quota.h>
#include <isc/random.h>
#include <isc/sockaddr.h>
+#include <isc/statsmulti.h>
#include <isc/types.h>
#include <dns/acl.h>
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;
#include <isc/mem.h>
#include <isc/stats.h>
+#include <isc/statsmulti.h>
#include <ns/types.h>
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_dot = 70,
- ns_statscounter_doh = 71,
- ns_statscounter_dohplain = 72,
+ ns_statscounter_max = 78,
+};
- 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,
+/*%
+ * 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_max = 80,
+ ns_highwater_max = 2,
};
void
-ns_stats_attach(ns_stats_t *stats, ns_stats_t **statsp);
-
-void
-ns_stats_detach(ns_stats_t **statsp);
+ns_stats_create(isc_mem_t *mctx, isc_statsmulti_t **statsp,
+ isc_stats_t **hwstatsp);
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_increment(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);
+ns_stats_decrement(isc_statsmulti_t *stats, isc_statscounter_t 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);
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);
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);
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);
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;
}
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);
}
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) {
/*! \file */
-#include <isc/magic.h>
#include <isc/mem.h>
-#include <isc/refcount.h>
#include <isc/stats.h>
+#include <isc/statsmulti.h>
#include <isc/util.h>
#include <ns/stats.h>
-#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;
+ isc_statsmulti_create(mctx, statsp, ns_statscounter_max);
+ isc_stats_create(mctx, hwstatsp, ns_highwater_max);
}
+/*%
+ * Increment/Decrement methods
+ */
void
-ns_stats_detach(ns_stats_t **statsp) {
- ns_stats_t *stats;
-
- REQUIRE(statsp != NULL && NS_STATS_VALID(*statsp));
+ns_stats_increment(isc_statsmulti_t *stats, isc_statscounter_t counter) {
+ REQUIRE(stats != NULL);
- 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));
- }
+ isc_statsmulti_increment(stats, counter);
}
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;
-}
+ns_stats_decrement(isc_statsmulti_t *stats, isc_statscounter_t counter) {
+ REQUIRE(stats != NULL);
-/*%
- * Increment/Decrement methods
- */
-isc_statscounter_t
-ns_stats_increment(ns_stats_t *stats, isc_statscounter_t counter) {
- REQUIRE(NS_STATS_VALID(stats));
-
- return isc_stats_increment(stats->counters, counter);
+ isc_statsmulti_decrement(stats, counter);
}
void
-ns_stats_decrement(ns_stats_t *stats, isc_statscounter_t counter) {
- REQUIRE(NS_STATS_VALID(stats));
+ns_stats_update_if_greater(isc_stats_t *hwstats, isc_statscounter_t counter,
+ isc_statscounter_t value) {
+ REQUIRE(hwstats != NULL);
- isc_stats_decrement(stats->counters, counter);
+ isc_stats_update_if_greater(hwstats, counter, value);
}
-isc_stats_t *
-ns_stats_get(ns_stats_t *stats) {
- REQUIRE(NS_STATS_VALID(stats));
+isc_statscounter_t
+ns_stats_get_counter(isc_statsmulti_t *stats, isc_statscounter_t counter) {
+ REQUIRE(stats != NULL);
- return stats->counters;
+ return isc_statsmulti_get_counter(stats, counter);
}
-void
-ns_stats_update_if_greater(ns_stats_t *stats, isc_statscounter_t counter,
- isc_statscounter_t value) {
- REQUIRE(NS_STATS_VALID(stats));
+isc_statscounter_t
+ns_stats_get_highwater(isc_stats_t *hwstats, isc_statscounter_t counter) {
+ REQUIRE(hwstats != NULL);
- isc_stats_update_if_greater(stats->counters, counter, value);
+ return isc_stats_get_counter(hwstats, counter);
}
-isc_statscounter_t
-ns_stats_get_counter(ns_stats_t *stats, isc_statscounter_t counter) {
- REQUIRE(NS_STATS_VALID(stats));
+void
+ns_stats_reset_highwater(isc_stats_t *hwstats, isc_statscounter_t counter) {
+ REQUIRE(hwstats != NULL);
- return isc_stats_get_counter(stats->counters, counter);
+ isc_stats_set(hwstats, 0, counter);
}
#define UNIT_TESTING
#include <cmocka.h>
+#include <isc/async.h>
+#include <isc/atomic.h>
#include <isc/lib.h>
+#include <isc/loop.h>
#include <isc/mem.h>
#include <isc/result.h>
#include <isc/stats.h>
+#include <isc/statsmulti.h>
+#include <isc/time.h>
+#include <isc/timer.h>
#include <isc/util.h>
#include <tests/isc.h>
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