Commit 0af500a2 authored by Witold Krecicki's avatar Witold Krecicki Committed by Witold Krecicki

- Make isc_quota use atomics instead of locks

- Use getters for isc_quota parameters, make fields private
- Fix a potential data race with recursion clients limits logging
parent 814bfa23
...@@ -8022,6 +8022,7 @@ load_configuration(const char *filename, named_server_t *server, ...@@ -8022,6 +8022,7 @@ load_configuration(const char *filename, named_server_t *server,
ns_altsecretlist_t altsecrets, tmpaltsecrets; ns_altsecretlist_t altsecrets, tmpaltsecrets;
unsigned int maxsocks; unsigned int maxsocks;
uint32_t softquota = 0; uint32_t softquota = 0;
uint32_t max;
unsigned int initial, idle, keepalive, advertised; unsigned int initial, idle, keepalive, advertised;
dns_aclenv_t *env = dns_aclenv_t *env =
ns_interfacemgr_getaclenv(named_g_server->interfacemgr); ns_interfacemgr_getaclenv(named_g_server->interfacemgr);
...@@ -8214,20 +8215,20 @@ load_configuration(const char *filename, named_server_t *server, ...@@ -8214,20 +8215,20 @@ load_configuration(const char *filename, named_server_t *server,
configure_server_quota(maps, "recursive-clients", configure_server_quota(maps, "recursive-clients",
&server->sctx->recursionquota); &server->sctx->recursionquota);
if (server->sctx->recursionquota.max > 1000) { max = isc_quota_getmax(&server->sctx->recursionquota);
int margin = ISC_MAX(100, named_g_cpus + 1); if (max > 1000) {
if (margin > server->sctx->recursionquota.max - 100) { unsigned margin = ISC_MAX(100, named_g_cpus + 1);
if (margin + 100 > max) {
isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
"'recursive-clients %d' too low when " "'recursive-clients %d' too low when "
"running with %d worker threads", "running with %d worker threads",
server->sctx->recursionquota.max, max, named_g_cpus);
named_g_cpus);
CHECK(ISC_R_RANGE); CHECK(ISC_R_RANGE);
} }
softquota = server->sctx->recursionquota.max - margin; softquota = max - margin;
} else { } else {
softquota = (server->sctx->recursionquota.max * 90) / 100; softquota = (max * 90) / 100;
} }
isc_quota_soft(&server->sctx->recursionquota, softquota); isc_quota_soft(&server->sctx->recursionquota, softquota);
...@@ -11452,13 +11453,14 @@ named_server_status(named_server_t *server, isc_buffer_t **text) { ...@@ -11452,13 +11453,14 @@ named_server_status(named_server_t *server, isc_buffer_t **text) {
CHECK(putstr(text, line)); CHECK(putstr(text, line));
snprintf(line, sizeof(line), "recursive clients: %d/%d/%d\n", snprintf(line, sizeof(line), "recursive clients: %d/%d/%d\n",
server->sctx->recursionquota.used, isc_quota_getused(&server->sctx->recursionquota),
server->sctx->recursionquota.soft, isc_quota_getsoft(&server->sctx->recursionquota),
server->sctx->recursionquota.max); isc_quota_getmax(&server->sctx->recursionquota));
CHECK(putstr(text, line)); CHECK(putstr(text, line));
snprintf(line, sizeof(line), "tcp clients: %d/%d\n", snprintf(line, sizeof(line), "tcp clients: %d/%d\n",
server->sctx->tcpquota.used, server->sctx->tcpquota.max); isc_quota_getused(&server->sctx->tcpquota),
isc_quota_getmax(&server->sctx->tcpquota));
CHECK(putstr(text, line)); CHECK(putstr(text, line));
if (server->reload_in_progress) { if (server->reload_in_progress) {
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
*** Imports. *** Imports.
***/ ***/
#include <isc/atomic.h>
#include <isc/lang.h> #include <isc/lang.h>
#include <isc/mutex.h> #include <isc/mutex.h>
#include <isc/types.h> #include <isc/types.h>
...@@ -42,14 +43,14 @@ ISC_LANG_BEGINDECLS ...@@ -42,14 +43,14 @@ ISC_LANG_BEGINDECLS
/*% isc_quota structure */ /*% isc_quota structure */
struct isc_quota { struct isc_quota {
isc_mutex_t lock; /*%< Locked by lock. */ atomic_uint_fast32_t __max;
int max; atomic_uint_fast32_t __used;
int used; atomic_uint_fast32_t __soft;
int soft;
}; };
void void
isc_quota_init(isc_quota_t *quota, int max); isc_quota_init(isc_quota_t *quota, unsigned int max);
/*%< /*%<
* Initialize a quota object. * Initialize a quota object.
*/ */
...@@ -61,17 +62,35 @@ isc_quota_destroy(isc_quota_t *quota); ...@@ -61,17 +62,35 @@ isc_quota_destroy(isc_quota_t *quota);
*/ */
void void
isc_quota_soft(isc_quota_t *quota, int soft); isc_quota_soft(isc_quota_t *quota, unsigned int soft);
/*%< /*%<
* Set a soft quota. * Set a soft quota.
*/ */
void void
isc_quota_max(isc_quota_t *quota, int max); isc_quota_max(isc_quota_t *quota, unsigned int max);
/*%< /*%<
* Re-set a maximum quota. * Re-set a maximum quota.
*/ */
unsigned int
isc_quota_getmax(isc_quota_t *quota);
/*%<
* Get the maximum quota.
*/
unsigned int
isc_quota_getsoft(isc_quota_t *quota);
/*%<
* Get the soft quota.
*/
unsigned int
isc_quota_getused(isc_quota_t *quota);
/*%<
* Get the current usage of quota.
*/
isc_result_t isc_result_t
isc_quota_reserve(isc_quota_t *quota); isc_quota_reserve(isc_quota_t *quota);
/*%< /*%<
......
...@@ -16,62 +16,73 @@ ...@@ -16,62 +16,73 @@
#include <stddef.h> #include <stddef.h>
#include <isc/atomic.h>
#include <isc/quota.h> #include <isc/quota.h>
#include <isc/util.h> #include <isc/util.h>
void void
isc_quota_init(isc_quota_t *quota, int max) { isc_quota_init(isc_quota_t *quota, unsigned int max) {
quota->max = max; atomic_store(&quota->__max, max);
quota->used = 0; atomic_store(&quota->__used, 0);
quota->soft = 0; atomic_store(&quota->__soft, 0);
isc_mutex_init(&quota->lock);
} }
void void
isc_quota_destroy(isc_quota_t *quota) { isc_quota_destroy(isc_quota_t *quota) {
INSIST(quota->used == 0); INSIST(atomic_load(&quota->__used) == 0);
quota->max = 0; atomic_store(&quota->__max, 0);
quota->used = 0; atomic_store(&quota->__used, 0);
quota->soft = 0; atomic_store(&quota->__soft, 0);
isc_mutex_destroy(&quota->lock);
} }
void void
isc_quota_soft(isc_quota_t *quota, int soft) { isc_quota_soft(isc_quota_t *quota, unsigned int soft) {
LOCK(&quota->lock); atomic_store(&quota->__soft, soft);
quota->soft = soft;
UNLOCK(&quota->lock);
} }
void void
isc_quota_max(isc_quota_t *quota, int max) { isc_quota_max(isc_quota_t *quota, unsigned int max) {
LOCK(&quota->lock); atomic_store(&quota->__max, max);
quota->max = max; }
UNLOCK(&quota->lock);
unsigned int
isc_quota_getmax(isc_quota_t *quota) {
return (atomic_load_relaxed(&quota->__max));
}
unsigned int
isc_quota_getsoft(isc_quota_t *quota) {
return (atomic_load_relaxed(&quota->__soft));
}
unsigned int
isc_quota_getused(isc_quota_t *quota) {
return (atomic_load_relaxed(&quota->__used));
} }
isc_result_t isc_result_t
isc_quota_reserve(isc_quota_t *quota) { isc_quota_reserve(isc_quota_t *quota) {
isc_result_t result; isc_result_t result;
LOCK(&quota->lock); uint32_t max = atomic_load(&quota->__max);
if (quota->max == 0 || quota->used < quota->max) { uint32_t soft = atomic_load(&quota->__soft);
if (quota->soft == 0 || quota->used < quota->soft) uint32_t used = atomic_fetch_add(&quota->__used, 1);
if (max == 0 || used < max) {
if (soft == 0 || used < soft) {
result = ISC_R_SUCCESS; result = ISC_R_SUCCESS;
else } else {
result = ISC_R_SOFTQUOTA; result = ISC_R_SOFTQUOTA;
quota->used++; }
} else } else {
INSIST(atomic_fetch_sub(&quota->__used, 1) > 0);
result = ISC_R_QUOTA; result = ISC_R_QUOTA;
UNLOCK(&quota->lock); }
return (result); return (result);
} }
void void
isc_quota_release(isc_quota_t *quota) { isc_quota_release(isc_quota_t *quota) {
LOCK(&quota->lock); INSIST(atomic_fetch_sub(&quota->__used, 1) > 0);
INSIST(quota->used > 0);
quota->used--;
UNLOCK(&quota->lock);
} }
isc_result_t isc_result_t
......
...@@ -449,6 +449,9 @@ isc_portset_removerange ...@@ -449,6 +449,9 @@ isc_portset_removerange
isc_quota_attach isc_quota_attach
isc_quota_destroy isc_quota_destroy
isc_quota_detach isc_quota_detach
isc_quota_getmax
isc_quota_getsoft
isc_quota_getused
isc_quota_init isc_quota_init
isc_quota_max isc_quota_max
isc_quota_release isc_quota_release
......
...@@ -5589,38 +5589,37 @@ ns_query_recurse(ns_client_t *client, dns_rdatatype_t qtype, dns_name_t *qname, ...@@ -5589,38 +5589,37 @@ ns_query_recurse(ns_client_t *client, dns_rdatatype_t qtype, dns_name_t *qname,
ns_statscounter_recursclients); ns_statscounter_recursclients);
if (result == ISC_R_SOFTQUOTA) { if (result == ISC_R_SOFTQUOTA) {
static isc_stdtime_t last = 0; static atomic_uint_fast32_t last = 0;
isc_stdtime_t now; isc_stdtime_t now;
isc_stdtime_get(&now); isc_stdtime_get(&now);
if (now != last) { if (now != atomic_load_relaxed(&last)) {
last = now; atomic_store_relaxed(&last, now);
ns_client_log(client, NS_LOGCATEGORY_CLIENT, ns_client_log(client, NS_LOGCATEGORY_CLIENT,
NS_LOGMODULE_QUERY, NS_LOGMODULE_QUERY, ISC_LOG_WARNING,
ISC_LOG_WARNING, "recursive-clients soft limit "
"recursive-clients soft limit " "exceeded (%u/%u/%u), "
"exceeded (%d/%d/%d), " "aborting oldest query",
"aborting oldest query", isc_quota_getused(client->recursionquota),
client->recursionquota->used, isc_quota_getsoft(client->recursionquota),
client->recursionquota->soft, isc_quota_getmax(client->recursionquota));
client->recursionquota->max);
} }
ns_client_killoldestquery(client); ns_client_killoldestquery(client);
result = ISC_R_SUCCESS; result = ISC_R_SUCCESS;
} else if (result == ISC_R_QUOTA) { } else if (result == ISC_R_QUOTA) {
static isc_stdtime_t last = 0; static atomic_uint_fast32_t last = 0;
isc_stdtime_t now; isc_stdtime_t now;
isc_stdtime_get(&now); isc_stdtime_get(&now);
if (now != last) { if (now != atomic_load_relaxed(&last)) {
last = now; ns_server_t *sctx = client->sctx;
atomic_store_relaxed(&last, now);
ns_client_log(client, NS_LOGCATEGORY_CLIENT, ns_client_log(client, NS_LOGCATEGORY_CLIENT,
NS_LOGMODULE_QUERY, NS_LOGMODULE_QUERY, ISC_LOG_WARNING,
ISC_LOG_WARNING, "no more recursive clients "
"no more recursive clients " "(%u/%u/%u): %s",
"(%d/%d/%d): %s", isc_quota_getused(&sctx->recursionquota),
client->sctx->recursionquota.used, isc_quota_getsoft(&sctx->recursionquota),
client->sctx->recursionquota.soft, isc_quota_getmax(&sctx->recursionquota),
client->sctx->recursionquota.max, isc_result_totext(result));
isc_result_totext(result));
} }
ns_client_killoldestquery(client); ns_client_killoldestquery(client);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment