new: usr: Provide response round-trip time (RTT) counters via statistics channel

Previously, :iscman:`named` provided RTT counters for outgoing
queries performed by itself during name resolutions. Now this
has been improved to provide more granular counters (histogram),
and to also provide RTT counters for the incoming queries.

Closes #5279

Merge branch '5279-query-rtt-isc_histo_t-statistics' into 'main'

See merge request isc-projects/bind9!11508
This commit is contained in:
Arаm Sаrgsyаn 2026-02-26 17:21:24 +00:00
commit e7b1a44b8c
19 changed files with 685 additions and 170 deletions

View file

@ -941,6 +941,52 @@
</table>
</xsl:for-each>
</xsl:if>
<xsl:for-each select="views/view">
<xsl:if test="rtt/counters[@type=&quot;in-queries-rtt&quot;]/counter[. &gt; 0]">
<h3>Incoming Queries Response Time for View <xsl:value-of select="@name"/></h3>
<table class="counters">
<tr>
<th>Milliseconds</th>
<th>Count</th>
</tr>
<xsl:for-each select="rtt/counters[@type=&quot;in-queries-rtt&quot;]/counter">
<xsl:variable name="css-class8">
<xsl:choose>
<xsl:when test="position() mod 2 = 0">even</xsl:when>
<xsl:otherwise>odd</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<tr class="{$css-class8}">
<td><xsl:value-of select="@name"/></td>
<td><xsl:value-of select="."/></td>
</tr>
</xsl:for-each>
</table>
</xsl:if>
</xsl:for-each>
<xsl:for-each select="views/view">
<xsl:if test="rtt/counters[@type=&quot;out-queries-rtt&quot;]/counter[. &gt; 0]">
<h3>Outgoing Queries Response Time for View <xsl:value-of select="@name"/></h3>
<table class="counters">
<tr>
<th>Milliseconds</th>
<th>Count</th>
</tr>
<xsl:for-each select="rtt/counters[@type=&quot;out-queries-rtt&quot;]/counter">
<xsl:variable name="css-class8">
<xsl:choose>
<xsl:when test="position() mod 2 = 0">even</xsl:when>
<xsl:otherwise>odd</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<tr class="{$css-class8}">
<td><xsl:value-of select="@name"/></td>
<td><xsl:value-of select="."/></td>
</tr>
</xsl:for-each>
</table>
</xsl:if>
</xsl:for-each>
<xsl:if test="memory/summary">
<h2>Memory Usage Summary</h2>
<table class="counters">

View file

