Compare commits

...
Author SHA1 Message Date
Witold Kręcicki 6c3af708ef incref fix 2020-02-10 10:54:06 +01:00
Witold Kręcicki db6e1379ca xxx tmp 2020-02-10 10:44:36 +01:00
Witold Kręcicki c7b5c0d9ba fixes 2020-02-10 10:44:36 +01:00
Witold Kręcicki be27968e24 fixup! clean up some handle/client reference counting errors in error cases. 2020-02-10 10:44:36 +01:00
Witold Kręcicki e5bda0d2e8 fixup! Cleaning up 2020-02-10 10:44:36 +01:00
Witold Kręcicki 19c11103f0 Revert "Reset affinity of LOWAC worker"
This reverts commit 38853183adf6846f2bc4ade9dc41734e199ec0a5.
2020-02-10 10:44:36 +01:00
Witold Kręcicki 1cf25df406 fixup! PoC LOWAC 2020-02-10 10:44:36 +01:00
Witold Kręcicki b0c1765501 fixup! Cleaning up 2020-02-10 10:44:36 +01:00
Witold Kręcicki 1b10390863 Reset affinity of LOWAC worker 2020-02-10 10:44:36 +01:00
Witold Kręcicki 661b15f25b Check if we have a view before LOWAC-caching 2020-02-10 10:44:35 +01:00
Witold Kręcicki e8dc021560 Use memcpy instead of byte-by-byte in dns_name_fromwire 2020-02-10 10:44:35 +01:00
Witold Kręcicki 7c806002c3 Minor fixes 2020-02-10 10:44:35 +01:00
Witold Kręcicki cf367bd64f Don't overuse isc_time_now(), use local time 2020-02-10 10:44:35 +01:00
Witold Kręcicki c9e6c59bc2 WiP 2020-02-10 10:44:35 +01:00
Witold Kręcicki 96ff385777 Allocate memory for blob: 2020-02-10 10:44:35 +01:00
Witold Kręcicki 36bc9ac28b Longer cache time 2020-02-10 10:44:35 +01:00
Witold Kręcicki 0b517735f2 Always enqueue removal after replacement 2020-02-10 10:44:35 +01:00
Witold Kręcicki 3edde4d190 Fixes 2020-02-10 10:44:35 +01:00
Witold Kręcicki 918af04b9d Mark unused memory 2020-02-10 10:44:35 +01:00
Witold Kręcicki 8279b866bc Add some magic checks 2020-02-10 10:44:35 +01:00
Witold Kręcicki ac88ecbbaa Fixes 2020-02-10 10:44:35 +01:00
Witold Kręcicki bb1bd0bcac Revert "Use common isc_time"
This reverts commit 1c5ba6ba8af5fb7e65456ef8b846afdc874b77a2.
2020-02-10 10:44:35 +01:00
Witold Kręcicki d1b608e7a2 Iterator fix 2020-02-10 10:44:35 +01:00
Witold Kręcicki 6d69556eea Use common isc_time 2020-02-10 10:44:35 +01:00
Witold Kręcicki a65d7597a9 Cleanup better 2020-02-10 10:44:35 +01:00
Witold Kręcicki cc0b84e84b More fiddling 2020-02-10 10:44:35 +01:00
Witold Kręcicki 55ce821070 Some fiddling 2020-02-10 10:44:35 +01:00
Witold Kręcicki 6c4447015d Cleaning up 2020-02-10 10:44:35 +01:00
Witold Kręcicki 0209c9f9ac Cleaning up 2020-02-10 10:44:35 +01:00
Witold Kręcicki 56d8a6060b Test: ck_fifo 2020-02-10 10:44:35 +01:00
Witold Kręcicki 2a82f35029 PoC LOWAC 2020-02-10 10:44:35 +01:00
Witold Kręcicki 14a852b86d fixup! Make client resolver tasks pooled and CPU-bound 2020-02-07 11:21:49 +01:00
Witold Kręcicki 30675428d8 Fix a race in isc_socket destruction.
There was a very slim chance of a race between isc_socket_detach and
process_fd: isc_socket_detach decrements references to 0, and before it
calls destroy gets preempted. Second thread calls process_fd, increments
socket references temporarily to 1, and then gets preempted, first thread
then hits assertion in destroy() as the reference counter is now 1 and
not 0.
2020-02-07 08:42:02 +01:00
Witold Kręcicki 627bf906ab test: don't use DISPATCHATTR_EXCLUSIVE, less random but waaay less sockets used 2020-02-07 08:42:02 +01:00
Witold Kręcicki 16dd6d8068 Use ISC_SOCKET_MAXSOCKETS at 64k no matter what the tuning would be, those affect only the recursion now 2020-02-07 08:41:53 +01:00
Witold Kręcicki 46fe61d359 Add an arena to compressctx 2020-02-07 08:41:53 +01:00
Witold Kręcicki 9fda4a4cbf Remove some stale fields from ns_client_t; make sendbuf allocated on heap 2020-02-07 08:40:25 +01:00
Witold Kręcicki e80ac06ed4 Don't update LRU if the node was recently used.
Updating LRU requires write-locking the node, which causes contention.
Update LRU only if time difference is large enough.
2020-02-07 08:40:25 +01:00
Witold Kręcicki aaa13532c2 Use libuv-provided uv_{export,import} if available 2020-02-07 08:40:25 +01:00
Witold Kręcicki 91d5c3313c Bucketed statistics.
Even though statistics are lockless they still use atomics which
might cause contention. Split stats counters into buckets, sharded
by an artificial thread identifier, to increase throughput.
2020-02-07 08:40:25 +01:00
Witold Kręcicki abc7b247e5 Allow --enable-pthread-rwlock without developer mode enabled. 2020-02-07 08:40:25 +01:00
Witold Kręcicki a1b6eae847 Don't enable NS_CLIENT_TRACE by default 2020-02-07 08:40:25 +01:00
Witold Kręcicki efc2a21590 Increase inactivehandles and inactivereqs size for better reuse. 2020-02-07 08:40:25 +01:00
Witold Kręcicki 0a21285b11 We don't need to fill udp local address every time since we are bound to it. 2020-02-07 08:40:25 +01:00
Witold Kręcicki 2985bcd7ef Make nm->recvbuf larger and heap allocated, to allow uv_recvmmsg usage. 2020-02-07 08:40:25 +01:00
Witold Kręcicki caf309a80f Fix atomics usage for mutexatomics 2020-02-07 08:40:25 +01:00
Witold Kręcicki 85a3cc6ffa Disable OpenSSL siphash.
Creation of EVP_MD_CTX and EVP_PKEY is quite expensive, until
we fix the code to reuse the context and key we'll use our own
implementation of siphash.
2020-02-07 08:40:25 +01:00
Witold Kręcicki 235c3e8685 Use the original threadid when sending a UDP packet to decrease probability of context switching 2020-02-07 08:40:25 +01:00
Witold Kręcicki 666b0f7564 Make client resolver tasks pooled and CPU-bound 2020-02-07 08:40:25 +01:00
Witold Kręcicki bcb55107ac Make isc_task_pause/isc_task_unpause thread safe.
isc_task_pause/unpause were inherently thread-unsafe - a task
could be paused only once by one thread, if the task was running
while we paused it it led to races. Fix it by making sure that
the task will pause if requested to, and by using a 'pause reference
counter' to count task pause requests - a task will be unpaused
iff all threads unpause it.

