commit f4a243d: [Rework] Rdns: Use faster and more compact hash table for DNS requests
Vsevolod Stakhov
vsevolod at highsecure.ru
Wed Jan 5 11:28:05 UTC 2022
Author: Vsevolod Stakhov
Date: 2022-01-01 17:05:59 +0000
URL: https://github.com/rspamd/rspamd/commit/f4a243daac590cc1e4db686a173795eb461b7205
[Rework] Rdns: Use faster and more compact hash table for DNS requests
---
contrib/librdns/dns_private.h | 5 ++-
contrib/librdns/resolver.c | 91 ++++++++++++++++++-------------------------
contrib/librdns/util.c | 54 +++++++++++++++++++++----
contrib/librdns/util.h | 7 ++++
4 files changed, 95 insertions(+), 62 deletions(-)
diff --git a/contrib/librdns/dns_private.h b/contrib/librdns/dns_private.h
index 5d77cbebe..f59fa2719 100644
--- a/contrib/librdns/dns_private.h
+++ b/contrib/librdns/dns_private.h
@@ -27,6 +27,7 @@
#include "config.h"
#include "uthash.h"
#include "utlist.h"
+#include "khash.h"
#include "rdns.h"
#include "upstream.h"
#include "ref.h"
@@ -107,7 +108,7 @@ enum rdns_io_channel_flags {
#define IS_CHANNEL_CONNECTED(ioc) (((ioc)->flags & RDNS_CHANNEL_CONNECTED) != 0)
#define IS_CHANNEL_ACTIVE(ioc) (((ioc)->flags & RDNS_CHANNEL_ACTIVE) != 0)
-
+KHASH_DECLARE(rdns_requests_hash, int, struct rdns_request *);
/**
* IO channel for a specific DNS server
*/
@@ -119,7 +120,7 @@ struct rdns_io_channel {
int sock; /**< persistent socket */
int flags; /**< see enum rdns_io_channel_flags */
void *async_io; /** async opaque ptr */
- struct rdns_request *requests; /**< requests in flight */
+ khash_t(rdns_requests_hash) *requests;
uint64_t uses;
ref_entry_t ref;
};
diff --git a/contrib/librdns/resolver.c b/contrib/librdns/resolver.c
index b100322b1..6b1ed8211 100644
--- a/contrib/librdns/resolver.c
+++ b/contrib/librdns/resolver.c
@@ -41,29 +41,37 @@
#include "logger.h"
#include "compression.h"
+__KHASH_IMPL(rdns_requests_hash, kh_inline, int, struct rdns_request *, true,
+ kh_int_hash_func, kh_int_hash_equal);
+
static int
rdns_send_request (struct rdns_request *req, int fd, bool new_req)
{
- int r;
+ ssize_t r;
struct rdns_server *serv = req->io->srv;
struct rdns_resolver *resolver = req->resolver;
- struct rdns_request *tmp;
struct dns_header *header;
const int max_id_cycles = 32;
+ khiter_t k;
/* Find ID collision */
if (new_req) {
r = 0;
- HASH_FIND_INT (req->io->requests, &req->id, tmp);
- while (tmp != NULL) {
- /* Check for unique id */
- header = (struct dns_header *)req->packet;
- header->qid = rdns_permutor_generate_id ();
- req->id = header->qid;
- if (++r > max_id_cycles) {
- return -1;
+
+ for (;;) {
+ k = kh_get(rdns_requests_hash, req->io->requests, req->id);
+ if (k != kh_end(req->io->requests)) {
+ /* Check for unique id */
+ header = (struct dns_header *) req->packet;
+ header->qid = rdns_permutor_generate_id();
+ req->id = header->qid;
+ if (++r > max_id_cycles) {
+ return -1;
+ }
+ }
+ else {
+ break;
}
- HASH_FIND_INT (req->io->requests, &req->id, tmp);
}
}
@@ -95,7 +103,10 @@ rdns_send_request (struct rdns_request *req, int fd, bool new_req)
if (errno == EAGAIN || errno == EINTR) {
if (new_req) {
/* Write when socket is ready */
- HASH_ADD_INT (req->io->requests, id, req);
+ int pr;
+
+ k = kh_put(rdns_requests_hash, req->io->requests, req->id, &pr);
+ kh_value(req->io->requests, k) = req;
req->async_event = resolver->async->add_write (resolver->async->data,
fd, req);
req->state = RDNS_REQUEST_WAIT_SEND;
@@ -126,7 +137,9 @@ rdns_send_request (struct rdns_request *req, int fd, bool new_req)
if (new_req) {
/* Add request to hash table */
- HASH_ADD_INT (req->io->requests, id, req);
+ int pr;
+ k = kh_put(rdns_requests_hash, req->io->requests, req->id, &pr);
+ kh_value(req->io->requests, k) = req;
/* Fill timeout */
req->async_event = resolver->async->add_timer (resolver->async->data,
req->timeout, req);
@@ -160,18 +173,18 @@ static struct rdns_request *
rdns_find_dns_request (uint8_t *in, struct rdns_io_channel *ioc)
{
struct dns_header *header = (struct dns_header *)in;
- struct rdns_request *req;
int id;
struct rdns_resolver *resolver = ioc->resolver;
id = header->qid;
- HASH_FIND_INT (ioc->requests, &id, req);
- if (req == NULL) {
+ khiter_t k = kh_get(rdns_requests_hash, ioc->requests, id);
+
+ if (k == kh_end(ioc->requests)) {
/* No such requests found */
- rdns_debug ("DNS request with id %d has not been found for IO channel", (int)id);
+ rdns_debug ("DNS request with id %d has not been found for IO channel", id);
}
- return req;
+ return kh_value(ioc->requests, k);
}
static bool
@@ -442,7 +455,7 @@ rdns_process_timer (void *arg)
req->async->del_timer (req->async->data,
req->async_event);
req->async_event = NULL;
- HASH_DEL (req->io->requests, req);
+ kh_del(rdns_requests_hash, req->io->requests, req->id);
}
/* We have not scheduled timeout actually due to send error */
@@ -479,25 +492,13 @@ rdns_process_ioc_refresh (void *arg)
ioc = serv->io_channels[i];
if (ioc->uses > resolver->max_ioc_uses) {
/* Schedule IOC removing */
- nioc = calloc (1, sizeof (struct rdns_io_channel));
+ nioc = rdns_ioc_new (serv, resolver, false);
+
if (nioc == NULL) {
rdns_err ("calloc fails to allocate rdns_io_channel");
continue;
}
- nioc->sock = rdns_make_client_socket (serv->name, serv->port,
- SOCK_DGRAM, &nioc->saddr, &nioc->slen);
- if (nioc->sock == -1) {
- rdns_err ("cannot open socket to %s: %s", serv->name,
- strerror (errno));
- free (nioc);
- continue;
- }
- nioc->srv = serv;
- nioc->flags = RDNS_CHANNEL_ACTIVE;
- nioc->resolver = resolver;
- nioc->async_io = resolver->async->add_read (resolver->async->data,
- nioc->sock, nioc);
- REF_INIT_RETAIN (nioc, rdns_ioc_free);
+
serv->io_channels[i] = nioc;
rdns_debug ("scheduled io channel for server %s to be refreshed after "
"%lu usages", serv->name, (unsigned long)ioc->uses);
@@ -883,30 +884,14 @@ rdns_resolver_init (struct rdns_resolver *resolver)
UPSTREAM_FOREACH (resolver->servers, serv) {
serv->io_channels = calloc (serv->io_cnt, sizeof (struct rdns_io_channel *));
for (i = 0; i < serv->io_cnt; i ++) {
- ioc = calloc (1, sizeof (struct rdns_io_channel));
+ ioc = rdns_ioc_new(serv, resolver, false);
+
if (ioc == NULL) {
rdns_err ("cannot allocate memory for the resolver IO channels");
return false;
}
- ioc->sock = rdns_make_client_socket (serv->name, serv->port, SOCK_DGRAM,
- &ioc->saddr, &ioc->slen);
-
- if (ioc->sock == -1) {
- rdns_err ("cannot open socket to %s:%d %s",
- serv->name, serv->port, strerror (errno));
- free (ioc);
-
- return false;
- }
- else {
- ioc->srv = serv;
- ioc->resolver = resolver;
- ioc->async_io = resolver->async->add_read (resolver->async->data,
- ioc->sock, ioc);
- REF_INIT_RETAIN (ioc, rdns_ioc_free);
- serv->io_channels[i] = ioc;
- }
+ serv->io_channels[i] = ioc;
}
}
diff --git a/contrib/librdns/util.c b/contrib/librdns/util.c
index be31c8f14..d69ef6cd0 100644
--- a/contrib/librdns/util.c
+++ b/contrib/librdns/util.c
@@ -458,14 +458,18 @@ rdns_request_free (struct rdns_request *req)
req->async->del_timer (req->async->data,
req->async_event);
/* Remove from id hashes */
- HASH_DEL (req->io->requests, req);
+ if (req->io) {
+ kh_del(rdns_requests_hash, req->io->requests, req->id);
+ }
req->async_event = NULL;
}
else if (req->state == RDNS_REQUEST_WAIT_SEND) {
/* Remove retransmit event */
req->async->del_write (req->async->data,
req->async_event);
- HASH_DEL (req->io->requests, req);
+ if (req->io) {
+ kh_del(rdns_requests_hash, req->io->requests, req->id);
+ }
req->async_event = NULL;
}
else if (req->state == RDNS_REQUEST_FAKE) {
@@ -492,19 +496,51 @@ rdns_request_free (struct rdns_request *req)
void
rdns_ioc_free (struct rdns_io_channel *ioc)
{
- struct rdns_request *req, *rtmp;
+ struct rdns_request *req;
- HASH_ITER (hh, ioc->requests, req, rtmp) {
+ kh_foreach_value(ioc->requests, req, {
REF_RELEASE (req);
- }
+ });
ioc->resolver->async->del_read (ioc->resolver->async->data,
ioc->async_io);
+ kh_destroy(rdns_requests_hash, ioc->requests);
close (ioc->sock);
free (ioc->saddr);
free (ioc);
}
+struct rdns_io_channel *
+rdns_ioc_new (struct rdns_server *serv,
+ struct rdns_resolver *resolver,
+ bool is_tcp)
+{
+ struct rdns_io_channel *nioc = calloc (1, sizeof (struct rdns_io_channel));
+ if (nioc == NULL) {
+ rdns_err ("calloc fails to allocate rdns_io_channel");
+ return NULL;
+ }
+
+ nioc->sock = rdns_make_client_socket (serv->name, serv->port,
+ is_tcp ? SOCK_STREAM : SOCK_DGRAM, &nioc->saddr, &nioc->slen);
+ if (nioc->sock == -1) {
+ rdns_err ("cannot open socket to %s: %s", serv->name,
+ strerror (errno));
+ free (nioc);
+ return NULL;
+ }
+
+ nioc->srv = serv;
+ nioc->flags = RDNS_CHANNEL_ACTIVE;
+ nioc->resolver = resolver;
+ nioc->async_io = resolver->async->add_read (resolver->async->data,
+ nioc->sock, nioc);
+ nioc->requests = kh_init(rdns_requests_hash);
+ REF_INIT_RETAIN (nioc, rdns_ioc_free);
+
+ return nioc;
+}
+
void
rdns_resolver_release (struct rdns_resolver *resolver)
{
@@ -526,14 +562,18 @@ rdns_request_unschedule (struct rdns_request *req)
req->async->del_timer (req->async->data,
req->async_event);
/* Remove from id hashes */
- HASH_DEL (req->io->requests, req);
+ if (req->io) {
+ kh_del(rdns_requests_hash, req->io->requests, req->id);
+ }
req->async_event = NULL;
}
else if (req->state == RDNS_REQUEST_WAIT_SEND) {
req->async->del_write (req->async->data,
req->async_event);
/* Remove from id hashes */
- HASH_DEL (req->io->requests, req);
+ if (req->io) {
+ kh_del(rdns_requests_hash, req->io->requests, req->id);
+ }
req->async_event = NULL;
}
}
diff --git a/contrib/librdns/util.h b/contrib/librdns/util.h
index 8d11d0cfc..5fc94eb80 100644
--- a/contrib/librdns/util.h
+++ b/contrib/librdns/util.h
@@ -50,6 +50,13 @@ uint16_t rdns_permutor_generate_id (void);
*/
void rdns_ioc_free (struct rdns_io_channel *ioc);
+/**
+ * C
+ */
+struct rdns_io_channel * rdns_ioc_new (struct rdns_server *srv,
+ struct rdns_resolver *resolver,
+ bool is_tcp);
+
/**
* Free request
* @param req
More information about the Commits
mailing list