@ -3678,6 +3678,8 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config,
const cfg_obj_t *disablelist = NULL;
isc_stats_t *resstats = NULL;
dns_stats_t *resquerystats = NULL;
isc_histomulti_t *resqueryinrttstats = NULL;
isc_histomulti_t *resqueryoutrttstats = NULL;
bool auto_root = false;
named_cache_t *nsc = NULL;
bool zero_no_soattl;
@ -4259,6 +4261,9 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config,
dns_resolver_getstats(pview->resolver, &resstats);
dns_resolver_getquerystats(pview->resolver,
&resquerystats);
dns_resolver_getqueryrttstats(pview->resolver,
&resqueryinrttstats,
&resqueryoutrttstats);
dns_view_detach(&pview);
}
}
@ -4319,11 +4324,23 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config,
isc_stats_create(mctx, &resstats, dns_resstatscounter_max);
}
dns_resolver_setstats(view->resolver, resstats);
if (resquerystats == NULL) {
dns_rdatatypestats_create(mctx, &resquerystats);
}
dns_resolver_setquerystats(view->resolver, resquerystats);
if (resqueryinrttstats == NULL) {
isc_histomulti_create(mctx, DNS_RTTHISTO_SIGBITS,
&resqueryinrttstats);
}
if (resqueryoutrttstats == NULL) {
isc_histomulti_create(mctx, DNS_RTTHISTO_SIGBITS,
&resqueryoutrttstats);
}
dns_resolver_setqueryrttstats(view->resolver, resqueryinrttstats,
resqueryoutrttstats);
/*
* Set the ADB cache size to 1/8th of the max-cache-size or
* MAX_ADB_SIZE_FOR_CACHESHARE when the cache is shared.
@ -5487,6 +5504,12 @@ cleanup:
if (resquerystats != NULL) {
dns_stats_detach(&resquerystats);
}
if (resqueryinrttstats != NULL) {
isc_histomulti_detach(&resqueryinrttstats);
}
if (resqueryoutrttstats != NULL) {
isc_histomulti_detach(&resqueryoutrttstats);
}
if (order != NULL) {
dns_order_detach(&order);
}

View file

@ -164,6 +164,8 @@ static const char *tcpinsizestats_xmldesc[dns_sizecounter_in_max];
static const char *tcpoutsizestats_xmldesc[dns_sizecounter_out_max];
static const char *dnstapstats_xmldesc[dns_dnstapcounter_max];
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
@ -203,6 +205,8 @@ static int tcpinsizestats_index[dns_sizecounter_in_max];
static int tcpoutsizestats_index[dns_sizecounter_out_max];
static int dnstapstats_index[dns_dnstapcounter_max];
static int gluecachestats_index[dns_gluecachestatscounter_max];
static int queryrttinstats_index[dns_queryrttcounter_in_max];
static int queryrttoutstats_index[dns_queryrttcounter_out_max];
static void
set_desc(int counter, int maxcounter, const char *fdesc, const char **fdescs,
@ -223,7 +227,7 @@ set_desc(int counter, int maxcounter, const char *fdesc, const char **fdescs,
}
static const char *
get_histo_desc(const char *prefix, int i, int inf, bool ext) {
get_sizehisto_desc(const char *prefix, int i, int inf, bool ext) {
static char buf[(DNS_SIZEHISTO_MAXIN + DNS_SIZEHISTO_MAXOUT) * 80];
static size_t used = 0;
char *desc = buf + used;
@ -246,6 +250,51 @@ get_histo_desc(const char *prefix, int i, int inf, bool ext) {
return desc;
}
#if defined(EXTENDED_STATS)
static const char *
get_rtthisto_desc(const char *prefix, unsigned int i, unsigned int inf,
uint64_t min, uint64_t max, bool ext) {
static char buf[DNS_RTTHISTO_MAX * 80];
static size_t used = 0;
char *desc = buf + used;
size_t space = sizeof(buf) - used;
int len = 0;
if (!ext && i < inf) {
if (min == max) {
if (min == 0) {
len = snprintf(desc, space, "%s ~0 ms", prefix);
} else {
len = snprintf(desc, space, "%s %" PRIu64 " ms",
prefix, min);
}
} else {
len = snprintf(desc, space,
"%s %" PRIu64 "-%" PRIu64 " ms", prefix,
min, max);
}
} else if (!ext && i >= inf) {
len = snprintf(desc, space, "%s %" PRIu64 "+ ms", prefix, min);
} else if (ext && i < inf) {
if (min == max) {
if (min == 0) {
len = snprintf(desc, space, "~0");
} else {
len = snprintf(desc, space, "%" PRIu64, min);
}
} else {
len = snprintf(desc, space, "%" PRIu64 "-%" PRIu64, min,
max);
}
} else if (ext && i >= inf) {
len = snprintf(desc, space, "%" PRIu64 "+", min);
}
INSIST(0 < len && (size_t)len < space);
used += len + 1;
return desc;
}
#endif /* if defined(EXTENDED_STATS) */
static void
init_desc(void) {
int i;
@ -441,28 +490,6 @@ init_desc(void) {
SET_RESSTATDESC(valnegsuccess, "DNSSEC NX validation succeeded",
"ValNegOk");
SET_RESSTATDESC(valfail, "DNSSEC validation failed", "ValFail");
SET_RESSTATDESC(queryrtt0,
"queries with RTT < " DNS_RESOLVER_QRYRTTCLASS0STR "ms",
"QryRTT" DNS_RESOLVER_QRYRTTCLASS0STR);
SET_RESSTATDESC(queryrtt1,
"queries with RTT " DNS_RESOLVER_QRYRTTCLASS0STR
"-" DNS_RESOLVER_QRYRTTCLASS1STR "ms",
"QryRTT" DNS_RESOLVER_QRYRTTCLASS1STR);
SET_RESSTATDESC(queryrtt2,
"queries with RTT " DNS_RESOLVER_QRYRTTCLASS1STR
"-" DNS_RESOLVER_QRYRTTCLASS2STR "ms",
"QryRTT" DNS_RESOLVER_QRYRTTCLASS2STR);
SET_RESSTATDESC(queryrtt3,
"queries with RTT " DNS_RESOLVER_QRYRTTCLASS2STR
"-" DNS_RESOLVER_QRYRTTCLASS3STR "ms",
"QryRTT" DNS_RESOLVER_QRYRTTCLASS3STR);
SET_RESSTATDESC(queryrtt4,
"queries with RTT " DNS_RESOLVER_QRYRTTCLASS3STR
"-" DNS_RESOLVER_QRYRTTCLASS4STR "ms",
"QryRTT" DNS_RESOLVER_QRYRTTCLASS4STR);
SET_RESSTATDESC(queryrtt5,
"queries with RTT > " DNS_RESOLVER_QRYRTTCLASS4STR "ms",
"QryRTT" DNS_RESOLVER_QRYRTTCLASS4STR "+");
SET_RESSTATDESC(nfetch, "active fetches", "NumFetch");
SET_RESSTATDESC(buckets, "bucket size", "BucketSize");
SET_RESSTATDESC(refused, "REFUSED received", "REFUSED");
@ -764,11 +791,11 @@ init_desc(void) {
for (i = 0; i < DNS_SIZEHISTO_MAXOUT; i++) {
udpoutsizestats_index[i] = i;
tcpoutsizestats_index[i] = i;
udpoutsizestats_desc[i] = get_histo_desc(
udpoutsizestats_desc[i] = get_sizehisto_desc(
"responses sent", i, DNS_SIZEHISTO_MAXOUT, false);
tcpoutsizestats_desc[i] = udpoutsizestats_desc[i];
#if defined(EXTENDED_STATS)
udpoutsizestats_xmldesc[i] = get_histo_desc(
udpoutsizestats_xmldesc[i] = get_sizehisto_desc(
"responses sent", i, DNS_SIZEHISTO_MAXOUT, true);
tcpoutsizestats_xmldesc[i] = udpoutsizestats_xmldesc[i];
#endif /* if defined(EXTENDED_STATS) */
@ -777,7 +804,7 @@ init_desc(void) {
for (i = 0; i <= DNS_SIZEHISTO_MAXIN; i++) {
udpinsizestats_index[i] = i;
tcpinsizestats_index[i] = i;
udpinsizestats_desc[i] = get_histo_desc(
udpinsizestats_desc[i] = get_sizehisto_desc(
"requests received", i, DNS_SIZEHISTO_MAXIN, false);
tcpinsizestats_desc[i] = udpinsizestats_desc[i];
#if defined(EXTENDED_STATS)
@ -786,10 +813,25 @@ init_desc(void) {
tcpinsizestats_xmldesc[i] = tcpoutsizestats_xmldesc[i];
} else {
udpinsizestats_xmldesc[i] =
get_histo_desc("requests received", i,
DNS_SIZEHISTO_MAXIN, true);
get_sizehisto_desc("requests received", i,
DNS_SIZEHISTO_MAXIN, true);
tcpinsizestats_xmldesc[i] = udpinsizestats_xmldesc[i];
}
#endif /* if defined(EXTENDED_STATS) */
}
for (i = 0; i <= DNS_RTTHISTO_MAX; i++) {
queryrttinstats_index[i] = i;
queryrttoutstats_index[i] = i;
#if defined(EXTENDED_STATS)
/*
* The descriptions are filled in during dumping (only once),
* because we don't have the isc_histomulti_t objects here
* to determine their non-linear minimum and maximum values.
*/
queryrttinstats_xmldesc[i] = NULL;
queryrttoutstats_xmldesc[i] = NULL;
#endif /* if defined(EXTENDED_STATS) */
}
}
@ -832,13 +874,26 @@ dump_stats(isc_stats_t *stats, isc_statsformat_t type, void *arg,
#if defined(EXTENDED_STATS)
static isc_result_t
dump_histo(isc_histomulti_t *hm, isc_statsformat_t type, void *arg,
const char *category, const char **desc, int ncounters, int *indices,
uint64_t *values, int options) {
const char *category, const char **desc, const char *desc_prefix,
int ncounters, int *indices, uint64_t *values, int options) {
isc_histo_t *hg = NULL;
uint64_t min, max;
isc_histomulti_merge(&hg, hm);
for (int i = 0; i < ncounters; i++) {
isc_histo_get(hg, i, NULL, NULL, &values[i]);
isc_histo_get(hg, i, &min, &max, &values[i]);
/*
* RTT descriptions are generated during the first call of
* this function for the corresponding histogram, the other
* descriptions are pregenerated and the caller shouldn't
* provide a prefix.
*/
if (desc[i] == NULL && desc_prefix != NULL) {
desc[i] = get_rtthisto_desc(desc_prefix, i,
DNS_RTTHISTO_MAX, min, max,
true);
}
}
isc_histo_destroy(&hg);
@ -1765,6 +1820,8 @@ generatexml(named_server_t *server, uint32_t flags, int *buflen,
uint64_t udpoutsizestat_values[DNS_SIZEHISTO_MAXOUT + 1];
uint64_t tcpinsizestat_values[DNS_SIZEHISTO_MAXIN + 1];
uint64_t tcpoutsizestat_values[DNS_SIZEHISTO_MAXOUT + 1];
uint64_t queryrttinstat_values[DNS_RTTHISTO_MAX + 1];
uint64_t queryrttoutstat_values[DNS_RTTHISTO_MAX + 1];
#ifdef HAVE_DNSTAP
uint64_t dnstapstat_values[dns_dnstapcounter_max];
#endif /* ifdef HAVE_DNSTAP */
@ -1921,7 +1978,7 @@ generatexml(named_server_t *server, uint32_t flags, int *buflen,
ISC_XMLCHAR "request-size"));
CHECK(dump_histo(server->sctx->udpinstats4, isc_statsformat_xml,
writer, NULL, udpinsizestats_xmldesc,
writer, NULL, udpinsizestats_xmldesc, NULL,
dns_sizecounter_in_max, udpinsizestats_index,
udpinsizestat_values, 0));
@ -1931,10 +1988,11 @@ generatexml(named_server_t *server, uint32_t flags, int *buflen,
TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
ISC_XMLCHAR "response-size"));
CHECK(dump_histo(
server->sctx->udpoutstats4, isc_statsformat_xml, writer,
NULL, udpoutsizestats_xmldesc, dns_sizecounter_out_max,
udpoutsizestats_index, udpoutsizestat_values, 0));
CHECK(dump_histo(server->sctx->udpoutstats4,
isc_statsformat_xml, writer, NULL,
udpoutsizestats_xmldesc, NULL,
dns_sizecounter_out_max, udpoutsizestats_index,
udpoutsizestat_values, 0));
TRY0(xmlTextWriterEndElement(writer)); /* </counters> */
TRY0(xmlTextWriterEndElement(writer)); /* </udp> */
@ -1945,7 +2003,7 @@ generatexml(named_server_t *server, uint32_t flags, int *buflen,
ISC_XMLCHAR "request-size"));
CHECK(dump_histo(server->sctx->tcpinstats4, isc_statsformat_xml,
writer, NULL, tcpinsizestats_xmldesc,
writer, NULL, tcpinsizestats_xmldesc, NULL,
dns_sizecounter_in_max, tcpinsizestats_index,
tcpinsizestat_values, 0));
@ -1954,10 +2012,11 @@ generatexml(named_server_t *server, uint32_t flags, int *buflen,
TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
ISC_XMLCHAR "response-size"));
CHECK(dump_histo(
server->sctx->tcpoutstats4, isc_statsformat_xml, writer,
NULL, tcpoutsizestats_xmldesc, dns_sizecounter_out_max,
tcpoutsizestats_index, tcpoutsizestat_values, 0));
CHECK(dump_histo(server->sctx->tcpoutstats4,
isc_statsformat_xml, writer, NULL,
tcpoutsizestats_xmldesc, NULL,
dns_sizecounter_out_max, tcpoutsizestats_index,
tcpoutsizestat_values, 0));
TRY0(xmlTextWriterEndElement(writer)); /* </counters> */
TRY0(xmlTextWriterEndElement(writer)); /* </tcp> */
@ -1970,7 +2029,7 @@ generatexml(named_server_t *server, uint32_t flags, int *buflen,
ISC_XMLCHAR "request-size"));
CHECK(dump_histo(server->sctx->udpinstats6, isc_statsformat_xml,
writer, NULL, udpinsizestats_xmldesc,
writer, NULL, udpinsizestats_xmldesc, NULL,
dns_sizecounter_in_max, udpinsizestats_index,
udpinsizestat_values, 0));
@ -1980,10 +2039,11 @@ generatexml(named_server_t *server, uint32_t flags, int *buflen,
TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
ISC_XMLCHAR "response-size"));
CHECK(dump_histo(
server->sctx->udpoutstats6, isc_statsformat_xml, writer,
NULL, udpoutsizestats_xmldesc, dns_sizecounter_out_max,
udpoutsizestats_index, udpoutsizestat_values, 0));
CHECK(dump_histo(server->sctx->udpoutstats6,
isc_statsformat_xml, writer, NULL,
udpoutsizestats_xmldesc, NULL,
dns_sizecounter_out_max, udpoutsizestats_index,
udpoutsizestat_values, 0));
TRY0(xmlTextWriterEndElement(writer)); /* </counters> */
TRY0(xmlTextWriterEndElement(writer)); /* </udp> */
@ -1994,7 +2054,7 @@ generatexml(named_server_t *server, uint32_t flags, int *buflen,
ISC_XMLCHAR "request-size"));
CHECK(dump_histo(server->sctx->tcpinstats6, isc_statsformat_xml,
writer, NULL, tcpinsizestats_xmldesc,
writer, NULL, tcpinsizestats_xmldesc, NULL,
dns_sizecounter_in_max, tcpinsizestats_index,
tcpinsizestat_values, 0));
@ -2004,10 +2064,11 @@ generatexml(named_server_t *server, uint32_t flags, int *buflen,
TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
ISC_XMLCHAR "response-size"));
CHECK(dump_histo(
server->sctx->tcpoutstats6, isc_statsformat_xml, writer,
NULL, tcpoutsizestats_xmldesc, dns_sizecounter_out_max,
tcpoutsizestats_index, tcpoutsizestat_values, 0));
CHECK(dump_histo(server->sctx->tcpoutstats6,
isc_statsformat_xml, writer, NULL,
tcpoutsizestats_xmldesc, NULL,
dns_sizecounter_out_max, tcpoutsizestats_index,
tcpoutsizestat_values, 0));
TRY0(xmlTextWriterEndElement(writer)); /* </counters> */
TRY0(xmlTextWriterEndElement(writer)); /* </tcp> */
@ -2027,6 +2088,7 @@ generatexml(named_server_t *server, uint32_t flags, int *buflen,
isc_stats_t *istats = NULL;
dns_stats_t *dstats = NULL;
dns_adb_t *adb = NULL;
isc_histomulti_t *hmpin = NULL, *hmpout = NULL;
TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "view"));
TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "name",
@ -2120,6 +2182,40 @@ generatexml(named_server_t *server, uint32_t flags, int *buflen,
TRY0(dns_cache_renderxml(view->cache, writer));
TRY0(xmlTextWriterEndElement(writer)); /* </cachestats> */
TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "rtt"));
dns_resolver_getqueryrttstats(view->resolver, &hmpin, &hmpout);
TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters"));
TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
ISC_XMLCHAR "in-queries-rtt"));
if (hmpin != NULL) {
CHECK(dump_histo(hmpin, isc_statsformat_xml, writer,
NULL, queryrttinstats_xmldesc,
"RTT (in)", dns_queryrttcounter_in_max,
queryrttinstats_index,
queryrttinstat_values, 0));
isc_histomulti_detach(&hmpin);
}
TRY0(xmlTextWriterEndElement(writer)); /* </counters> */
TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counters"));
TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "type",
ISC_XMLCHAR
"out-queries-rtt"));
if (hmpout != NULL) {
CHECK(dump_histo(hmpout, isc_statsformat_xml, writer,
NULL, queryrttoutstats_xmldesc,
"RTT (out)",
dns_queryrttcounter_out_max,
queryrttoutstats_index,
queryrttoutstat_values, 0));
isc_histomulti_detach(&hmpout);
}
TRY0(xmlTextWriterEndElement(writer)); /* </counters> */
TRY0(xmlTextWriterEndElement(writer)); /* </rtt> */
TRY0(xmlTextWriterEndElement(writer)); /* view */
view = ISC_LIST_NEXT(view, link);
@ -2818,6 +2914,8 @@ generatejson(named_server_t *server, size_t *msglen, const char **msg,
uint64_t udpoutsizestat_values[dns_sizecounter_out_max];
uint64_t tcpinsizestat_values[dns_sizecounter_in_max];
uint64_t tcpoutsizestat_values[dns_sizecounter_out_max];
uint64_t queryrttinstat_values[DNS_RTTHISTO_MAX + 1];
uint64_t queryrttoutstat_values[DNS_RTTHISTO_MAX + 1];
#ifdef HAVE_DNSTAP
uint64_t dnstapstat_values[dns_dnstapcounter_max];
#endif /* ifdef HAVE_DNSTAP */
@ -3027,6 +3125,7 @@ generatejson(named_server_t *server, size_t *msglen, const char **msg,
ISC_LIST_FOREACH(server->viewlist, view, link) {
json_object *za, *xa, *v = json_object_new_object();
dns_adb_t *adb = NULL;
isc_histomulti_t *hmpin = NULL, *hmpout = NULL;
CHECKMEM(v);
json_object_object_add(viewlist, view->name, v);
@ -3170,6 +3269,45 @@ generatejson(named_server_t *server, size_t *msglen, const char **msg,
json_object_object_add(res, "adb",
counters);
}
dns_resolver_getqueryrttstats(view->resolver,
&hmpin, &hmpout);
if (hmpin != NULL) {
counters = json_object_new_object();
CHECKMEM(counters);
CHECK(dump_histo(
hmpin, isc_statsformat_json,
counters, NULL,
queryrttinstats_xmldesc,
"RTT (in)",
dns_queryrttcounter_in_max,
queryrttinstats_index,
queryrttinstat_values, 0));
isc_histomulti_detach(&hmpin);
json_object_object_add(res,
"in-queries-rtt",
counters);
}
if (hmpout != NULL) {
counters = json_object_new_object();
CHECKMEM(counters);
CHECK(dump_histo(
hmpout, isc_statsformat_json,
counters, NULL,
queryrttoutstats_xmldesc,
"RTT (out)",
dns_queryrttcounter_out_max,
queryrttoutstats_index,
queryrttoutstat_values, 0));
isc_histomulti_detach(&hmpout);
json_object_object_add(
res, "out-queries-rtt",
counters);
}
}
}
}
@ -3241,49 +3379,49 @@ generatejson(named_server_t *server, size_t *msglen, const char **msg,
CHECK(dump_histo(server->sctx->udpinstats4,
isc_statsformat_json, udpreq4, NULL,
udpinsizestats_xmldesc, dns_sizecounter_in_max,
udpinsizestats_index, udpinsizestat_values,
0));
udpinsizestats_xmldesc, NULL,
dns_sizecounter_in_max, udpinsizestats_index,
udpinsizestat_values, 0));
CHECK(dump_histo(server->sctx->udpoutstats4,
isc_statsformat_json, udpresp4, NULL,
udpoutsizestats_xmldesc,
udpoutsizestats_xmldesc, NULL,
dns_sizecounter_out_max, udpoutsizestats_index,
udpoutsizestat_values, 0));
CHECK(dump_histo(server->sctx->tcpinstats4,
isc_statsformat_json, tcpreq4, NULL,
tcpinsizestats_xmldesc, dns_sizecounter_in_max,
tcpinsizestats_index, tcpinsizestat_values,
0));
tcpinsizestats_xmldesc, NULL,
dns_sizecounter_in_max, tcpinsizestats_index,
tcpinsizestat_values, 0));
CHECK(dump_histo(server->sctx->tcpoutstats4,
isc_statsformat_json, tcpresp4, NULL,
tcpoutsizestats_xmldesc,
tcpoutsizestats_xmldesc, NULL,
dns_sizecounter_out_max, tcpoutsizestats_index,
tcpoutsizestat_values, 0));
CHECK(dump_histo(server->sctx->udpinstats6,
isc_statsformat_json, udpreq6, NULL,
udpinsizestats_xmldesc, dns_sizecounter_in_max,
udpinsizestats_index, udpinsizestat_values,
0));
udpinsizestats_xmldesc, NULL,
dns_sizecounter_in_max, udpinsizestats_index,
udpinsizestat_values, 0));
CHECK(dump_histo(server->sctx->udpoutstats6,
isc_statsformat_json, udpresp6, NULL,
udpoutsizestats_xmldesc,
udpoutsizestats_xmldesc, NULL,
dns_sizecounter_out_max, udpoutsizestats_index,
udpoutsizestat_values, 0));
CHECK(dump_histo(server->sctx->tcpinstats6,
isc_statsformat_json, tcpreq6, NULL,
tcpinsizestats_xmldesc, dns_sizecounter_in_max,
tcpinsizestats_index, tcpinsizestat_values,
0));
tcpinsizestats_xmldesc, NULL,
dns_sizecounter_in_max, tcpinsizestats_index,
tcpinsizestat_values, 0));
CHECK(dump_histo(server->sctx->tcpoutstats6,
isc_statsformat_json, tcpresp6, NULL,
tcpoutsizestats_xmldesc,
tcpoutsizestats_xmldesc, NULL,
dns_sizecounter_out_max, tcpoutsizestats_index,
tcpoutsizestat_values, 0));