Don't remove from queue when pausing task - we lock the queue lock
(expensive), while it's unlikely that the task will be running -
and we'll remove it anyway in dispatcher
2020-02-07 08:40:25 +01:00
Witold Kręcicki b5afff59c2 Increase nodelock count for both cache and regular db. 2020-02-07 08:40:25 +01:00
Witold Kręcicki 79fc0e3f01 Use isc_rwlock for isc_result tables 2020-02-07 08:40:25 +01:00
Witold Kręcicki b21e515e1b Make ns_client mctxpool more thread-friendly by sharding it by netmgr threadid 2020-02-07 08:40:24 +01:00
Witold Kręcicki b42ac28eb1 Don't check if the client is on recursing list (requires locking) if it's not RECURSING 2020-02-07 08:40:24 +01:00
33 changed files with 896 additions and 204 deletions
+2 -2
View File
@@ -1344,7 +1344,7 @@ get_view_querysource_dispatch(const cfg_obj_t **maps, int af,
break;
}
if (isc_sockaddr_getport(&sa) == 0) {
attrs |= DNS_DISPATCHATTR_EXCLUSIVE;
// attrs |= DNS_DISPATCHATTR_EXCLUSIVE;
maxdispatchbuffers = EXCLBUFFERS;
} else {
INSIST(obj != NULL);
@@ -9544,7 +9544,7 @@ run_server(isc_task_t *task, isc_event_t *event) {
named_g_nm,
named_g_dispatchmgr,
server->task, named_g_udpdisp, geoip,
&server->interfacemgr),
named_g_cpus, &server->interfacemgr),
"creating interface manager");
CHECKFATAL(isc_timer_create(named_g_timermgr, isc_timertype_inactive,
+3
View File
@@ -471,6 +471,9 @@
/* Define to 1 if you have the `uv_handle_set_data' function. */
#undef HAVE_UV_HANDLE_SET_DATA
/* Define to 1 if you have the `uv_import' function. */
#undef HAVE_UV_IMPORT
/* Use zlib library */
#undef HAVE_ZLIB
+9
View File
@@ -355,6 +355,15 @@ typedef __int64 off_t;
/* Define to 1 if you have the `HMAC_CTX_reset' function. */
@HAVE_HMAC_CTX_RESET@
/* Define to 1 if you have the `uv_handle_get_data' function. */
@HAVE_UV_HANDLE_GET_DATA@
/* Define to 1 if you have the `uv_handle_set_data' function. */
@HAVE_UV_HANDLE_SET_DATA@
/* Define to 1 if you have the `uv_import' function. */
@HAVE_UV_IMPORT@
/*
* Define to nothing if C supports flexible array members, and to 1 if it does
* not. That way, with a declaration like `struct s { int n; double
Vendored
+21 -13
View File
@@ -852,6 +852,7 @@ infodir
docdir
oldincludedir
includedir
runstatedir
localstatedir
sharedstatedir
sysconfdir
@@ -1025,6 +1026,7 @@ datadir='${datarootdir}'
sysconfdir='${prefix}/etc'
sharedstatedir='${prefix}/com'
localstatedir='${prefix}/var'
runstatedir='${localstatedir}/run'
includedir='${prefix}/include'
oldincludedir='/usr/include'
docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
@@ -1277,6 +1279,15 @@ do
| -silent | --silent | --silen | --sile | --sil)
silent=yes ;;
-runstatedir | --runstatedir | --runstatedi | --runstated \
| --runstate | --runstat | --runsta | --runst | --runs \
| --run | --ru | --r)
ac_prev=runstatedir ;;
-runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
| --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
| --run=* | --ru=* | --r=*)
runstatedir=$ac_optarg ;;
-sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
ac_prev=sbindir ;;
-sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
@@ -1414,7 +1425,7 @@ fi
for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
datadir sysconfdir sharedstatedir localstatedir includedir \
oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
libdir localedir mandir
libdir localedir mandir runstatedir
do
eval ac_val=\$$ac_var
# Remove trailing slashes.
@@ -1567,6 +1578,7 @@ Fine tuning of the installation directories:
--sysconfdir=DIR read-only single-machine data [PREFIX/etc]
--sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
--localstatedir=DIR modifiable single-machine data [PREFIX/var]
--runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run]
--libdir=DIR object code libraries [EPREFIX/lib]
--includedir=DIR C header files [PREFIX/include]
--oldincludedir=DIR C header files for non-gcc [/usr/include]
@@ -4011,7 +4023,7 @@ else
We can't simply define LARGE_OFF_T to be 9223372036854775807,
since some C++ compilers masquerading as C compilers
incorrectly reject 9223372036854775807. */
#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
&& LARGE_OFF_T % 2147483647 == 1)
? 1 : -1];
@@ -4057,7 +4069,7 @@ else
We can't simply define LARGE_OFF_T to be 9223372036854775807,
since some C++ compilers masquerading as C compilers
incorrectly reject 9223372036854775807. */
#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
&& LARGE_OFF_T % 2147483647 == 1)
? 1 : -1];
@@ -4081,7 +4093,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
We can't simply define LARGE_OFF_T to be 9223372036854775807,
since some C++ compilers masquerading as C compilers
incorrectly reject 9223372036854775807. */
#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
&& LARGE_OFF_T % 2147483647 == 1)
? 1 : -1];
@@ -4126,7 +4138,7 @@ else
We can't simply define LARGE_OFF_T to be 9223372036854775807,
since some C++ compilers masquerading as C compilers
incorrectly reject 9223372036854775807. */
#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
&& LARGE_OFF_T % 2147483647 == 1)
? 1 : -1];
@@ -4150,7 +4162,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
We can't simply define LARGE_OFF_T to be 9223372036854775807,
since some C++ compilers masquerading as C compilers
incorrectly reject 9223372036854775807. */
#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
&& LARGE_OFF_T % 2147483647 == 1)
? 1 : -1];
@@ -15582,8 +15594,8 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
LIBS="$PTHREAD_LIBS $LIBS"
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
LIBS="$PTHREAD_LIBS -lck $LIBS"
CFLAGS="$CFLAGS $PTHREAD_CFLAGS -I/usr/include/ck"
CC="$PTHREAD_CC"
for ac_func in pthread_attr_getstacksize pthread_attr_setstacksize
@@ -15948,7 +15960,7 @@ LIBS="$LIBS $LIBUV_LIBS"
# Those functions are only provided in newer versions of libuv, we'll be emulating them
# for now
for ac_func in uv_handle_get_data uv_handle_set_data
for ac_func in uv_handle_get_data uv_handle_set_data uv_import
do :
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
@@ -16070,10 +16082,6 @@ $as_echo "#define USE_PTHREAD_RWLOCK 1" >>confdefs.h
fi
if test "$enable_pthread_rwlock" = "yes" -a "$enable_developer" != "yes"; then :
as_fn_error $? "pthread rwlock is not meant used in production and the developer mode must be enabled" "$LINENO" 5
fi
CRYPTO=OpenSSL
#
+3 -6
View File
@@ -607,8 +607,8 @@ AC_CHECK_FUNCS(arc4random arc4random_buf arc4random_uniform getrandom)
AX_PTHREAD
LIBS="$PTHREAD_LIBS $LIBS"
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
LIBS="$PTHREAD_LIBS -lck $LIBS"
CFLAGS="$CFLAGS $PTHREAD_CFLAGS -I/usr/include/ck"
CC="$PTHREAD_CC"
AC_CHECK_FUNCS([pthread_attr_getstacksize pthread_attr_setstacksize])
@@ -667,7 +667,7 @@ LIBS="$LIBS $LIBUV_LIBS"
# Those functions are only provided in newer versions of libuv, we'll be emulating them
# for now
AC_CHECK_FUNCS([uv_handle_get_data uv_handle_set_data])
AC_CHECK_FUNCS([uv_handle_get_data uv_handle_set_data uv_import])
#
# flockfile is usually provided by pthreads
@@ -729,9 +729,6 @@ AS_IF([test "$enable_pthread_rwlock" = "yes"],
AC_DEFINE([USE_PTHREAD_RWLOCK],[1],[Define if you want to use pthread rwlock implementation])
])
AS_IF([test "$enable_pthread_rwlock" = "yes" -a "$enable_developer" != "yes"],
[AC_MSG_ERROR([pthread rwlock is not meant used in production and the developer mode must be enabled])])
CRYPTO=OpenSSL
#
+2 -2
View File
@@ -77,7 +77,7 @@ DNSOBJS = acl.@O@ adb.@O@ badcache.@O@ byaddr.@O@ \
stats.@O@ tcpmsg.@O@ time.@O@ timer.@O@ tkey.@O@ \
tsec.@O@ tsig.@O@ ttl.@O@ update.@O@ validator.@O@ \
version.@O@ view.@O@ xfrin.@O@ zone.@O@ zonekey.@O@ \
zoneverify.@O@ zt.@O@
zoneverify.@O@ zt.@O@ lowac.@O@
PORTDNSOBJS = client.@O@ ecdb.@O@
OBJS= @DNSTAPOBJS@ ${DNSOBJS} ${OTHEROBJS} ${DSTOBJS} \
@@ -112,7 +112,7 @@ DNSSRCS = acl.c adb.c badcache. byaddr.c \
stats.c tcpmsg.c time.c timer.c tkey.c \
tsec.c tsig.c ttl.c update.c validator.c \
version.c view.c xfrin.c zone.c zoneverify.c \
zonekey.c zt.c ${OTHERSRCS}
zonekey.c zt.c ${OTHERSRCS} lowac.c
PORTDNSSRCS = client.c ecdb.c
SRCS = ${DSTSRCS} ${DNSSRCS} \
+18 -4
View File
@@ -149,6 +149,7 @@ dns_compress_init(dns_compress_t *cctx, int edns, isc_mem_t *mctx) {
cctx->mctx = mctx;
cctx->count = 0;
cctx->allowed = DNS_COMPRESS_ENABLED;
cctx->arena_off = 0;
memset(&cctx->table[0], 0, sizeof(cctx->table));
@@ -386,6 +387,7 @@ dns_compress_add(dns_compress_t *cctx, const dns_name_t *name,
uint16_t toffset;
unsigned char *tmp;
isc_region_t r;
bool allocated = false;
REQUIRE(VALID_CCTX(cctx));
REQUIRE(dns_name_isabsolute(name));
@@ -407,7 +409,13 @@ dns_compress_add(dns_compress_t *cctx, const dns_name_t *name,
start = 0;
dns_name_toregion(name, &r);
length = r.length;
tmp = isc_mem_get(cctx->mctx, length);
if (cctx->arena_off + length < DNS_COMPRESS_ARENA_SIZE) {
tmp = &cctx->arena[cctx->arena_off];
cctx->arena_off += length;
} else {
allocated = true;
tmp = isc_mem_get(cctx->mctx, length);
}
/*
* Copy name data to 'tmp' and make 'r' use 'tmp'.
*/
@@ -446,8 +454,9 @@ dns_compress_add(dns_compress_t *cctx, const dns_name_t *name,
* 'node->r.base' becomes 'tmp' when start == 0.
* Record this by setting 0x8000 so it can be freed later.
*/
if (start == 0)
if (start == 0 && allocated) {
toffset |= 0x8000;
}
node->offset = toffset;
dns_name_toregion(&tname, &node->r);
dns_name_init(&node->name, NULL);
@@ -462,8 +471,13 @@ dns_compress_add(dns_compress_t *cctx, const dns_name_t *name,
count--;
}
if (start == 0)
isc_mem_put(cctx->mctx, tmp, length);
if (start == 0) {
if (!allocated) {
cctx->arena_off -= length;
} else {
isc_mem_put(cctx->mctx, tmp, length);
}
}
}
void
+5 -1
View File
@@ -51,7 +51,8 @@ ISC_LANG_BEGINDECLS
#define DNS_COMPRESS_TABLEBITS 6
#define DNS_COMPRESS_TABLESIZE (1U << DNS_COMPRESS_TABLEBITS)
#define DNS_COMPRESS_TABLEMASK (DNS_COMPRESS_TABLESIZE - 1)
#define DNS_COMPRESS_INITIALNODES 16
#define DNS_COMPRESS_INITIALNODES 24
#define DNS_COMPRESS_ARENA_SIZE 640
typedef struct dns_compressnode dns_compressnode_t;
@@ -69,6 +70,9 @@ struct dns_compress {
int edns; /*%< Edns version or -1. */
/*% Global compression table. */
dns_compressnode_t *table[DNS_COMPRESS_TABLESIZE];
/*% Preallocated arena for names. */
unsigned char arena[DNS_COMPRESS_ARENA_SIZE];
off_t arena_off;
/*% Preallocated nodes for the table. */
dns_compressnode_t initialnodes[DNS_COMPRESS_INITIALNODES];
uint16_t count; /*%< Number of nodes. */
+17
View File
@@ -0,0 +1,17 @@
#include <isc/mem.h>
#include <dns/name.h>
typedef struct dns_lowac_entry dns_lowac_entry_t;
typedef struct dns_lowac dns_lowac_t;
dns_lowac_t*
dns_lowac_create(isc_mem_t *mctx);
void
dns_lowac_destroy(dns_lowac_t *lowac);
isc_result_t
dns_lowac_put(dns_lowac_t *lowac, dns_name_t *name, char* packet, int size);
isc_result_t
dns_lowac_get(dns_lowac_t *lowac, dns_name_t *name, unsigned char* blob, int* blobsize, bool tcp);
+2
View File
@@ -75,6 +75,7 @@
#include <dns/rpz.h>
#include <dns/types.h>
#include <dns/zt.h>
#include <dns/lowac.h>
ISC_LANG_BEGINDECLS
@@ -240,6 +241,7 @@ struct dns_view {
void *hooktable; /* ns_hooktable */
void (*hooktable_free)(isc_mem_t *, void **);
dns_lowac_t* lowac;
};
#define DNS_VIEW_MAGIC ISC_MAGIC('V','i','e','w')
+488
View File
@@ -0,0 +1,488 @@
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <isc/thread.h>
#include <isc/mem.h>
#include <isc/hash.h>
#include <isc/time.h>
#include <isc/util.h>
#include <isc/random.h>
#include <isc/refcount.h>
#include <dns/name.h>
#include <dns/lowac.h>
#include <stdlib.h>
#include <ck_ht.h>
#include <ck_fifo.h>
#include <ck_queue.h>
#define fprintf(...) {}
#define MAXIMUM_PKT_SIZE 1024
#define LENTRY_MAGIC ISC_MAGIC('L', 'o', 'w', 'E')
#define VALID_LENTRY(c) ISC_MAGIC_VALID(c, LENTRY_MAGIC)
struct dns_lowac_entry {
unsigned int magic;
dns_name_t name;
isc_region_t key;
uint16_t flags;
int64_t expire;
ck_ht_hash_t hash;
unsigned char *blob;
uint32_t blobsize;
isc_refcount_t refcount;
/*
* Set to 'true' when we enqueue this entry on remq.
* Nothing serious will happen if we enqueue the entry
* on remq multiple times as we're refcounting.
* It's not locked in any way as it can only change
* from false to true during runtime.
*/
bool remq_enqueued;
bool inht;
isc_refcount_t rqrefcount;
atomic_int_fast64_t lastusage;
};
struct dns_lowac {
isc_mem_t * mctx;
isc_thread_t thread;
int expiry; /* Time after which records expire */
bool running; /* We're not shut down */
bool accepting; /* We're accepting packets into cache */
ck_ht_t ht; /* Cache hash table */
ck_ht_iterator_t htit; /* Hashtable maintenance iterator */
ck_fifo_mpmc_t inq; /* Packet input queue */
ck_fifo_mpmc_t remq; /* Removal queue */
atomic_int_fast64_t now; /* Epoch time, updated at every loop */
int count;
};
static void *
rthread(void*d);
static void *
ht_malloc(size_t r)
{
return(malloc(r));
}
static void
ht_free(void *p, size_t b, bool r)
{
(void)b;
(void)r;
free(p);
return;
}
static void
ht_hash_wrapper(struct ck_ht_hash *h, const void *key, size_t length,
uint64_t seed)
{
(void)seed;
h->value = isc_hash_function(key, length, false);
return;
}
static struct ck_malloc my_allocator = {
.malloc = ht_malloc,
.free = ht_free
};
static void
free_entry(dns_lowac_t *lowac, dns_lowac_entry_t *entry) {
entry->magic = 0xffffffff;
dns_name_free(&entry->name, lowac->mctx);
isc_mem_put(lowac->mctx, entry->blob, entry->blobsize);
isc_mem_put(lowac->mctx, entry, sizeof(*entry));
}
static bool
dequeue_input_entry(dns_lowac_t*lowac) {
dns_lowac_entry_t *entry = NULL;
ck_fifo_mpmc_entry_t *garbage = NULL;
if (ck_fifo_mpmc_dequeue(&lowac->inq, &entry,
&garbage) == true) {
REQUIRE(VALID_LENTRY(entry));
isc_mem_put(lowac->mctx, garbage,
sizeof(*garbage));
ck_ht_entry_t htentry;
ck_ht_entry_t oldhtentry;
ck_ht_entry_set(&htentry, entry->hash, entry->key.base,
entry->key.length, entry);
ck_ht_entry_set(&oldhtentry, entry->hash, entry->key.base,
entry->key.length, NULL);
if (ck_ht_get_spmc(&lowac->ht, entry->hash,
&oldhtentry) == false) {
/* We don't have this entry in hashtable */
entry->inht = true;
if (ck_ht_put_spmc(&lowac->ht, entry->hash,
&htentry) == false) {
abort();
printf("oddness but might happen\n");
/* We can do it safely as it never was in
* hashtable */
RUNTIME_CHECK(isc_refcount_decrement(&entry->
refcount) ==
1);
free_entry(lowac, entry);
} else {
fprintf(stderr, "XXXInsert %p %d\n", entry, lowac->count);
lowac->count++;
}
} else {
dns_lowac_entry_t *oldentry =
ck_ht_entry_value(&oldhtentry);
/* Note: set without remove doesn't seem to work
* properly */
oldentry->inht = false;
RUNTIME_CHECK(ck_ht_remove_spmc(&lowac->ht,
entry->hash,
&oldhtentry) == true);
entry->inht = true;
RUNTIME_CHECK(ck_ht_set_spmc(&lowac->ht, entry->hash,
&htentry) == true);
lowac->count++;
/*
* We don't need to increment refcount since we
* have not decremented it
* when removing from hashtable
*/
ck_fifo_mpmc_entry_t *qentry =
isc_mem_get(lowac->mctx,
(sizeof(
ck_fifo_mpmc_entry_t)));
oldentry->remq_enqueued = true;
isc_refcount_increment0(&oldentry->rqrefcount);
fprintf(stderr, "XXXenq %p %d\n", oldentry, __LINE__);
ck_fifo_mpmc_enqueue(&lowac->remq, qentry,
oldentry);
}
return (true);
}
return (false);
}
static int
expire_entries(dns_lowac_t *lowac) {
int iterated = 0;
ck_ht_entry_t *htitentry = NULL;
bool iterok = ck_ht_next(&lowac->ht, &lowac->htit, &htitentry);
if (!iterok) {
ck_ht_iterator_init(&lowac->htit);
iterok = ck_ht_next(&lowac->ht, &lowac->htit, &htitentry);
}
while (iterok && htitentry != NULL && iterated < 2048) {
dns_lowac_entry_t *entry = ck_ht_entry_value(htitentry);
REQUIRE(VALID_LENTRY(entry));
if (entry->expire < atomic_load(&lowac->now)) {
if (!ck_ht_remove_spmc(&lowac->ht, entry->hash, htitentry)) {
abort();
/*
* Very unlikely, but can happen when we're between generations.
* TODO verify that it's ok at all, maybe we're using the iterator wrong?
*/
isc_refcount_increment0(&entry->refcount);
fprintf(stderr, "INCREF %d %p\n", __LINE__, entry);
} else {
dns_lowac_entry_t *ent2 = ck_ht_entry_value(htitentry);
RUNTIME_CHECK(ent2 == entry);
}
entry->inht = false;
/*
* We don't need to increment refcount since we have
* not decremented it when removing from hashtable.
*/
ck_fifo_mpmc_entry_t *qentry =
isc_mem_get(lowac->mctx,
(sizeof(
ck_fifo_mpmc_entry_t)));
entry->remq_enqueued = true;
isc_refcount_increment0(&entry->rqrefcount);
fprintf(stderr, "XXXenq %p %d\n", entry, __LINE__);
ck_fifo_mpmc_enqueue(&lowac->remq, qentry, entry);
}
htitentry = NULL;
iterok = ck_ht_next(&lowac->ht, &lowac->htit, &htitentry);
iterated++;
}
if (!iterok) {
ck_ht_iterator_init(&lowac->htit);
}
return (iterated);
}
/*
* Iterate over remq.
* If the entry is in HT - remove it, requeue.
* If the entry is not in HT but it is referenced - requeue.
* If the entry is not referenced - free.
*/
static int
cleanup_entries(dns_lowac_t *lowac) {
ck_ht_entry_t htentry;
dns_lowac_entry_t *entry;
ck_fifo_mpmc_entry_t *qentry = NULL;
int removed = 0;
int max = 100;
while (--max > 0 &&
ck_fifo_mpmc_dequeue(&lowac->remq, &entry, &qentry) == true)
{
REQUIRE(VALID_LENTRY(entry));
int rc = isc_refcount_decrement(&entry->refcount);
int rqrc = isc_refcount_decrement(&entry->rqrefcount);
fprintf(stderr, "DECREF %d %p %d\n", __LINE__, entry, lowac->count);
if (entry->inht) {
/*
* Remove entry from the hashtable, we'll remove the
* entry itself in the next iteration.
*/
ck_ht_entry_set(&htentry, entry->hash, entry->key.base,
entry->key.length, entry);
RUNTIME_CHECK(ck_ht_remove_spmc(&lowac->ht,
entry->hash,
&htentry) == true);
entry->inht = false;
isc_refcount_increment0(&entry->rqrefcount);
/* We don't increment refcount - it was at 2 (remq + ht), it stays at 1 (remq) */
fprintf(stderr, "INCREF %d %p\n", __LINE__, entry);
fprintf(stderr, "XXXenq %p %d\n", entry, __LINE__);
ck_fifo_mpmc_enqueue(&lowac->remq, qentry, entry);
} else {
if (rc > 1) {
/* Requeue if still in use and there's no other request in queue */
/* TODO that's completely wrong, if we have two instances in the queue they will always have rc > 1 !!! */
if (rqrc == 0) {
int p1 = isc_refcount_increment0(&entry->rqrefcount);
int p2 = isc_refcount_increment0(&entry->refcount);
(void) p1;
(void) p2;
fprintf(stderr, "INCREF %d %p %d %d\n", __LINE__, entry, p1, p2);
fprintf(stderr, "XXXenq %p %d\n", entry, __LINE__);
ck_fifo_mpmc_enqueue(&lowac->remq, qentry,
entry);
} else {
isc_mem_put(lowac->mctx, qentry,
sizeof(*qentry));
}
fprintf(stderr, "IGNREF %d %p\n", __LINE__, entry);
} else {
isc_mem_put(lowac->mctx, qentry,
sizeof(*qentry));
removed++;
free_entry(lowac, entry);
fprintf(stderr, "XXXFree %p %d\n", entry, lowac->count);
lowac->count--;
}
}
}
return (removed);
}
static void *
rthread(void *d) {
dns_lowac_t *lowac = (dns_lowac_t*) d;
ck_ht_iterator_init(&lowac->htit);
while (lowac->running) {
isc_time_t now;
isc_time_now(&now);
atomic_store(&lowac->now, now.seconds);
bool dequeued = dequeue_input_entry(lowac);
if (!dequeued) {
expire_entries(lowac);
int removed = cleanup_entries(lowac);
if (removed < 256) {
usleep(1000);
} else {
RUNTIME_CHECK(ck_ht_gc(&lowac->ht, 128,
isc_random32()));
}
}
}
return (NULL);
}
dns_lowac_t*
dns_lowac_create(isc_mem_t *mctx) {
dns_lowac_t *lowac = isc_mem_get(mctx, sizeof(dns_lowac_t));
lowac->expiry = 600;
lowac->count = 0;
lowac->running = true;
if (ck_ht_init(&lowac->ht,
CK_HT_MODE_BYTESTRING | CK_HT_WORKLOAD_DELETE,
ht_hash_wrapper,
&my_allocator, 32, isc_random32()) == false) {
abort();
}
ck_fifo_mpmc_entry_t *inq_stub =
isc_mem_get(mctx, sizeof(ck_fifo_mpmc_entry_t));
ck_fifo_mpmc_entry_t *remq_stub =
isc_mem_get(mctx, sizeof(ck_fifo_mpmc_entry_t));
ck_fifo_mpmc_init(&lowac->inq, inq_stub);
ck_fifo_mpmc_init(&lowac->remq, remq_stub);
lowac->mctx = NULL;
isc_mem_attach(mctx, &lowac->mctx);
isc_thread_create(rthread, lowac, &lowac->thread);
return (lowac);
}
void
dns_lowac_destroy(dns_lowac_t *lowac) {
lowac->running = false;
isc_thread_join(lowac->thread, NULL);
dns_lowac_entry_t *entry;
ck_fifo_mpmc_entry_t *fentry;
/* Entries in inq can only be in inq, it's safe to free them */
while (ck_fifo_mpmc_dequeue(&lowac->inq,
&entry,
&fentry))
{
isc_mem_put(lowac->mctx, fentry, sizeof(*fentry));
free_entry(lowac, entry);
}
/*
* Entries in remq can be freed only if they're no longer referenced
* by either multiple occurences in queue or HT
*/
while (ck_fifo_mpmc_dequeue(&lowac->remq,
&entry,
&fentry))
{
if (isc_refcount_decrement(&entry->refcount) == 1) {
fprintf(stderr, "DECREF %d %p\n", __LINE__, entry);
free_entry(lowac, entry);
} else {
fprintf(stderr, "Non-unreferenced entry in remq %p\n", entry);
}
isc_mem_put(lowac->mctx, fentry, sizeof(*fentry));
}
/* Finally we free rest of entries from HT */
while (ck_ht_count(&lowac->ht) > 0) {
ck_ht_gc(&lowac->ht, 0, 0);
ck_ht_iterator_t htit = CK_HT_ITERATOR_INITIALIZER;
ck_ht_entry_t *htitentry = NULL;
while (ck_ht_next(&lowac->ht, &htit, &htitentry)) {
entry = ck_ht_entry_value(htitentry);
ck_ht_remove_spmc(&lowac->ht, entry->hash, htitentry);
free_entry(lowac, entry);
}
}
ck_fifo_mpmc_deinit(&lowac->inq, &fentry);
isc_mem_put(lowac->mctx, fentry, sizeof(*fentry));
ck_fifo_mpmc_deinit(&lowac->remq, &fentry);
isc_mem_put(lowac->mctx, fentry, sizeof(*fentry));
ck_ht_destroy(&lowac->ht);
isc_mem_putanddetach(&lowac->mctx, lowac, sizeof(*lowac));
}
isc_result_t
dns_lowac_put(dns_lowac_t *lowac, dns_name_t *name, char*packet, int size) {
if (!lowac->running) {
return (ISC_R_SHUTTINGDOWN);
}
if (size > MAXIMUM_PKT_SIZE) {
return (ISC_R_FAILURE);
}
dns_lowac_entry_t *entry = isc_mem_get(lowac->mctx, sizeof(*entry));
dns_name_init(&entry->name, NULL);
dns_name_dup(name, lowac->mctx, &entry->name);
entry->blob = isc_mem_get(lowac->mctx, size);
memcpy(entry->blob, packet, size);
entry->blobsize = size;
isc_refcount_init(&entry->refcount, 1);
isc_refcount_init(&entry->rqrefcount, 0);
entry->expire = atomic_load(&lowac->now) + lowac->expiry;
entry->remq_enqueued = false;
entry->inht = false;
entry->magic = LENTRY_MAGIC;
dns_name_toregion(&entry->name, &entry->key);
ck_ht_hash(&entry->hash, &lowac->ht, entry->key.base,
entry->key.length);
ck_fifo_mpmc_entry_t *qentry =
isc_mem_get(lowac->mctx, (sizeof(ck_fifo_mpmc_entry_t)));
ck_fifo_mpmc_enqueue(&lowac->inq, qentry, entry);
return (ISC_R_SUCCESS);
}
isc_result_t
dns_lowac_get(dns_lowac_t *lowac, dns_name_t *name, unsigned char *blob,
int *blobsize, bool tcp) {
ck_ht_entry_t htentry;
ck_ht_hash_t h;
isc_region_t r;
dns_name_toregion(name, &r);
ck_ht_hash(&h, &lowac->ht, r.base, r.length);
ck_ht_entry_key_set(&htentry, r.base, r.length);
if (ck_ht_get_spmc(&lowac->ht, h, &htentry) == false) {
return (ISC_R_NOTFOUND);
} else {
dns_lowac_entry_t *entry = ck_ht_entry_value(&htentry);
REQUIRE(VALID_LENTRY(entry));
int oldrc = isc_refcount_increment0(&entry->refcount);
fprintf(stderr, "INCREF %d %p\n", __LINE__, entry, oldrc);
RUNTIME_CHECK(oldrc > 0);
if (entry->remq_enqueued || !entry->inht) {
/* This entry is being removed, bail */
isc_refcount_decrement(&entry->refcount);
fprintf(stderr, "DECREF %d %p\n", __LINE__, entry);
return (ISC_R_NOTFOUND);
}
if (entry->expire < atomic_load(&lowac->now)) {
ck_fifo_mpmc_entry_t *qentry =
isc_mem_get(lowac->mctx,
(sizeof(ck_fifo_mpmc_entry_t)));
entry->remq_enqueued = true;
isc_refcount_increment0(&entry->rqrefcount);
fprintf(stderr, "XXXenq %p %d\n", entry, __LINE__);
ck_fifo_mpmc_enqueue(&lowac->remq, qentry, entry);
return (ISC_R_NOTFOUND);
}
if (tcp) {
blob[0] = entry->blobsize >> 8;
blob[1] = entry->blobsize;
memcpy(blob + 2, entry->blob, entry->blobsize);
*blobsize = entry->blobsize + 2;
} else {
memcpy(blob, entry->blob, entry->blobsize);
*blobsize = entry->blobsize;
}
isc_refcount_decrement(&entry->refcount);
fprintf(stderr, "DECREF %d %p\n", __LINE__, entry);
return (ISC_R_SUCCESS);
}
return (ISC_R_FAILURE);
}
+15 -1
View File
@@ -1777,7 +1777,21 @@ dns_name_fromwire(dns_name_t *name, isc_buffer_t *source,
if (c == 0)
done = true;
n = c;
state = fw_ordinary;
if (downcase) {
state = fw_ordinary;
} else {
current += n;
if (current >= source->active) {
return (ISC_R_UNEXPECTEDEND);
}
memcpy(ndata, cdata, n);
cdata += n;
ndata += n;
if (!seen_pointer) {
cused+=n;
}
state = fw_start;
}
} else if (c >= 128 && c < 192) {
/*
* 14 bit local compression pointer.
+8 -5
View File
@@ -172,9 +172,12 @@ typedef isc_rwlock_t nodelock_t;
* to be 0 by default either with or without threads.
*/
#ifndef DNS_RBTDB_LIMITLRUUPDATE
#define DNS_RBTDB_LIMITLRUUPDATE 0
#define DNS_RBTDB_LIMITLRUUPDATE 1
#endif
#define DNS_RBTDB_LRUUPDATE_GLUE 300
#define DNS_RBTDB_LRUUPDATE_REGULAR 600
/*
* Allow clients with a virtual time of up to 5 minutes in the past to see
* records that would have otherwise have expired.
@@ -309,7 +312,7 @@ typedef ISC_LIST(dns_rbtnode_t) rbtnodelist_t;
(((header)->rdh_ttl > (now)) || \
((header)->rdh_ttl == (now) && ZEROTTL(header)))
#define DEFAULT_NODE_LOCK_COUNT 7 /*%< Should be prime. */
#define DEFAULT_NODE_LOCK_COUNT 53 /*%< Should be prime. */
#define RBTDB_GLUE_TABLE_INIT_SIZE 2U
/*%
@@ -329,7 +332,7 @@ typedef ISC_LIST(dns_rbtnode_t) rbtnodelist_t;
#define DEFAULT_CACHE_NODE_LOCK_COUNT DNS_RBTDB_CACHE_NODE_LOCK_COUNT
#endif
#else
#define DEFAULT_CACHE_NODE_LOCK_COUNT 16
#define DEFAULT_CACHE_NODE_LOCK_COUNT 97
#endif /* DNS_RBTDB_CACHE_NODE_LOCK_COUNT */
typedef struct {
@@ -10088,11 +10091,11 @@ need_headerupdate(rdatasetheader_t *header, isc_stdtime_t now) {
* Glue records are updated if at least 60 seconds have passed
* since the previous update time.
*/
return (header->last_used + 60 <= now);
return (header->last_used + DNS_RBTDB_LRUUPDATE_GLUE <= now);
}
/* Other records are updated if 5 minutes have passed. */
return (header->last_used + 300 <= now);
return (header->last_used + DNS_RBTDB_LRUUPDATE_REGULAR <= now);
#else
UNUSED(now);
+1 -1
View File
@@ -4832,7 +4832,7 @@ fctx_create(dns_resolver_t *res, const dns_name_t *name, dns_rdatatype_t type,
fctx->vresult = ISC_R_SUCCESS;
fctx->exitline = -1; /* sentinel */
fctx->logged = false;
atomic_store(&fctx->attributes, 0);
atomic_init(&fctx->attributes, 0);
fctx->spilled = false;
fctx->nqueries = 0;
fctx->reason = NULL;
+5
View File
@@ -279,6 +279,8 @@ dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass,
view, NULL, NULL, NULL);
view->viewlist = NULL;
view->magic = DNS_VIEW_MAGIC;
/* TODO we might destroy the view (and LOWAC) when we still need it on shutdown! */
view->lowac = dns_lowac_create(view->mctx);
*viewp = view;
@@ -610,6 +612,9 @@ view_flushanddetach(dns_view_t **viewp, bool flush) {
if (view->catzs != NULL) {
dns_catz_catzs_detach(&view->catzs);
}
if (view->lowac != NULL) {
dns_lowac_destroy(view->lowac);
}
UNLOCK(&view->lock);
/* Need to detach zones outside view lock */
+1 -1
View File
@@ -133,7 +133,7 @@ void
isc_hp_destroy(isc_hp_t *hp) {
for (int i = 0; i < isc__hp_max_threads; i++) {
isc_mem_put(hp->mctx, hp->hp[i],
CLPAD * 2 * sizeof(uintptr_t));
CLPAD * 2 * sizeof(hp->hp[i][0]));
for (int j = 0; j < hp->rl[i]->size; j++) {
void *data = (void *)hp->rl[i]->list[j];
+2 -2
View File
@@ -33,7 +33,7 @@
#include "uv-compat.h"
#define ISC_NETMGR_TID_UNKNOWN -1
#define ISC_NETMGR_RECVBUF_SIZE (20*65536)
/*
* Single network event loop worker.
*/
@@ -55,7 +55,7 @@ typedef struct isc__networker {
* worker is paused */
isc_refcount_t references;
atomic_int_fast64_t pktcount;
char recvbuf[65536];
char * recvbuf;
bool recvbuf_inuse;
} isc__networker_t;
+10 -5
View File
@@ -210,6 +210,7 @@ isc_nm_start(isc_mem_t *mctx, uint32_t workers) {
worker->ievents = isc_queue_new(mgr->mctx, 128);
worker->ievents_prio = isc_queue_new(mgr->mctx, 128);
worker->recvbuf = isc_mem_get(mctx, ISC_NETMGR_RECVBUF_SIZE);
/*
* We need to do this here and not in nm_thread to avoid a
@@ -281,6 +282,7 @@ nm_destroy(isc_nm_t **mgr0) {
isc_queue_destroy(worker->ievents);
isc_queue_destroy(worker->ievents_prio);
isc_mem_put(mgr->mctx, worker->recvbuf, ISC_NETMGR_RECVBUF_SIZE);
isc_thread_join(worker->thread, NULL);
}
@@ -921,8 +923,8 @@ isc__nmsocket_init(isc_nmsocket_t *sock, isc_nm_t *mgr,
.iface = iface,
.fd = -1,
.ah_size = 32,
.inactivehandles = isc_astack_new(mgr->mctx, 60),
.inactivereqs = isc_astack_new(mgr->mctx, 60)
.inactivehandles = isc_astack_new(mgr->mctx, 600),
.inactivereqs = isc_astack_new(mgr->mctx, 600)
};
isc_nm_attach(mgr, &sock->mgr);
@@ -982,14 +984,14 @@ isc__nm_alloc_cb(uv_handle_t *handle, size_t size, uv_buf_t *buf) {
REQUIRE(VALID_NMSOCK(sock));
REQUIRE(isc__nm_in_netthread());
REQUIRE(size <= 65536);
REQUIRE(size <= ISC_NETMGR_RECVBUF_SIZE);
worker = &sock->mgr->workers[sock->tid];
INSIST(!worker->recvbuf_inuse);
buf->base = worker->recvbuf;
worker->recvbuf_inuse = true;
buf->len = size;
buf->len = ISC_NETMGR_RECVBUF_SIZE;
}
void
@@ -1004,8 +1006,11 @@ isc__nm_free_uvbuf(isc_nmsocket_t *sock, const uv_buf_t *buf) {
worker = &sock->mgr->workers[sock->tid];
REQUIRE(worker->recvbuf_inuse);
if (buf->base > worker->recvbuf && buf->base <= worker->recvbuf + ISC_NETMGR_RECVBUF_SIZE) {
/* Can happen in case of recvmmsg */
return;
}
REQUIRE(buf->base == worker->recvbuf);
worker->recvbuf_inuse = false;
}
+13 -5
View File
@@ -291,8 +291,8 @@ udp_recv_cb(uv_udp_t *handle, ssize_t nrecv, const uv_buf_t *buf,
isc_result_t result;
isc_nmhandle_t *nmhandle = NULL;
isc_sockaddr_t sockaddr;
isc_sockaddr_t localaddr;
struct sockaddr_storage laddr;
/* isc_sockaddr_t localaddr;
struct sockaddr_storage laddr; */
isc_nmsocket_t *sock = uv_handle_get_data((uv_handle_t *)handle);
isc_region_t region;
uint32_t maxudp;
@@ -326,13 +326,13 @@ udp_recv_cb(uv_udp_t *handle, ssize_t nrecv, const uv_buf_t *buf,
result = isc_sockaddr_fromsockaddr(&sockaddr, addr);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
uv_udp_getsockname(handle, (struct sockaddr *) &laddr,
/* uv_udp_getsockname(handle, (struct sockaddr *) &laddr,
&(int){sizeof(struct sockaddr_storage)});
result = isc_sockaddr_fromsockaddr(&localaddr,
(struct sockaddr *) &laddr);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
RUNTIME_CHECK(result == ISC_R_SUCCESS); */
nmhandle = isc__nmhandle_get(sock, &sockaddr, &localaddr);
nmhandle = isc__nmhandle_get(sock, &sockaddr, NULL);
region.base = (unsigned char *) buf->base;
region.length = nrecv;
@@ -391,8 +391,16 @@ isc__nm_udp_send(isc_nmhandle_t *handle, isc_region_t *region,
return (ISC_R_CANCELED);
}
/*
* If we're in netthread - send it directly
* If the original packet was received over a regular socket
* - send it over the same thread (assuming cpu affinity)
* Otherwise - use a random thread.
*/
if (isc__nm_in_netthread()) {
ntid = isc_nm_tid();
} else if (sock->type == isc_nm_udpsocket) {
ntid = sock->tid;
} else {
ntid = (int) isc_random_uniform(sock->nchildren);
}
+3
View File
@@ -13,6 +13,7 @@
#include <isc/util.h>
#include "uv-compat.h"
#ifndef HAVE_UV_IMPORT
/*
* XXXWPK: This code goes into libuv internals and it's platform dependent.
* It's ugly, we shouldn't do it, but the alternative with passing sockets
@@ -190,3 +191,5 @@ isc_uv_import(uv_stream_t *stream, isc_uv_stream_info_t *info) {
return (uv_tcp_open(tcp, info->fd));
}
#endif
#endif
+10
View File
@@ -33,6 +33,14 @@ uv_handle_set_data(uv_handle_t *handle, void *data) {
};
#endif
#ifdef HAVE_UV_IMPORT
#define isc_uv_stream_info_t uv_stream_info_t
#define isc_uv_export uv_export
#define isc_uv_import uv_import
#else
/*
* These functions are not available in libuv, but they're very internal
* to libuv. We should try to get them merged upstream.
@@ -69,3 +77,5 @@ isc_uv_import(uv_stream_t *stream, isc_uv_stream_info_t *info);
* Imports uv_stream_info_t value into uv_stream_t to initialize a
* shared stream.
*/
#endif
+7 -7
View File
@@ -15,9 +15,9 @@
#include <stdlib.h>
#include <isc/lib.h>
#include <isc/mutex.h>
#include <isc/once.h>
#include <isc/resultclass.h>
#include <isc/rwlock.h>
#include <isc/util.h>
typedef struct resulttable {
@@ -182,7 +182,7 @@ static const char *identifier[ISC_R_NRESULTS] = {
static isc_once_t once = ISC_ONCE_INIT;
static resulttable_list_t description_tables;
static resulttable_list_t identifier_tables;
static isc_mutex_t lock;
static isc_rwlock_t lock;
static isc_result_t
register_table(resulttable_list_t *tables, unsigned int base,
@@ -208,11 +208,11 @@ register_table(resulttable_list_t *tables, unsigned int base,
table->set = set;
ISC_LINK_INIT(table, link);
LOCK(&lock);
RWLOCK(&lock, isc_rwlocktype_write);
ISC_LIST_APPEND(*tables, table, link);
UNLOCK(&lock);
RWUNLOCK(&lock, isc_rwlocktype_write);
return (ISC_R_SUCCESS);
}
@@ -221,7 +221,7 @@ static void
initialize_action(void) {
isc_result_t result;
isc_mutex_init(&lock);
isc_rwlock_init(&lock, 0, 0);
ISC_LIST_INIT(description_tables);
ISC_LIST_INIT(identifier_tables);
@@ -257,7 +257,7 @@ isc_result_tomany_helper(resulttable_list_t *tables, isc_result_t result) {
initialize();
LOCK(&lock);
RWLOCK(&lock, isc_rwlocktype_read);
text = NULL;
for (table = ISC_LIST_HEAD(*tables);
@@ -273,7 +273,7 @@ isc_result_tomany_helper(resulttable_list_t *tables, isc_result_t result) {
text = "(result code text not available)";
}
UNLOCK(&lock);
RWUNLOCK(&lock, isc_rwlocktype_read);
return (text);
}
+6 -1
View File
@@ -17,7 +17,12 @@
#include <isc/util.h>
#include <isc/siphash.h>
#if HAVE_OPENSSL_SIPHASH
/*
* Creation of EVP_MD_CTX and EVP_PKEY is quite expensive, until
* we fix the code to reuse the context and key we'll use our own
* implementation of siphash.
*/
#if 0 /* HAVE_OPENSSL_SIPHASH */
#include <openssl/evp.h>
void
+44 -11
View File
@@ -23,11 +23,14 @@
#include <isc/print.h>
#include <isc/refcount.h>
#include <isc/stats.h>
#include <isc/thread.h>
#include <isc/util.h>
#define ISC_STATS_MAGIC ISC_MAGIC('S', 't', 'a', 't')
#define ISC_STATS_VALID(x) ISC_MAGIC_VALID(x, ISC_STATS_MAGIC)
#define STATS_BUCKETS 64
#if defined(_WIN32) && !defined(_WIN64)
typedef atomic_int_fast32_t isc__atomic_statcounter_t;
#else
@@ -42,6 +45,17 @@ struct isc_stats {
isc__atomic_statcounter_t *counters;
};
ISC_THREAD_LOCAL int isc__stats_thread_v = -1;
static atomic_uint_fast32_t isc__stats_thread_n = 0;
static int
threadhash() {
if (isc__stats_thread_v < 0) {
isc__stats_thread_v = atomic_fetch_add_relaxed(&isc__stats_thread_n, 1) % STATS_BUCKETS;
}
return (isc__stats_thread_v);
}
static isc_result_t
create_stats(isc_mem_t *mctx, int ncounters, isc_stats_t **statsp) {
isc_stats_t *stats;
@@ -50,7 +64,7 @@ create_stats(isc_mem_t *mctx, int ncounters, isc_stats_t **statsp) {
REQUIRE(statsp != NULL && *statsp == NULL);
stats = isc_mem_get(mctx, sizeof(*stats));
counters_alloc_size = sizeof(isc__atomic_statcounter_t) * ncounters;
counters_alloc_size = sizeof(isc__atomic_statcounter_t) * ncounters * STATS_BUCKETS;
stats->counters = isc_mem_get(mctx, counters_alloc_size);
isc_refcount_init(&stats->references, 1);
memset(stats->counters, 0, counters_alloc_size);
@@ -85,7 +99,8 @@ isc_stats_detach(isc_stats_t **statsp) {
isc_refcount_destroy(&stats->references);
isc_mem_put(stats->mctx, stats->counters,
sizeof(isc__atomic_statcounter_t) *
stats->ncounters);
stats->ncounters *
STATS_BUCKETS);
isc_mem_putanddetach(&stats->mctx, stats, sizeof(*stats));
}
}
@@ -108,8 +123,8 @@ void
isc_stats_increment(isc_stats_t *stats, isc_statscounter_t counter) {
REQUIRE(ISC_STATS_VALID(stats));
REQUIRE(counter < stats->ncounters);
atomic_fetch_add_explicit(&stats->counters[counter], 1,
int idx = threadhash() * stats->ncounters + counter;
atomic_fetch_add_explicit(&stats->counters[idx], 1,
memory_order_relaxed);
}
@@ -118,7 +133,8 @@ isc_stats_decrement(isc_stats_t *stats, isc_statscounter_t counter) {
REQUIRE(ISC_STATS_VALID(stats));
REQUIRE(counter < stats->ncounters);
atomic_fetch_sub_explicit(&stats->counters[counter], 1,
int idx = threadhash() * stats->ncounters + counter;
atomic_fetch_sub_explicit(&stats->counters[idx], 1,
memory_order_relaxed);
}
@@ -131,8 +147,13 @@ isc_stats_dump(isc_stats_t *stats, isc_stats_dumper_t dump_fn,
REQUIRE(ISC_STATS_VALID(stats));
for (i = 0; i < stats->ncounters; i++) {
uint32_t counter = atomic_load_explicit(&stats->counters[i],
uint32_t counter = 0;
int b;
for (b = 0; b < STATS_BUCKETS; b++) {
int idx = stats->ncounters * b + i;
counter += atomic_load_explicit(&stats->counters[idx],
memory_order_relaxed);
}
if ((options & ISC_STATSDUMP_VERBOSE) == 0 && counter == 0) {
continue;
}
@@ -144,11 +165,17 @@ void
isc_stats_set(isc_stats_t *stats, uint64_t val,
isc_statscounter_t counter)
{
int i;
REQUIRE(ISC_STATS_VALID(stats));
REQUIRE(counter < stats->ncounters);
atomic_store_explicit(&stats->counters[counter], val,
memory_order_relaxed);
for (i = 1; i < STATS_BUCKETS; i++) {
int idx = stats->ncounters * i + counter;
atomic_store_explicit(&stats->counters[idx], val,
memory_order_relaxed);
}
}
void isc_stats_update_if_greater(isc_stats_t *stats,
@@ -158,9 +185,9 @@ void isc_stats_update_if_greater(isc_stats_t *stats,
REQUIRE(ISC_STATS_VALID(stats));
REQUIRE(counter < stats->ncounters);
isc_statscounter_t curr_value =
atomic_load_relaxed(&stats->counters[counter]);
isc_statscounter_t curr_value;
do {
curr_value = atomic_load_relaxed(&stats->counters[counter]);
if (curr_value >= value) {
break;
}
@@ -172,9 +199,15 @@ void isc_stats_update_if_greater(isc_stats_t *stats,
isc_statscounter_t
isc_stats_get_counter(isc_stats_t *stats, isc_statscounter_t counter)
{
uint32_t value = 0;
int i;
REQUIRE(ISC_STATS_VALID(stats));
REQUIRE(counter < stats->ncounters);
return (atomic_load_explicit(&stats->counters[counter],
memory_order_relaxed));
for (i = 0; i < STATS_BUCKETS; i++) {
int idx = i * stats->ncounters + counter;
value += atomic_load_explicit(&stats->counters[idx],
memory_order_relaxed);
}
return (value);
}
+46 -28
View File
@@ -106,6 +106,7 @@ struct isc__task {
isc_mutex_t lock;
/* Locked by task lock. */
task_state_t state;
int pause_cnt;
isc_refcount_t references;
isc_eventlist_t events;
isc_eventlist_t on_shutdown;
@@ -308,6 +309,7 @@ isc_task_create_bound(isc_taskmgr_t *manager0, unsigned int quantum,
isc_mutex_init(&task->lock);
task->state = task_state_idle;
task->pause_cnt = 0;
isc_refcount_init(&task->references, 1);
INIT_LIST(task->events);
@@ -407,7 +409,7 @@ task_shutdown(isc__task_t *task) {
/*
* Moves a task onto the appropriate run queue.
*
* Caller must NOT hold manager lock.
* Caller must NOT hold queue lock.
*/
static inline void
task_ready(isc__task_t *task) {
@@ -415,7 +417,6 @@ task_ready(isc__task_t *task) {
bool has_privilege = isc_task_privilege((isc_task_t *) task);
REQUIRE(VALID_MANAGER(manager));
REQUIRE(task->state == task_state_ready);
XTRACE("task_ready");
LOCK(&manager->queues[task->threadid].lock);
@@ -967,10 +968,13 @@ pop_readyq(isc__taskmgr_t *manager, int c) {
* Push 'task' onto the ready_tasks queue. If 'task' has the privilege
* flag set, then also push it onto the ready_priority_tasks queue.
*
* Caller must hold the task manager lock.
* Caller must hold the task queue lock.
*/
static inline void
push_readyq(isc__taskmgr_t *manager, isc__task_t *task, int c) {
if (ISC_LINK_LINKED(task, ready_link)) {
return;
}
ENQUEUE(manager->queues[c].ready_tasks, task, ready_link);
if (TASK_PRIVILEGED(task)) {
ENQUEUE(manager->queues[c].ready_priority_tasks, task,
@@ -1128,6 +1132,17 @@ dispatch(isc__taskmgr_t *manager, unsigned int threadid) {
memory_order_acquire);
LOCK(&task->lock);
/*
* It is possible because that we have a paused task
* in the queue - it might have been paused in the
* meantime and we never hold both queue and task lock
* to avoid deadlocks, just bail then.
*/
if (task->state != task_state_ready) {
UNLOCK(&task->lock);
LOCK(&manager->queues[threadid].lock);
continue;
}
INSIST(task->state == task_state_ready);
task->state = task_state_running;
XTRACE("running");
@@ -1215,6 +1230,15 @@ dispatch(isc__taskmgr_t *manager, unsigned int threadid) {
}
}
done = true;
} else if (task->state == task_state_pausing) {
/*
* We got a pause request on this task,
* stop working on it and switch the state
* to paused.
*/
XTRACE("pausing");
task->state = task_state_paused;
done = true;
} else if (dispatch_count >= task->quantum) {
/*
* Our quantum has expired, but
@@ -1227,17 +1251,8 @@ dispatch(isc__taskmgr_t *manager, unsigned int threadid) {
* so the minimum quantum is one.
*/
XTRACE("quantum");
if (task->state == task_state_running) {
/*
* We requeue only if it's
* not paused.
*/
task->state = task_state_ready;
requeue = true;
} else if (task->state ==
task_state_pausing) {
task->state = task_state_paused;
}
task->state = task_state_ready;
requeue = true;
done = true;
}
} while (!done);
@@ -1686,31 +1701,27 @@ void
isc_task_pause(isc_task_t *task0) {
REQUIRE(ISCAPI_TASK_VALID(task0));
isc__task_t *task = (isc__task_t *)task0;
isc__taskmgr_t *manager = task->manager;
bool running = false;
LOCK(&task->lock);
task->pause_cnt++;
if (task->pause_cnt > 1) {
/*
* Someone already paused this thread, just increase
* the number of pausing clients.
*/
UNLOCK(&task->lock);
return;
}
INSIST(task->state == task_state_idle ||
task->state == task_state_ready ||
task->state == task_state_running);
if (task->state == task_state_running) {
running = true;
task->state = task_state_pausing;
} else {
task->state = task_state_paused;
}
UNLOCK(&task->lock);
if (running) {
return;
}
LOCK(&manager->queues[task->threadid].lock);
if (ISC_LINK_LINKED(task, ready_link)) {
DEQUEUE(manager->queues[task->threadid].ready_tasks,
task, ready_link);
}
UNLOCK(&manager->queues[task->threadid].lock);
}
void
@@ -1721,6 +1732,13 @@ isc_task_unpause(isc_task_t *task0) {
REQUIRE(ISCAPI_TASK_VALID(task0));
LOCK(&task->lock);
task->pause_cnt--;
INSIST(task->pause_cnt >= 0);
if (task->pause_cnt > 0) {
UNLOCK(&task->lock);
return;
}
INSIST(task->state == task_state_paused ||
task->state == task_state_pausing);
/* If the task was pausing we can't reschedule it */
+14 -14
View File
@@ -135,11 +135,7 @@ int isc_dscp_check_value = -1;
*/
#ifndef ISC_SOCKET_MAXSOCKETS
#if defined(USE_KQUEUE) || defined(USE_EPOLL) || defined(USE_DEVPOLL)
#ifdef TUNE_LARGE
#define ISC_SOCKET_MAXSOCKETS 21000
#else
#define ISC_SOCKET_MAXSOCKETS 4096
#endif /* TUNE_LARGE */
#define ISC_SOCKET_MAXSOCKETS 65536
#elif defined(USE_SELECT)
#define ISC_SOCKET_MAXSOCKETS FD_SETSIZE
#endif /* USE_KQUEUE... */
@@ -1834,7 +1830,6 @@ destroy(isc__socket_t **sockp) {
socket_log(sock, NULL, CREATION, "destroying");
isc_refcount_destroy(&sock->references);
LOCK(&sock->lock);
INSIST(ISC_LIST_EMPTY(sock->connect_list));
@@ -1862,6 +1857,7 @@ destroy(isc__socket_t **sockp) {
if (ISC_LIST_EMPTY(manager->socklist)) {
SIGNAL(&manager->shutdown_ok);
}
isc_refcount_destroy(&sock->references);
/* can't unlock manager as its memory context is still used */
free_socket(sockp);
@@ -2631,7 +2627,6 @@ isc_socket_detach(isc_socket_t **socketp) {
REQUIRE(socketp != NULL);
sock = (isc__socket_t *)*socketp;
REQUIRE(VALID_SOCKET(sock));
if (isc_refcount_decrement(&sock->references) == 1) {
destroy(&sock);
}
@@ -3149,16 +3144,20 @@ process_fd(isc__socketthread_t *thread, int fd, bool readable,
return;
}
if (isc_refcount_increment0(&sock->references) == 0) {
LOCK(&sock->lock);
if (isc_refcount_current(&sock->references) == 0) {
/*
* Sock is being closed, it will be destroyed, bail.
* Sock is being closed - the final external reference
* is gone but it was not yet removed from event loop
* and fdstate[]/fds[] as destroy() is waiting on
* thread->fdlock[lockid] or sock->lock that we're holding.
* Just release the locks and bail.
*/
(void)isc_refcount_decrement(&sock->references);
UNLOCK(&sock->lock);
UNLOCK(&thread->fdlock[lockid]);
return;
}
LOCK(&sock->lock);
if (readable) {
if (sock->listener) {
internal_accept(sock);
@@ -3177,9 +3176,10 @@ process_fd(isc__socketthread_t *thread, int fd, bool readable,
UNLOCK(&sock->lock);
UNLOCK(&thread->fdlock[lockid]);
if (isc_refcount_decrement(&sock->references) == 1) {
destroy(&sock);
}
/*
* Socket destruction might be pending, it will resume
* after releasing fdlock and sock->lock.
*/
}
/*
-2
View File
@@ -685,8 +685,6 @@ isc_timermgr_destroy
isc_timermgr_poke
isc_tm_timegm
isc_tm_strptime
isc_uv_export
isc_uv_import
isc_win32os_versioncheck
openlog
@IF PKCS11
+122 -73
View File
@@ -79,7 +79,6 @@
* task to change the client, then the client will have to be locked.
*/
#define NS_CLIENT_TRACE
#ifdef NS_CLIENT_TRACE
#define CTRACE(m) ns_client_log(client, \
NS_LOGCATEGORY_CLIENT, \
@@ -132,6 +131,8 @@ static void compute_cookie(ns_client_t *client, uint32_t when,
isc_buffer_t *buf);
static void
get_clientmctx(ns_clientmgr_t *manager, isc_mem_t **mctxp);
static void
get_clienttask(ns_clientmgr_t *manager, isc_task_t **taskp);
void
ns_client_recursing(ns_client_t *client) {
@@ -171,21 +172,19 @@ ns_client_settimeout(ns_client_t *client, unsigned int seconds) {
static void
ns_client_endrequest(ns_client_t *client) {
INSIST(client->naccepts == 0);
INSIST(client->nreads == 0);
INSIST(client->nsends == 0);
INSIST(client->nrecvs == 0);
INSIST(client->nupdates == 0);
INSIST(client->state == NS_CLIENTSTATE_WORKING ||
client->state == NS_CLIENTSTATE_RECURSING);
CTRACE("endrequest");
LOCK(&client->manager->reclock);
if (ISC_LINK_LINKED(client, rlink)) {
ISC_LIST_UNLINK(client->manager->recursing, client, rlink);
if (client->state == NS_CLIENTSTATE_RECURSING) {
LOCK(&client->manager->reclock);
if (ISC_LINK_LINKED(client, rlink)) {
ISC_LIST_UNLINK(client->manager->recursing, client, rlink);
}
UNLOCK(&client->manager->reclock);
}
UNLOCK(&client->manager->reclock);
if (client->cleanup != NULL) {
(client->cleanup)(client);
@@ -338,13 +337,15 @@ client_allocsendbuf(ns_client_t *client, isc_buffer_t *buffer,
}
static isc_result_t
client_sendpkg(ns_client_t *client, isc_buffer_t *buffer) {
client_sendpkg(ns_client_t *client, isc_buffer_t *buffer, bool lowac) {
isc_region_t r;
isc_buffer_usedregion(buffer, &r);
INSIST(client->handle != NULL);
if (lowac && client->view != NULL) {
dns_lowac_put(client->view->lowac, ISC_LIST_HEAD(client->message->sections[0]), (char*) r.base, r.length);
}
return (isc_nm_send(client->handle, &r, client_senddone, client));
}
@@ -380,7 +381,7 @@ ns_client_sendraw(ns_client_t *client, dns_message_t *message) {
r.base[0] = (client->message->id >> 8) & 0xff;
r.base[1] = client->message->id & 0xff;
result = client_sendpkg(client, &buffer);
result = client_sendpkg(client, &buffer, true);
if (result == ISC_R_SUCCESS) {
return;
}
@@ -597,7 +598,7 @@ ns_client_send(ns_client_t *client) {
respsize = isc_buffer_usedlength(&tcpbuffer) - 2;
isc_nmhandle_ref(client->handle);
result = client_sendpkg(client, &tcpbuffer);
result = client_sendpkg(client, &tcpbuffer, true);
if (result != ISC_R_SUCCESS) {
/* We won't get a callback to clean it up */
isc_nmhandle_unref(client->handle);
@@ -634,7 +635,7 @@ ns_client_send(ns_client_t *client) {
respsize = isc_buffer_usedlength(&buffer);
isc_nmhandle_ref(client->handle);
result = client_sendpkg(client, &buffer);
result = client_sendpkg(client, &buffer, true);
if (result != ISC_R_SUCCESS) {
/* We won't get a callback to clean it up */
isc_nmhandle_unref(client->handle);
@@ -1571,7 +1572,7 @@ ns__client_put_cb(void *client0) {
clientmgr_detach(&client->manager);
}
isc_mem_put(client->mctx, client->recvbuf, NS_CLIENT_RECV_BUFFER_SIZE);
isc_mem_put(client->mctx, client->sendbuf, NS_CLIENT_SEND_BUFFER_SIZE);
if (client->opt != NULL) {
INSIST(dns_rdataset_isassociated(client->opt));
dns_rdataset_disassociate(client->opt);
@@ -1605,6 +1606,51 @@ ns__client_put_cb(void *client0) {
}
}
static isc_result_t
lowac_checksend(ns_client_t *client) {
isc_result_t result;
unsigned char *data;
isc_buffer_t buffer;
isc_buffer_t tcpbuffer;
isc_region_t r;
result = client_allocsendbuf(client, &buffer, &tcpbuffer, 0,
&data);
if (result != ISC_R_SUCCESS) {
return (result);
}
int blen;
result = dns_lowac_get(client->view->lowac, ISC_LIST_HEAD(client->message->sections[0]), data, &blen, false);
if (result != ISC_R_SUCCESS) {
goto done;
}
if (TCP_CLIENT(client)) {
data[2] = (client->message->id >> 8) & 0xff;
data[3] = client->message->id & 0xff;
} else {
data[0] = (client->message->id >> 8) & 0xff;
data[1] = client->message->id & 0xff;
}
isc_buffer_add(&buffer, blen);
isc_nmhandle_ref(client->handle);
if (client->sendcb != NULL) {
client->sendcb(&buffer);
} else if (TCP_CLIENT(client)) {
isc_buffer_usedregion(&buffer, &r);
isc_buffer_putuint16(&tcpbuffer, (uint16_t) r.length);
isc_buffer_add(&tcpbuffer, r.length);
result = client_sendpkg(client, &tcpbuffer, false);
} else {
result = client_sendpkg(client, &buffer, false);
}
done:
if (client->tcpbuf != NULL) {
isc_mem_put(client->mctx, client->tcpbuf, NS_CLIENT_TCP_BUFFER_SIZE);
client->tcpbuf = NULL;
}
return result;
}
/*
* Handle an incoming request event from the socket (UDP case)
* or tcpmsg (TCP case).
@@ -1662,7 +1708,6 @@ ns__client_request(isc_nmhandle_t *handle, isc_region_t *region, void *arg) {
}
client->state = NS_CLIENTSTATE_READY;
client->dscp = ifp->dscp;
isc_task_pause(client->task);
if (client->handle == NULL) {
@@ -1997,6 +2042,12 @@ ns__client_request(isc_nmhandle_t *handle, isc_region_t *region, void *arg) {
NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(5),
"using view '%s'", client->view->name);
result = lowac_checksend(client);
if (result == ISC_R_SUCCESS) {
isc_task_unpause(client->task);
return;
}
/*
* Check for a signature. We log bad signatures regardless of
* whether they ultimately cause the request to be rejected or
@@ -2212,38 +2263,33 @@ ns__client_tcpconn(isc_nmhandle_t *handle, isc_result_t result, void *arg) {
static void
get_clientmctx(ns_clientmgr_t *manager, isc_mem_t **mctxp) {
isc_mem_t *clientmctx;
#if CLIENT_NMCTXS > 0
unsigned int nextmctx;
#endif
MTRACE("clientmctx");
#if CLIENT_NMCTXS > 0
LOCK(&manager->lock);
if (isc_nm_tid() >= 0) {
nextmctx = isc_nm_tid();
} else {
nextmctx = manager->nextmctx++;
if (manager->nextmctx == CLIENT_NMCTXS)
manager->nextmctx = 0;
INSIST(nextmctx < CLIENT_NMCTXS);
int tid = isc_nm_tid();
if (tid < 0) {
tid = isc_random_uniform(manager->ncpus);
}
int rand = isc_random_uniform(CLIENT_NMCTXS_PERCPU);
int nextmctx = (rand * manager->ncpus) + tid;
clientmctx = manager->mctxpool[nextmctx];
if (clientmctx == NULL) {
isc_mem_create(&clientmctx);
isc_mem_setname(clientmctx, "client", NULL);
manager->mctxpool[nextmctx] = clientmctx;
}
UNLOCK(&manager->lock);
#else
clientmctx = manager->mctx;
#endif
isc_mem_attach(clientmctx, mctxp);
}
static void
get_clienttask(ns_clientmgr_t *manager, isc_task_t **taskp) {
MTRACE("clienttask");
int tid = isc_nm_tid();
if (tid < 0) {
tid = isc_random_uniform(manager->ncpus);
}
int rand = isc_random_uniform(CLIENT_NTASKS_PERCPU);
int nexttask = (rand * manager->ncpus) + tid;
isc_task_attach(manager->taskpool[nexttask], taskp);
}
isc_result_t
ns__client_setup(ns_client_t *client, ns_clientmgr_t *mgr, bool new) {
isc_result_t result;
@@ -2267,10 +2313,8 @@ ns__client_setup(ns_client_t *client, ns_clientmgr_t *mgr, bool new) {
get_clientmctx(mgr, &client->mctx);
clientmgr_attach(mgr, &client->manager);
ns_server_attach(mgr->sctx, &client->sctx);
result = isc_task_create(mgr->taskmgr, 20, &client->task);
if (result != ISC_R_SUCCESS) {
goto cleanup;
}
get_clienttask(mgr, &client->task);
result = dns_message_create(client->mctx,
DNS_MESSAGE_INTENTPARSE,
&client->message);
@@ -2279,8 +2323,8 @@ ns__client_setup(ns_client_t *client, ns_clientmgr_t *mgr, bool new) {
}
client->recvbuf = isc_mem_get(client->mctx,
NS_CLIENT_RECV_BUFFER_SIZE);
client->sendbuf = isc_mem_get(client->mctx,
NS_CLIENT_SEND_BUFFER_SIZE);
/*
* Set magic earlier than usual because ns_query_init()
* and the functions it calls will require it.
@@ -2294,7 +2338,7 @@ ns__client_setup(ns_client_t *client, ns_clientmgr_t *mgr, bool new) {
ns_clientmgr_t *oldmgr = client->manager;
ns_server_t *sctx = client->sctx;
isc_task_t *task = client->task;
unsigned char *recvbuf = client->recvbuf;
unsigned char *sendbuf = client->sendbuf;
dns_message_t *message = client->message;
isc_mem_t *oldmctx = client->mctx;
ns_query_t query = client->query;
@@ -2305,7 +2349,7 @@ ns__client_setup(ns_client_t *client, ns_clientmgr_t *mgr, bool new) {
.manager = oldmgr,
.sctx = sctx,
.task = task,
.recvbuf = recvbuf,
.sendbuf = sendbuf,
.message = message,
.query = query
};
@@ -2313,7 +2357,6 @@ ns__client_setup(ns_client_t *client, ns_clientmgr_t *mgr, bool new) {
client->state = NS_CLIENTSTATE_INACTIVE;
client->udpsize = 512;
client->dscp = -1;
client->ednsversion = -1;
dns_name_init(&client->signername, NULL);
dns_ecs_init(&client->ecs);
@@ -2330,9 +2373,9 @@ ns__client_setup(ns_client_t *client, ns_clientmgr_t *mgr, bool new) {
return (ISC_R_SUCCESS);
cleanup:
if (client->recvbuf != NULL) {
isc_mem_put(client->mctx, client->recvbuf,
NS_CLIENT_RECV_BUFFER_SIZE);
if (client->sendbuf != NULL) {
isc_mem_put(client->mctx, client->sendbuf,
NS_CLIENT_SEND_BUFFER_SIZE);
}
if (client->message != NULL) {
@@ -2397,21 +2440,18 @@ clientmgr_detach(ns_clientmgr_t **mp) {
static void
clientmgr_destroy(ns_clientmgr_t *manager) {
#if CLIENT_NMCTXS > 0
int i;
#endif
MTRACE("clientmgr_destroy");
isc_refcount_destroy(&manager->references);
manager->magic = 0;
#if CLIENT_NMCTXS > 0
for (i = 0; i < CLIENT_NMCTXS; i++) {
if (manager->mctxpool[i] != NULL)
isc_mem_detach(&manager->mctxpool[i]);
for (i = 0; i < manager->ncpus * CLIENT_NMCTXS_PERCPU; i++) {
isc_mem_detach(&manager->mctxpool[i]);
}
#endif
isc_mem_put(manager->mctx, manager->mctxpool,
manager->ncpus * CLIENT_NMCTXS_PERCPU * sizeof(isc_mem_t*));
if (manager->interface != NULL) {
ns_interface_detach(&manager->interface);
@@ -2423,13 +2463,14 @@ clientmgr_destroy(ns_clientmgr_t *manager) {
if (manager->excl != NULL)
isc_task_detach(&manager->excl);
for (i = 0; i < CLIENT_NTASKS; i++) {
for (i = 0; i < manager->ncpus * CLIENT_NTASKS_PERCPU; i++) {
if (manager->taskpool[i] != NULL) {
isc_task_detach(&manager->taskpool[i]);
}
}
isc_mem_put(manager->mctx, manager->taskpool,
CLIENT_NTASKS * sizeof(isc_task_t *));
manager->ncpus * CLIENT_NTASKS_PERCPU *
sizeof(isc_task_t *));
ns_server_detach(&manager->sctx);
isc_mem_put(manager->mctx, manager, sizeof(*manager));
@@ -2438,13 +2479,12 @@ clientmgr_destroy(ns_clientmgr_t *manager) {
isc_result_t
ns_clientmgr_create(isc_mem_t *mctx, ns_server_t *sctx, isc_taskmgr_t *taskmgr,
isc_timermgr_t *timermgr, ns_interface_t *interface,
ns_clientmgr_t **managerp)
int ncpus, ns_clientmgr_t **managerp)
{
ns_clientmgr_t *manager;
isc_result_t result;
#if CLIENT_NMCTXS > 0
int i;
#endif
int npools;
manager = isc_mem_get(mctx, sizeof(*manager));
*manager = (ns_clientmgr_t) { .magic = 0 };
@@ -2461,26 +2501,35 @@ ns_clientmgr_create(isc_mem_t *mctx, ns_server_t *sctx, isc_taskmgr_t *taskmgr,
manager->mctx = mctx;
manager->taskmgr = taskmgr;
manager->timermgr = timermgr;
manager->ncpus = ncpus;
ns_interface_attach(interface, &manager->interface);
manager->exiting = false;
manager->taskpool =
isc_mem_get(mctx, CLIENT_NTASKS*sizeof(isc_task_t *));
for (i = 0; i < CLIENT_NTASKS; i++) {
int ntasks = CLIENT_NTASKS_PERCPU * manager->ncpus;
manager->taskpool = isc_mem_get(mctx, ntasks * sizeof(isc_task_t *));
for (i = 0; i < ntasks; i++) {
manager->taskpool[i] = NULL;
isc_task_create(manager->taskmgr, 20, &manager->taskpool[i]);
result = isc_task_create_bound(manager->taskmgr, 20,
&manager->taskpool[i],
i % CLIENT_NTASKS_PERCPU);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
}
isc_refcount_init(&manager->references, 1);
manager->sctx = NULL;
ns_server_attach(sctx, &manager->sctx);
ISC_LIST_INIT(manager->recursing);
#if CLIENT_NMCTXS > 0
manager->nextmctx = 0;
for (i = 0; i < CLIENT_NMCTXS; i++)
manager->mctxpool[i] = NULL; /* will be created on-demand */
#endif
npools = CLIENT_NMCTXS_PERCPU * manager->ncpus;
manager->mctxpool = isc_mem_get(manager->mctx,
npools * sizeof(isc_mem_t*));
for (i = 0; i < npools; i++) {
manager->mctxpool[i] = NULL;
isc_mem_create(&manager->mctxpool[i]);
isc_mem_setname(manager->mctxpool[i], "client", NULL);
}
manager->magic = MANAGER_MAGIC;
MTRACE("create");
+6 -17
View File
@@ -85,7 +85,7 @@
#define NS_CLIENT_SEND_BUFFER_SIZE 4096
#define NS_CLIENT_RECV_BUFFER_SIZE 4096
#define CLIENT_NMCTXS 100
#define CLIENT_NMCTXS_PERCPU 8
/*%<
* Number of 'mctx pools' for clients. (Should this be configurable?)
* When enabling threads, we use a pool of memory contexts shared by
@@ -95,7 +95,7 @@
* server.
*/
#define CLIENT_NTASKS 100
#define CLIENT_NTASKS_PERCPU 32
/*%<
* Number of tasks to be used by clients - those are used only when recursing
*/
@@ -166,6 +166,7 @@ struct ns_clientmgr {
isc_timermgr_t * timermgr;
isc_task_t * excl;
isc_refcount_t references;
int ncpus;
/* Attached by clients, needed for e.g. recursion */
isc_task_t ** taskpool;
@@ -180,11 +181,8 @@ struct ns_clientmgr {
isc_mutex_t reclock;
client_list_t recursing; /*%< Recursing clients */
#if CLIENT_NMCTXS > 0
/*%< mctx pool for clients. */
unsigned int nextmctx;
isc_mem_t * mctxpool[CLIENT_NMCTXS];
#endif
isc_mem_t ** mctxpool;
};
/*% nameserver client structure */
@@ -195,12 +193,7 @@ struct ns_client {
ns_server_t *sctx;
ns_clientmgr_t *manager;
ns_clientstate_t state;
int naccepts;
int nreads;
int nsends;
int nrecvs;
int nupdates;
int nctls;
bool shuttingdown;
unsigned int attributes;
isc_task_t *task;
@@ -209,8 +202,7 @@ struct ns_client {
isc_nmhandle_t *handle;
unsigned char *tcpbuf;
dns_message_t *message;
unsigned char *recvbuf;
unsigned char sendbuf[NS_CLIENT_SEND_BUFFER_SIZE];
unsigned char *sendbuf;
dns_rdataset_t *opt;
uint16_t udpsize;
uint16_t extflags;
@@ -224,7 +216,6 @@ struct ns_client {
isc_time_t tnow;
dns_name_t signername; /*%< [T]SIG key name */
dns_name_t *signer; /*%< NULL if not valid sig */
bool mortal; /*%< Die after handling request */
isc_quota_t *recursionquota;
isc_sockaddr_t peeraddr;
@@ -234,8 +225,6 @@ struct ns_client {
dns_ecs_t ecs; /*%< EDNS client subnet sent by client */
struct in6_pktinfo pktinfo;
isc_dscp_t dscp;
/*%
* Information about recent FORMERR response(s), for
* FORMERR loop avoidance. This is separate for each
@@ -364,7 +353,7 @@ ns_client_settimeout(ns_client_t *client, unsigned int seconds);
isc_result_t
ns_clientmgr_create(isc_mem_t *mctx, ns_server_t *sctx, isc_taskmgr_t *taskmgr,
isc_timermgr_t *timermgr, ns_interface_t *ifp,
isc_timermgr_t *timermgr, ns_interface_t *ifp, int ncpus,
ns_clientmgr_t **managerp);
/*%<
* Create a client manager.
+1 -1
View File
@@ -103,7 +103,7 @@ ns_interfacemgr_create(isc_mem_t *mctx, ns_server_t *sctx,
isc_socketmgr_t *socketmgr, isc_nm_t *nm,
dns_dispatchmgr_t *dispatchmgr, isc_task_t *task,
unsigned int udpdisp, dns_geoip_databases_t *geoip,
ns_interfacemgr_t **mgrp);
int ncpus, ns_interfacemgr_t **mgrp);
/*%<
* Create a new interface manager.
*
+4 -1
View File
@@ -75,6 +75,7 @@ struct ns_interfacemgr {
isc_timermgr_t * timermgr; /*%< Timer manager. */
isc_socketmgr_t * socketmgr; /*%< Socket manager. */
isc_nm_t * nm; /*%< Net manager. */
int ncpus; /*%< Number of workers . */
dns_dispatchmgr_t * dispatchmgr;
unsigned int generation; /*%< Current generation no. */
ns_listenlist_t * listenon4;
@@ -181,6 +182,7 @@ ns_interfacemgr_create(isc_mem_t *mctx,
isc_task_t *task,
unsigned int udpdisp,
dns_geoip_databases_t *geoip,
int ncpus,
ns_interfacemgr_t **mgrp)
{
isc_result_t result;
@@ -219,6 +221,7 @@ ns_interfacemgr_create(isc_mem_t *mctx,
mgr->listenon4 = NULL;
mgr->listenon6 = NULL;
mgr->udpdisp = udpdisp;
mgr->ncpus = ncpus;
atomic_init(&mgr->shuttingdown, false);
ISC_LIST_INIT(mgr->interfaces);
@@ -425,7 +428,7 @@ ns_interface_create(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr,
result = ns_clientmgr_create(mgr->mctx, mgr->sctx,
mgr->taskmgr, mgr->timermgr, ifp,
&ifp->clientmgr);
mgr->ncpus, &ifp->clientmgr);
if (result != ISC_R_SUCCESS) {
isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
"ns_clientmgr_create() failed: %s",
+1 -1
View File
@@ -237,7 +237,7 @@ create_managers(void) {
CHECK(ns_interfacemgr_create(mctx, sctx, taskmgr, timermgr,
socketmgr, nm, dispatchmgr, maintask,
ncpus, NULL, &interfacemgr));
ncpus, NULL, 1, &interfacemgr));
CHECK(ns_listenlist_default(mctx, port, -1, true, &listenon));
ns_interfacemgr_setlistenon4(interfacemgr, listenon);
+7
View File
@@ -223,6 +223,9 @@ my @substdefh = ("CONFIGARGS",
"HAVE_HMAC_CTX_GET_MD",
"HAVE_HMAC_CTX_NEW",
"HAVE_HMAC_CTX_RESET",
"HAVE_UV_HANDLE_GET_DATA",
"HAVE_UV_HANDLE_SET_DATA",
"HAVE_UV_IMPORT",
);
# for platform.h
@@ -1321,6 +1324,10 @@ if ($use_libuv eq "auto") {
last;
}
}
$configdefh{"HAVE_UV_HANDLE_SET_DATA"} = 1;
$configdefh{"HAVE_UV_HANDLE_GET_DATA"} = 1;
$configdefh{"HAVE_UV_IMPORT"} = 1;
# If we have one use it otherwise report the error
if ($use_libuv eq "auto") {