+1891. [func] Limit the number of recursive clients that can be
+ waiting for a single query (<qname,qtype,qclass>) to
+ resolve. New options clients-per-query and
+ max-clients-per-query.
+
1890. [func] Add a system test for named-checkconf. [RT #14931]
1889. [func] The lame cache is now done on a <qname,qclass,qtype>
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: config.c,v 1.57 2005/05/19 04:59:00 marka Exp $ */
+/* $Id: config.c,v 1.58 2005/06/27 00:15:41 marka Exp $ */
/*! \file */
max-acache-size 0;\n\
dnssec-enable no; /* Make yes for 9.4. */ \n\
integrity-check yes;\n\
+ clients-per-query 10;\n\
+ max-clients-per-query 100;\n\
"
" /* zone */\n\
- PERFORMANCE OF THIS SOFTWARE.
-->
-<!-- $Id: named.conf.docbook,v 1.12 2005/06/07 00:27:31 marka Exp $ -->
+<!-- $Id: named.conf.docbook,v 1.13 2005/06/27 00:15:41 marka Exp $ -->
<refentry>
<refentryinfo>
<date>Aug 13, 2004</date>
max-cache-ttl <replaceable>integer</replaceable>;
transfer-format ( many-answers | one-answer );
max-cache-size <replaceable>size_no_default</replaceable>;
+ max-acache-size <replaceable>size_no_default</replaceable>;
+ clients-per-query <replaceable>number</replaceable>;
+ max-clients-per-query <replaceable>number</replaceable>;
check-names ( master | slave | response )
( fail | warn | ignore );
check-mx ( fail | warn | ignore );
max-cache-ttl <replaceable>integer</replaceable>;
transfer-format ( many-answers | one-answer );
max-cache-size <replaceable>size_no_default</replaceable>;
+ max-acache-size <replaceable>size_no_default</replaceable>;
+ clients-per-query <replaceable>number</replaceable>;
+ max-clients-per-query <replaceable>number</replaceable>;
check-names ( master | slave | response )
( fail | warn | ignore );
check-mx ( fail | warn | ignore );
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: query.c,v 1.267 2005/06/17 01:58:21 marka Exp $ */
+/* $Id: query.c,v 1.268 2005/06/27 00:15:42 marka Exp $ */
/*! \file */
query_next(ns_client_t *client, isc_result_t result) {
if (result == DNS_R_DUPLICATE)
inc_stats(client, dns_statscounter_duplicate);
+ else if (result == DNS_R_DROP)
+ inc_stats(client, dns_statscounter_dropped);
else
inc_stats(client, dns_statscounter_failure);
ns_client_next(client, result);
if (result == ISC_R_SUCCESS)
client->query.attributes |=
NS_QUERYATTR_RECURSING;
- else if (result == DNS_R_DUPLICATE) {
+ else if (result == DNS_R_DUPLICATE ||
+ result == DNS_R_DROP) {
/* Duplicate query. */
QUERY_ERROR(result);
} else {
if (result == ISC_R_SUCCESS)
client->query.attributes |=
NS_QUERYATTR_RECURSING;
- else if (result == DNS_R_DUPLICATE)
+ else if (result == DNS_R_DUPLICATE ||
+ result == DNS_R_DROP)
QUERY_ERROR(result);
else
QUERY_ERROR(DNS_R_SERVFAIL);
if (eresult != ISC_R_SUCCESS &&
(!PARTIALANSWER(client) || WANTRECURSION(client))) {
- if (eresult == DNS_R_DUPLICATE) {
+ if (eresult == DNS_R_DUPLICATE || eresult == DNS_R_DROP) {
/*
* This was a duplicate query that we are
* recursing on. Don't send a response now.
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: server.c,v 1.444 2005/06/07 01:52:51 marka Exp $ */
+/* $Id: server.c,v 1.445 2005/06/27 00:15:42 marka Exp $ */
/*! \file */
dns_order_t *order = NULL;
isc_uint32_t udpsize;
unsigned int check = 0;
+ isc_uint32_t max_clients_per_query;
REQUIRE(DNS_VIEW_VALID(view));
result = ns_config_get(maps, "provide-ixfr", &obj);
INSIST(result == ISC_R_SUCCESS);
view->provideixfr = cfg_obj_asboolean(obj);
+
+ obj = NULL;
+ result = ns_config_get(maps, "max-clients-per-query", &obj);
+ INSIST(result == ISC_R_SUCCESS);
+ max_clients_per_query = cfg_obj_asuint32(obj);
+
+ obj = NULL;
+ result = ns_config_get(maps, "clients-per-query", &obj);
+ INSIST(result == ISC_R_SUCCESS);
+ dns_resolver_setclientsperquery(view->resolver,
+ cfg_obj_asuint32(obj),
+ max_clients_per_query);
obj = NULL;
result = ns_config_get(maps, "dnssec-enable", &obj);
- PERFORMANCE OF THIS SOFTWARE.
-->
-<!-- File: $Id: Bv9ARM-book.xml,v 1.273 2005/06/20 01:11:57 marka Exp $ -->
+<!-- File: $Id: Bv9ARM-book.xml,v 1.274 2005/06/27 00:15:42 marka Exp $ -->
<book>
<title>BIND 9 Administrator Reference Manual</title>
</listitem>
</varlistentry>
+
+ <varlistentry>
+ <term><command>clients-per-query</command></term>
+ <term><command>max-clients-per-query</command></term>
+ <listitem>
+ <para><command>clients-per-query</command>
+ and <command>max-clients-per-query</command> set the
+ initial value (minimum) and maximum number of recursive
+ simultanious clients for any given query
+ (<qname,qtype,qclass>) that the server will accept
+ before dropping additional clients. named will attempt to
+ self tune this value and changes will be logged. The
+ default values are 10 and 100.
+ </para>
+ <para>
+ This value should reflect how many queries come in for
+ a given name in the time it takes to resolve that name.
+ If the number of queries exceed this value named will
+ assume that it is dealing with a non-responsive zone
+ and will drop additional queries. If it gets a response
+ after dropping queries it will raise the estimate. The
+ estimate will then be lowered in 20 minutes if it has
+ remained unchanged.
+ </para>
+ <para>
+ If <command>clients-per-query</command> is set to zero
+ then there is no limit on the number of clients per query
+ and no queries will be dropped.
+ </para>
+ <para>
+ If <command>max-clients-per-query</command> is set to zero
+ then there is no upper bound other than imposed by
+ <command>recurive-clients</command>.
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
</sect3>
<optional> use-additional-cache <replaceable>yes_or_no</replaceable> ; </optional>
<optional> acache-cleaning-interval <replaceable>number</replaceable>; </optional>
<optional> max-acache-size <replaceable>size_spec</replaceable> ; </optional>
+ <optional> clients-per-query <replaceable>number</replaceable> ; </optional>
+ <optional> max-clients-per-query <replaceable>number</replaceable> ; </optional>
<optional> masterfile-format (<constant>text</constant>|<constant>raw</constant>) ; </optional>
};
</programlisting>
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: resolver.h,v 1.46 2005/06/17 01:58:23 marka Exp $ */
+/* $Id: resolver.h,v 1.47 2005/06/27 00:15:44 marka Exp $ */
#ifndef DNS_RESOLVER_H
#define DNS_RESOLVER_H 1
*
*\li #ISC_R_SUCCESS Success
*\li #DNS_R_DUPLICATE
+ *\li #DNS_R_DROP
*
*\li Many other values are possible, all of which indicate failure.
*/
isc_boolean_t
dns_resolver_getmustbesecure(dns_resolver_t *resolver, dns_name_t *name);
+void
+dns_resolver_setclientsperquery(dns_resolver_t *resolver,
+ isc_uint32_t min, isc_uint32_t max);
+
+void
+dns_resolver_getclientsperquery(dns_resolver_t *resolver, isc_uint32_t *cur,
+ isc_uint32_t *min, isc_uint32_t *max);
ISC_LANG_ENDDECLS
#endif /* DNS_RESOLVER_H */
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: stats.h,v 1.8 2005/06/17 01:58:23 marka Exp $ */
+/* $Id: stats.h,v 1.9 2005/06/27 00:15:44 marka Exp $ */
#ifndef DNS_STATS_H
#define DNS_STATS_H 1
dns_statscounter_nxdomain = 3, /*%< NXDOMAIN result */
dns_statscounter_recursion = 4, /*%< Recursion was used */
dns_statscounter_failure = 5, /*%< Some other failure */
- dns_statscounter_duplicate = 6 /*%< Duplicate query */
+ dns_statscounter_duplicate = 6, /*%< Duplicate query */
+ dns_statscounter_dropped = 7 /*%< Duplicate query */
} dns_statscounter_t;
-#define DNS_STATS_NCOUNTERS 7
+#define DNS_STATS_NCOUNTERS 8
LIBDNS_EXTERNAL_DATA extern const char *dns_statscounter_names[];
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: resolver.c,v 1.313 2005/06/23 06:12:56 marka Exp $ */
+/* $Id: resolver.c,v 1.314 2005/06/27 00:15:43 marka Exp $ */
/*! \file */
fetchstate state;
isc_boolean_t want_shutdown;
isc_boolean_t cloned;
+ isc_boolean_t spilled;
unsigned int references;
isc_event_t control_event;
ISC_LINK(struct fetchctx) link;
isc_rwlock_t mbslock;
#endif
dns_rbt_t * mustbesecure;
+ unsigned int spillatmax;
+ unsigned int spillatmin;
+ isc_timer_t * spillattimer;
/* Locked by lock. */
unsigned int references;
isc_boolean_t exiting;
isc_eventlist_t whenshutdown;
unsigned int activebuckets;
isc_boolean_t priming;
+ unsigned int spillat;
/* Locked by primelock. */
dns_fetch_t * primefetch;
/* Locked by nlock. */
* no further idle events are delivered.
*/
return (isc_timer_reset(fctx->timer, isc_timertype_once,
- &fctx->expires, NULL,
- ISC_TRUE));
+ &fctx->expires, NULL, ISC_TRUE));
}
static inline void
fctx_sendevents(fetchctx_t *fctx, isc_result_t result) {
dns_fetchevent_t *event, *next_event;
isc_task_t *task;
+ unsigned int count = 0;
+ isc_interval_t i;
+ isc_boolean_t logit = ISC_FALSE;
/*
* Caller must be holding the appropriate bucket lock.
fctx->type == dns_rdatatype_rrsig);
isc_task_sendanddetach(&task, ISC_EVENT_PTR(&event));
+ count++;
+ }
+
+ if ((fctx->attributes & FCTX_ATTR_HAVEANSWER) != 0 &&
+ fctx->spilled &&
+ (count < fctx->res->spillatmax || fctx->res->spillatmax == 0)) {
+ LOCK(&fctx->res->lock);
+ if (count == fctx->res->spillat && !fctx->res->exiting) {
+ fctx->res->spillat += 5;
+ if (fctx->res->spillat > fctx->res->spillatmax &&
+ fctx->res->spillatmax != 0)
+ fctx->res->spillat = fctx->res->spillatmax;
+ isc_interval_set(&i, 20 * 60, 0);
+ result = isc_timer_reset(fctx->res->spillattimer,
+ isc_timertype_ticker, NULL,
+ &i, ISC_TRUE);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
+ logit = ISC_TRUE;
+ }
+ UNLOCK(&fctx->res->lock);
+ if (logit)
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,
+ DNS_LOGMODULE_RESOLVER, ISC_LOG_NOTICE,
+ "clients-per-query increased to %u",
+ count + 1);
}
}
fctx->restarts = 0;
fctx->timeouts = 0;
fctx->attributes = 0;
+ fctx->spilled = ISC_FALSE;
dns_name_init(&fctx->nsname, NULL);
fctx->nsfetch = NULL;
#if USE_MBSLOCK
isc_rwlock_destroy(&res->mbslock);
#endif
+ isc_timer_detach(&res->spillattimer);
res->magic = 0;
isc_mem_put(res->mctx, res, sizeof(*res));
}
UNLOCK(&res->lock);
}
+static void
+spillattimer_countdown(isc_task_t *task, isc_event_t *event) {
+ dns_resolver_t *res = event->ev_arg;
+ isc_result_t result;
+ unsigned int count;
+ isc_boolean_t logit = ISC_FALSE;
+
+ REQUIRE(VALID_RESOLVER(res));
+
+ UNUSED(task);
+
+ LOCK(&res->lock);
+ INSIST(!res->exiting);
+ if (res->spillat > res->spillatmin) {
+ res->spillat--;
+ logit = ISC_TRUE;
+ }
+ if (res->spillat <= res->spillatmin) {
+ result = isc_timer_reset(res->spillattimer,
+ isc_timertype_inactive, NULL,
+ NULL, ISC_TRUE);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
+ }
+ count = res->spillat;
+ UNLOCK(&res->lock);
+ if (logit)
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,
+ DNS_LOGMODULE_RESOLVER, ISC_LOG_NOTICE,
+ "clients-per-query decreased to %u", count);
+}
+
isc_result_t
dns_resolver_create(dns_view_t *view,
isc_taskmgr_t *taskmgr, unsigned int ntasks,
isc_socketmgr_t *socketmgr,
- isc_timermgr_t *timermgr,
+ isc_timermgr_t *timermgr,
unsigned int options,
dns_dispatchmgr_t *dispatchmgr,
dns_dispatch_t *dispatchv4,
dns_resolver_t *res;
isc_result_t result = ISC_R_SUCCESS;
unsigned int i, buckets_created = 0;
+ isc_task_t *task = NULL;
char name[16];
/*
res->udpsize = RECV_BUFFER_SIZE;
res->algorithms = NULL;
res->mustbesecure = NULL;
+ res->spillatmin = res->spillat = 10;
+ res->spillatmax = 100;
+ res->spillattimer = NULL;
res->nbuckets = ntasks;
res->activebuckets = ntasks;
if (result != ISC_R_SUCCESS)
goto cleanup_nlock;
+ task = NULL;
+ result = isc_task_create(taskmgr, 0, &task);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_primelock;
+
+ result = isc_timer_create(timermgr, isc_timertype_inactive, NULL, NULL,
+ task, spillattimer_countdown, res,
+ &res->spillattimer);
+ isc_task_detach(&task);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_primelock;
+
#if USE_ALGLOCK
result = isc_rwlock_init(&res->alglock, 0, 0);
if (result != ISC_R_SUCCESS)
- goto cleanup_primelock;
+ goto cleanup_spillattimer;
#endif
#if USE_MBSLOCK
result = isc_rwlock_init(&res->mbslock, 0, 0);
#endif
#endif
#if USE_ALGLOCK || USE_MBSLOCK
+ cleanup_spillattimer:
+ isc_timer_detach(&res->spillattimer);
+#endif
+
cleanup_primelock:
DESTROYLOCK(&res->primelock);
-#endif
cleanup_nlock:
DESTROYLOCK(&res->nlock);
unsigned int i;
fetchctx_t *fctx;
isc_socket_t *sock;
+ isc_result_t result;
REQUIRE(VALID_RESOLVER(res));
}
if (res->activebuckets == 0)
send_shutdown_events(res);
+ result = isc_timer_reset(res->spillattimer,
+ isc_timertype_inactive, NULL,
+ NULL, ISC_TRUE);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
}
UNLOCK(&res->lock);
{
dns_fetch_t *fetch;
fetchctx_t *fctx = NULL;
- isc_result_t result;
+ isc_result_t result = ISC_R_SUCCESS;
unsigned int bucketnum;
isc_boolean_t new_fctx = ISC_FALSE;
isc_event_t *event;
+ unsigned int count = 0;
UNUSED(forwarders);
result = DNS_R_DUPLICATE;
goto unlock;
}
+ count++;
+ }
+ }
+ if (count >= res->spillatmin && res->spillatmin != 0) {
+ if (!fctx->spilled) {
+ LOCK(&fctx->res->lock);
+ if (count >= res->spillat)
+ fctx->spilled = ISC_TRUE;
+ UNLOCK(&fctx->res->lock);
+ }
+ if (fctx->spilled) {
+ result = DNS_R_DROP;
+ goto unlock;
}
}
#endif
return (value);
}
+
+void
+dns_resolver_getclientsperquery(dns_resolver_t *resolver, isc_uint32_t *cur,
+ isc_uint32_t *min, isc_uint32_t *max)
+{
+ REQUIRE(VALID_RESOLVER(resolver));
+
+ LOCK(&resolver->lock);
+ if (cur != NULL)
+ *cur = resolver->spillat;
+ if (min != NULL)
+ *min = resolver->spillatmin;
+ if (max != NULL)
+ *max = resolver->spillatmax;
+ UNLOCK(&resolver->lock);
+}
+
+void
+dns_resolver_setclientsperquery(dns_resolver_t *resolver, isc_uint32_t min,
+ isc_uint32_t max)
+{
+ REQUIRE(VALID_RESOLVER(resolver));
+
+ LOCK(&resolver->lock);
+ resolver->spillatmin = resolver->spillat = min;
+ resolver->spillatmax = max;
+ UNLOCK(&resolver->lock);
+}
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: stats.c,v 1.9 2005/06/17 01:58:22 marka Exp $ */
+/* $Id: stats.c,v 1.10 2005/06/27 00:15:44 marka Exp $ */
/*! \file */
"nxdomain",
"recursion",
"failure",
- "duplicate"
+ "duplicate",
+ "dropped"
};
isc_result_t
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: namedconf.c,v 1.52 2005/06/20 01:03:55 marka Exp $ */
+/* $Id: namedconf.c,v 1.53 2005/06/27 00:15:45 marka Exp $ */
/*! \file */
{ "use-additional-cache", &cfg_type_boolean, 0 },
{ "acache-cleaning-interval", &cfg_type_uint32, 0 },
{ "max-acache-size", &cfg_type_sizenodefault, 0 },
+ { "clients-per-query", &cfg_type_uint32, 0 },
+ { "max-clients-per-query", &cfg_type_uint32, 0 },
{ NULL, NULL, 0 }
};