View file

@ -0,0 +1,56 @@
"""
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.
"""
from collections.abc import AsyncGenerator
import dns.rcode
import dns.rdatatype
import dns.rrset
from isctest.asyncserver import (
ControllableAsyncDnsServer,
DnsResponseSend,
QueryContext,
ResponseHandler,
)
class DelayedAddressAnswerHandler(ResponseHandler):
async def get_responses(
self, qctx: QueryContext
) -> AsyncGenerator[DnsResponseSend, None]:
if qctx.qtype in (dns.rdatatype.A, dns.rdatatype.AAAA):
addr = "192.0.2.1" if qctx.qtype == dns.rdatatype.A else "2001:db8:beef::1"
rrset = dns.rrset.from_text(qctx.qname, 300, qctx.qclass, qctx.qtype, addr)
qctx.response.answer.append(rrset)
delay = 0
if (
len(qctx.qname.labels) >= 2
and qctx.qname.labels[1] == b"latency"
and qctx.qname.labels[0].isdigit()
):
delay = int(qctx.qname.labels[0]) / 1000
yield DnsResponseSend(qctx.response, delay=delay)
def main() -> None:
server = ControllableAsyncDnsServer(
default_aa=True, default_rcode=dns.rcode.NOERROR
)
server.install_response_handler(DelayedAddressAnswerHandler())
server.run()
if __name__ == "__main__":
main()

View file

@ -58,6 +58,11 @@ def check_zone_timers(loaded, expires, refresh, loaded_exp):
check_loaded(loaded, loaded_exp, now)
def check_rtt(rtt, rtt_expected):
for val in rtt_expected:
assert rtt[val[0]] == val[1]
#
# The output is gibberish, but at least make sure it does not crash.
#
@ -225,3 +230,33 @@ def test_traffic(fetch_traffic, **kwargs):
data = fetch_traffic(statsip, statsport)
check_traffic(data, exp)
def test_rtt(fetch_views, **kwargs):
statsip = kwargs["statsip"]
statsport = kwargs["statsport"]
# auth query, 0 delay is expected, only for "in"
msg = create_msg("a.example2.", "TXT")
ans = isctest.query.tcp(msg, statsip, attempts=1)
isctest.check.noerror(ans)
# resolver query with a 530ms delay for both "in" and "out"
msg = create_msg("530.latency.example2.", "A")
ans = isctest.query.tcp(msg, statsip, attempts=1)
isctest.check.noerror(ans)
# resolver query with a 540ms delay for both "in" and "out"
msg = create_msg("540.latency.example2.", "A")
ans = isctest.query.tcp(msg, statsip, attempts=1)
isctest.check.noerror(ans)
# resolver query with a 730ms delay for both "in" and "out"
msg = create_msg("730.latency.example2.", "A")
ans = isctest.query.tcp(msg, statsip, attempts=1)
isctest.check.noerror(ans)
data = fetch_views(statsip, statsport)
check_rtt(data["in-queries-rtt"], [["~0", 1], ["512-575", 2], ["704-767", 1]])
check_rtt(data["out-queries-rtt"], [["512-575", 2], ["704-767", 1]])

View file

@ -0,0 +1,28 @@
; 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.
$ORIGIN .
$TTL 300 ; 5 minutes
example2 IN SOA mname1. . (
1 ; serial
20 ; refresh (20 seconds)
20 ; retry (20 seconds)
1814400 ; expire (3 weeks)
3600 ; minimum (1 hour)
)
example2. NS ns4.example2.
ns4.example2. A 10.53.0.4
$ORIGIN example2.
a A 10.0.0.1
latency NS ns5.example2.
ns5.example2. A 10.53.0.5

View file

@ -0,0 +1,44 @@
/*
* 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.
*/
options {
query-source address 10.53.0.4;
notify-source 10.53.0.4;
transfer-source 10.53.0.4;
port @PORT@;
pid-file "named.pid";
listen-on { 10.53.0.4; };
listen-on-v6 { none; };
recursion yes;
dnssec-validation no;
notify no;
minimal-responses no;
version none; // make statistics independent of the version number
};
statistics-channels { inet 10.53.0.4 port @EXTRAPORT1@ allow { localhost; }; };
key rndc_key {
secret "1234abcd8765";
algorithm @DEFAULT_HMAC@;
};
controls {
inet 10.53.0.4 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
};
zone "example2" {
type primary;
file "example2.db";
allow-transfer { any; };
};

View file

@ -24,6 +24,7 @@ pytestmark = [
isctest.mark.with_json_c,
pytest.mark.extra_artifacts(
[
"ans5/ans.run",
"ns2/*.jnl",
"ns2/*.signed",
"ns2/dsset-*",
@ -62,6 +63,19 @@ def fetch_traffic_json(statsip, statsport):
return data["traffic"]
def fetch_rtt_json(statsip, statsport):
r = requests.get(f"http://{statsip}:{statsport}/json/v1", timeout=600)
assert r.status_code == 200
views = r.json()["views"]
data = {
"in-queries-rtt": views["_default"]["resolver"]["in-queries-rtt"],
"out-queries-rtt": views["_default"]["resolver"]["out-queries-rtt"],
}
return data
def load_timers_json(zone, primary=True):
name = zone["name"]
@ -119,3 +133,8 @@ def test_zone_with_many_keys_json(statsport):
@pytest.mark.flaky(max_runs=2)
def test_traffic_json(statsport):
generic.test_traffic(fetch_traffic_json, statsip="10.53.0.2", statsport=statsport)
@pytest.mark.flaky(max_runs=2)
def test_rtt_json(statsport):
generic.test_rtt(fetch_rtt_json, statsip="10.53.0.4", statsport=statsport)

View file

@ -14,6 +14,7 @@ import pytest
pytestmark = pytest.mark.extra_artifacts(
[
"K*",
"ans5/ans.run",
"bind9.xsl.1",
"bind9.xsl.2",
"compressed.headers",

View file

@ -27,6 +27,7 @@ pytestmark = [
pytest.mark.extra_artifacts(
[
"ns2/K*",
"ans5/ans.run",
"ns2/*.jnl",
"ns2/*.signed",
"ns2/dsset-*",
@ -91,6 +92,35 @@ def fetch_traffic_xml(statsip, statsport):
return traffic
def fetch_rtt_xml(statsip, statsport):
def load_counters(data):
out = {}
for counter in data.findall("counter"):
out[counter.attrib["name"]] = int(counter.text)
return out
r = requests.get(f"http://{statsip}:{statsport}/xml/v3", timeout=600)
assert r.status_code == 200
root = ET.fromstring(r.text)
default_view = None
for view in root.find("views").iter("view"):
if view.attrib["name"] == "_default":
default_view = view
break
assert default_view is not None
rtt = {}
for counters in default_view.find("rtt").findall("counters"):
key = counters.attrib["type"]
values = load_counters(counters)
rtt[key] = values
return rtt
def load_timers_xml(zone, primary=True):
name = zone.attrib["name"]
@ -149,3 +179,8 @@ def test_zone_with_many_keys_xml(statsport):
@pytest.mark.flaky(max_runs=2)
def test_traffic_xml(statsport):
generic.test_traffic(fetch_traffic_xml, statsip="10.53.0.2", statsport=statsport)
@pytest.mark.flaky(max_runs=2)
def test_rtt_xml(statsport):
generic.test_rtt(fetch_rtt_xml, statsip="10.53.0.4", statsport=statsport)

View file

@ -8468,9 +8468,6 @@ Resolver Statistics Counters
``ValFail``
This indicates the number of failed DNSSEC validations.
``QryRTTnn``
This provides a frequency table on query round-trip times (RTTs). Each ``nn`` specifies the corresponding frequency. In the sequence of ``nn_1``, ``nn_2``, ..., ``nn_m``, the value of ``nn_i`` is the number of queries whose RTTs are between ``nn_(i-1)`` (inclusive) and ``nn_i`` (exclusive) milliseconds. For the sake of convenience, we define ``nn_0`` to be 0. The last entry should be represented as ``nn_m+``, which means the number of queries whose RTTs are equal to or greater than ``nn_m`` milliseconds.
``NumFetch``
This indicates the number of active fetches.
@ -8516,6 +8513,21 @@ Resolver Statistics Counters
``Priming``
This indicates the number of priming fetches performed by the resolver.
.. _resolver_rtt_stats:
Resolver Queries Response Time counters
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
:iscman:`named` provides query response round-trip time (RTT) counters
(histogram) both for incoming and outgoing queries in milliseconds. Response
times which are lower than 1ms are calculated under the ``~0`` counter.
Response times from 1ms to 15ms are calculated under their own counters, e.g. a
response that took 5ms to complete is calculated under the ``5`` counter.
Response times starting from 16ms are calculated under the ``MinMS-MaxMS``
(inclusive) range counters. For example, a response that took 18ms to complete
is calculated under the ``18-19`` counter, and a response that took 550ms to
complete is calculated under the ``512-575`` counter.
.. _socket_stats:
Socket I/O Statistics Counters

View file

@ -49,6 +49,7 @@
#include <netinet/in.h>
#include <stdbool.h>
#include <isc/histo.h>
#include <isc/loop.h>
#include <isc/refcount.h>
#include <isc/stats.h>
@ -143,21 +144,6 @@ enum {
DNS_FETCHOPT_EDNSVERSIONMASK = 0xff000000,
};
/*
* Upper bounds of class of query RTT (ms). Corresponds to
* dns_resstatscounter_queryrttX statistics counters.
*/
#define DNS_RESOLVER_QRYRTTCLASS0 10
#define DNS_RESOLVER_QRYRTTCLASS0STR "10"
#define DNS_RESOLVER_QRYRTTCLASS1 100
#define DNS_RESOLVER_QRYRTTCLASS1STR "100"
#define DNS_RESOLVER_QRYRTTCLASS2 500
#define DNS_RESOLVER_QRYRTTCLASS2STR "500"
#define DNS_RESOLVER_QRYRTTCLASS3 800
#define DNS_RESOLVER_QRYRTTCLASS3STR "800"
#define DNS_RESOLVER_QRYRTTCLASS4 1600
#define DNS_RESOLVER_QRYRTTCLASS4STR "1600"
/*
* XXXRTH Should this API be made semi-private? (I.e.
* _dns_resolver_create()).
@ -586,8 +572,7 @@ dns_resolver_setstats(dns_resolver_t *res, isc_stats_t *stats);
*
* Requires:
* \li 'res' is valid.
*
*\li stats is a valid statistics supporting resolver statistics counters
* \li stats is a valid statistics supporting resolver statistics counters
* (see dns/stats.h).
*/
@ -600,8 +585,7 @@ dns_resolver_getstats(dns_resolver_t *res, isc_stats_t **statsp);
*
* Requires:
* \li 'res' is valid.
*
*\li 'statsp' != NULL && '*statsp' != NULL
* \li 'statsp' != NULL && '*statsp' != NULL
*/
void
@ -623,8 +607,7 @@ dns_resolver_setquerystats(dns_resolver_t *res, dns_stats_t *stats);
*
* Requires:
* \li 'res' is valid.
*
*\li stats is a valid statistics created by dns_rdatatypestats_create().
* \li 'stats' is a valid statistics created by dns_rdatatypestats_create().
*/
void
@ -636,8 +619,36 @@ dns_resolver_getquerystats(dns_resolver_t *res, dns_stats_t **statsp);
*
* Requires:
* \li 'res' is valid.
* \li 'statsp' != NULL && '*statsp' != NULL
*/
void
dns_resolver_setqueryrttstats(dns_resolver_t *res, isc_histomulti_t *hmin,
isc_histomulti_t *hmout);
/*%<
* Set a query RTT statistics histograms 'hmin' and 'hmout' for 'res'. Once the
* statistic histograms are installed, the resolver will start updating them
* with the incoming and outgoing queries' RTT values accordingly.
*
*\li 'statsp' != NULL && '*statsp' != NULL
* Requires:
* \li 'res' is valid.
* \li 'stats' is a valid statistics created by dns_rdatatypestats_create().
* \li 'hmin' is a valid isc_histomulti_t object.
* \li 'hmout' is a valid isc_histomulti_t object.
*/
void
dns_resolver_getqueryrttstats(dns_resolver_t *res, isc_histomulti_t **hmpin,
isc_histomulti_t **hmpout);
/*%<
* Get the query RTT statistics histograms for 'res'. If the histograms are set
* then the corresponding '*hmp{in,out}' are attached to them; otherwise,
* '*hmp{in,out}' are untouched.
*
* Requires:
* \li 'res' is valid.
* \li 'hmpin' == NULL || '*hmpin' == NULL
* \li 'hmpout' == NULL || '*hmpout' == NULL
*/
void

View file

@ -19,6 +19,7 @@
#include <isc/histo.h>
#include <dns/resolver.h>
#include <dns/types.h>
/*%
@ -52,30 +53,24 @@ enum {
dns_resstatscounter_dispabort = 21,
dns_resstatscounter_dispsockfail = 22,
dns_resstatscounter_querytimeout = 23,
dns_resstatscounter_queryrtt0 = 24,
dns_resstatscounter_queryrtt1 = 25,
dns_resstatscounter_queryrtt2 = 26,
dns_resstatscounter_queryrtt3 = 27,
dns_resstatscounter_queryrtt4 = 28,
dns_resstatscounter_queryrtt5 = 29,
dns_resstatscounter_nfetch = 30,
dns_resstatscounter_disprequdp = 31,
dns_resstatscounter_dispreqtcp = 32,
dns_resstatscounter_buckets = 33,
dns_resstatscounter_refused = 34,
dns_resstatscounter_cookienew = 35,
dns_resstatscounter_cookieout = 36,
dns_resstatscounter_cookiein = 37,
dns_resstatscounter_cookieok = 38,
dns_resstatscounter_badvers = 39,
dns_resstatscounter_badcookie = 40,
dns_resstatscounter_zonequota = 41,
dns_resstatscounter_serverquota = 42,
dns_resstatscounter_clientquota = 43,
dns_resstatscounter_nextitem = 44,
dns_resstatscounter_priming = 45,
dns_resstatscounter_forwardonlyfail = 46,
dns_resstatscounter_max = 47,
dns_resstatscounter_nfetch = 24,
dns_resstatscounter_disprequdp = 25,
dns_resstatscounter_dispreqtcp = 26,
dns_resstatscounter_buckets = 27,
dns_resstatscounter_refused = 28,
dns_resstatscounter_cookienew = 29,
dns_resstatscounter_cookieout = 30,
dns_resstatscounter_cookiein = 31,
dns_resstatscounter_cookieok = 32,
dns_resstatscounter_badvers = 33,
dns_resstatscounter_badcookie = 34,
dns_resstatscounter_zonequota = 35,
dns_resstatscounter_serverquota = 36,
dns_resstatscounter_clientquota = 37,
dns_resstatscounter_nextitem = 38,
dns_resstatscounter_priming = 39,
dns_resstatscounter_forwardonlyfail = 40,
dns_resstatscounter_max = 41,
/*
* DNSSEC stats.
@ -203,6 +198,24 @@ enum {
dns_sizecounter_out_max = DNS_SIZEHISTO_MAXOUT + 1,
};
/*
* This gives enough amount of buckets in the lower end of the values (which
* are the values up to about 30000 milliseconds (MAXIMUM_QUERY_TIMEOUT) to make
* sense for the resolver) to be useful and not to be too many. E.g. bucket
* number 30 covers values between 56 and 59, while bucket number 102 covers the
* values between 28672 and 30719.
*/
#define DNS_RTTHISTO_SIGBITS 3
#define DNS_RTTHISTO_MAX 102
/*
* For consistency with other stats counters
*/
enum {
dns_queryrttcounter_in_max = DNS_RTTHISTO_MAX + 1,
dns_queryrttcounter_out_max = DNS_RTTHISTO_MAX + 1,
};
/*%
* Attributes for statistics counters of RRset and Rdatatype types.
*

View file

@ -25,6 +25,7 @@
#include <isc/hash.h>
#include <isc/hashmap.h>
#include <isc/hex.h>
#include <isc/histo.h>
#include <isc/list.h>
#include <isc/log.h>
#include <isc/loop.h>
@ -207,7 +208,11 @@
#define DEFAULT_QUERY_TIMEOUT (MAX_SINGLE_QUERY_TIMEOUT + 1000U)
#endif /* ifndef DEFAULT_QUERY_TIMEOUT */
/* The maximum time in seconds for the whole query to live. */
/*
* The maximum time in seconds for the whole query to live.
*
* Note: if increased, DNS_RTTHISTO_MAX should also be updated.
*/
#ifndef MAXIMUM_QUERY_TIMEOUT
#define MAXIMUM_QUERY_TIMEOUT 30000
#endif /* ifndef MAXIMUM_QUERY_TIMEOUT */
@ -598,6 +603,8 @@ struct dns_resolver {
isc_result_t quotaresp[2];
isc_stats_t *stats;
dns_stats_t *querystats;
isc_histomulti_t *queryinrttstats;
isc_histomulti_t *queryoutrttstats;
/* Additions for serve-stale feature. */
unsigned int retryinterval; /* in milliseconds */
@ -1255,31 +1262,17 @@ fctx_cancelquery(resquery_t **queryp, isc_time_t *finish, bool no_response,
* We have both the start and finish times for this
* packet, so we can compute a real RTT.
*/
unsigned int rttms;
rtt = (unsigned int)isc_time_microdiff(finish,
&query->start);
rttms = rtt / US_PER_MS;
factor = DNS_ADB_RTTADJDEFAULT;
if (rttms < DNS_RESOLVER_QRYRTTCLASS0) {
inc_stats(fctx->res,
dns_resstatscounter_queryrtt0);
} else if (rttms < DNS_RESOLVER_QRYRTTCLASS1) {
inc_stats(fctx->res,
dns_resstatscounter_queryrtt1);
} else if (rttms < DNS_RESOLVER_QRYRTTCLASS2) {
inc_stats(fctx->res,
dns_resstatscounter_queryrtt2);
} else if (rttms < DNS_RESOLVER_QRYRTTCLASS3) {
inc_stats(fctx->res,
dns_resstatscounter_queryrtt3);
} else if (rttms < DNS_RESOLVER_QRYRTTCLASS4) {
inc_stats(fctx->res,
dns_resstatscounter_queryrtt4);
} else {
inc_stats(fctx->res,
dns_resstatscounter_queryrtt5);
if (fctx->res->queryoutrttstats != NULL) {
const unsigned int rttms = rtt / US_PER_MS;
isc_histomulti_inc(
fctx->res->queryoutrttstats,
rttms < MAXIMUM_QUERY_TIMEOUT
? rttms
: MAXIMUM_QUERY_TIMEOUT);
}
} else {
uint32_t value;
@ -9642,6 +9635,12 @@ dns_resolver__destroy(dns_resolver_t *res) {
dns_nametree_detach(&res->algorithms);
dns_nametree_detach(&res->digests);
if (res->queryoutrttstats != NULL) {
isc_histomulti_detach(&res->queryoutrttstats);
}
if (res->queryinrttstats != NULL) {
isc_histomulti_detach(&res->queryinrttstats);
}
if (res->querystats != NULL) {
dns_stats_detach(&res->querystats);
}
@ -10884,6 +10883,32 @@ dns_resolver_getquerystats(dns_resolver_t *res, dns_stats_t **statsp) {
}
}
void
dns_resolver_setqueryrttstats(dns_resolver_t *res, isc_histomulti_t *hmin,
isc_histomulti_t *hmout) {
REQUIRE(VALID_RESOLVER(res));
REQUIRE(res->queryinrttstats == NULL);
REQUIRE(res->queryoutrttstats == NULL);
isc_histomulti_attach(hmin, &res->queryinrttstats);
isc_histomulti_attach(hmout, &res->queryoutrttstats);
}
void
dns_resolver_getqueryrttstats(dns_resolver_t *res, isc_histomulti_t **hmpin,
isc_histomulti_t **hmpout) {
REQUIRE(VALID_RESOLVER(res));
REQUIRE(hmpin == NULL || *hmpin == NULL);
REQUIRE(hmpout == NULL || *hmpout == NULL);
if (hmpin != NULL && res->queryinrttstats != NULL) {
isc_histomulti_attach(res->queryinrttstats, hmpin);
}
if (hmpout != NULL && res->queryoutrttstats != NULL) {
isc_histomulti_attach(res->queryoutrttstats, hmpout);
}
}
void
dns_resolver_freefresp(dns_fetchresponse_t **frespp) {
REQUIRE(frespp != NULL);

View file

@ -74,6 +74,7 @@ struct isc_histo {
struct isc_histomulti {
uint magic;
uint size;
isc_refcount_t references;
isc_histo_t *hg[];
};
@ -386,22 +387,23 @@ isc_histomulti_create(isc_mem_t *mctx, uint sigbits, isc_histomulti_t **hmp) {
isc_histo_create(mctx, sigbits, &hm->hg[i]);
}
isc_refcount_init(&hm->references, 1);
*hmp = hm;
}
void
isc_histomulti_destroy(isc_histomulti_t **hmp) {
REQUIRE(hmp != NULL);
REQUIRE(HISTOMULTI_VALID(*hmp));
static void
isc__histomulti_destroy(isc_histomulti_t *hm) {
REQUIRE(HISTOMULTI_VALID(hm));
isc_histomulti_t *hm = *hmp;
isc_mem_t *mctx = hm->hg[0]->mctx;
*hmp = NULL;
for (uint i = 0; i < hm->size; i++) {
isc_histo_destroy(&hm->hg[i]);
}
isc_refcount_destroy(&hm->references);
isc_mem_put(mctx, hm, STRUCT_FLEX_SIZE(hm, hg, hm->size));
}
@ -426,6 +428,12 @@ isc_histomulti_inc(isc_histomulti_t *hm, uint64_t value) {
isc_histomulti_add(hm, value, 1);
}
#ifdef ISC_HISTO_TRACE
ISC_REFCOUNT_TRACE_IMPL(isc_histomulti, isc__histomulti_destroy);
#else
ISC_REFCOUNT_IMPL(isc_histomulti, isc__histomulti_destroy);
#endif /* ISC_HISTO_TRACE */
/**********************************************************************/
/*

View file

@ -278,20 +278,6 @@ isc_histomulti_create(isc_mem_t *mctx, uint sigbits, isc_histomulti_t **hmp);
*\li `*hmp` is a pointer to a multithreaded sharded histogram.
*/
void
isc_histomulti_destroy(isc_histomulti_t **hmp);
/*%<
* Destroy a multithreaded sharded histogram
*
* Requires:
*\li `hmp != NULL`
*\li `*hmp` is a pointer to a valid multithreaded sharded histogram
*
* Ensures:
*\li all memory allocated by the histogram has been released
*\li `*hmp == NULL`
*/
void
isc_histomulti_merge(isc_histo_t **targetp, const isc_histomulti_t *source);
/*%<
@ -326,6 +312,21 @@ isc_histomulti_add(isc_histomulti_t *hm, uint64_t value, uint64_t inc);
*\li `hm` is a pointer to a valid histomulti
*/
#ifdef ISC_HISTO_TRACE
#define isc_histomulti_ref(ptr) \
dns_histomulti__ref(ptr, __func__, __FILE__, __LINE__)
#define isc_histomulti_unref(ptr) \
isc_histomulti__unref(ptr, __func__, __FILE__, __LINE__)
#define isc_histomulti_attach(ptr, ptrp) \
isc_histomulti__attach(ptr, ptrp, __func__, __FILE__, __LINE__)
#define isc_histomulti_detach(ptrp) \
isc_histomulti__detach(ptrp, __func__, __FILE__, __LINE__)
ISC_REFCOUNT_TRACE_DECL(isc_histomulti);
#else
ISC_REFCOUNT_DECL(isc_histomulti);
#endif /* ISC_HISTO_TRACE */
/**********************************************************************/
void

View file

@ -325,7 +325,24 @@ client_senddone(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) {
*/
client->inner.sendhandle = NULL;
if (result != ISC_R_SUCCESS) {
if (result == ISC_R_SUCCESS) {
isc_histomulti_t *hmpin = NULL;
if (client->inner.view != NULL &&
client->inner.view->resolver != NULL)
{
dns_resolver_getqueryrttstats(
client->inner.view->resolver, &hmpin, NULL);
}
if (hmpin != NULL) {
const unsigned int rtt = (unsigned int)
isc_time_microdiff(&client->inner.tnow,
&client->inner.requesttime);
const unsigned int rttms = rtt / US_PER_MS;
isc_histomulti_inc(hmpin, rttms);
isc_histomulti_detach(&hmpin);
}
} else {
if (!TCP_CLIENT(client) && result == ISC_R_MAXSIZE) {
ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(3),

View file

@ -2703,7 +2703,8 @@ stale_refresh_aftermath(ns_client_t *client, isc_result_t result) {
* database, starting the stale-refresh-time window for it.
* This is a condensed form of query_lookup().
*/
client->inner.now = isc_stdtime_now();
client->inner.tnow = isc_time_now();
client->inner.now = isc_time_seconds(&client->inner.tnow);
client->query.attributes &= ~NS_QUERYATTR_RECURSIONOK;
qctx_init(client, NULL, 0, &qctx);
@ -6076,7 +6077,8 @@ fetch_callback(void *arg) {
/*
* Update client->now.
*/
client->inner.now = isc_stdtime_now();
client->inner.tnow = isc_time_now();
client->inner.now = isc_time_seconds(&client->inner.tnow);
} else {
/*
* This is a fetch completion event for a canceled fetch.
@ -6538,7 +6540,8 @@ query_hookresume(void *arg) {
INSIST(rev->ctx == client->query.hookasyncctx);
client->query.hookasyncctx = NULL;
canceled = false;
client->inner.now = isc_stdtime_now();
client->inner.tnow = isc_time_now();
client->inner.now = isc_time_seconds(&client->inner.tnow);
} else {
canceled = true;
}

View file

@ -176,29 +176,29 @@ ns_server_detach(ns_server_t **sctxp) {
}
if (sctx->udpinstats4 != NULL) {
isc_histomulti_destroy(&sctx->udpinstats4);
isc_histomulti_detach(&sctx->udpinstats4);
}
if (sctx->tcpinstats4 != NULL) {
isc_histomulti_destroy(&sctx->tcpinstats4);
isc_histomulti_detach(&sctx->tcpinstats4);
}
if (sctx->udpoutstats4 != NULL) {
isc_histomulti_destroy(&sctx->udpoutstats4);
isc_histomulti_detach(&sctx->udpoutstats4);
}
if (sctx->tcpoutstats4 != NULL) {
isc_histomulti_destroy(&sctx->tcpoutstats4);
isc_histomulti_detach(&sctx->tcpoutstats4);
}
if (sctx->udpinstats6 != NULL) {
isc_histomulti_destroy(&sctx->udpinstats6);
isc_histomulti_detach(&sctx->udpinstats6);
}
if (sctx->tcpinstats6 != NULL) {
isc_histomulti_destroy(&sctx->tcpinstats6);
isc_histomulti_detach(&sctx->tcpinstats6);
}
if (sctx->udpoutstats6 != NULL) {
isc_histomulti_destroy(&sctx->udpoutstats6);
isc_histomulti_detach(&sctx->udpoutstats6);
}
if (sctx->tcpoutstats6 != NULL) {
isc_histomulti_destroy(&sctx->tcpoutstats6);
isc_histomulti_detach(&sctx->tcpoutstats6);
}
sctx->magic = 0;