From 78680c6fce480d7b9be38a1b5a1fca4df7092591 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marek=20Vavru=C5=A1a?= <marek.vavrusa@nic.cz>
Date: Thu, 5 Feb 2015 15:13:49 +0100
Subject: [PATCH] tcp: throttling affect accept() only, lets the processing
 continue

---
 src/knot/server/tcp-handler.c | 32 +++++++++++++++++++-------------
 1 file changed, 19 insertions(+), 13 deletions(-)

diff --git a/src/knot/server/tcp-handler.c b/src/knot/server/tcp-handler.c
index f8a83a2d4..70099c773 100644
--- a/src/knot/server/tcp-handler.c
+++ b/src/knot/server/tcp-handler.c
@@ -48,6 +48,7 @@ typedef struct tcp_context {
 	struct iovec iov[2];        /*!< TX/RX buffers. */
 	unsigned client_threshold;  /*!< Index of first TCP client. */
 	timev_t last_poll_time;     /*!< Time of the last socket poll. */
+	timev_t throttle_end;       /*!< End of accept() throttling. */
 	fdset_t set;                /*!< Set of server/client sockets. */
 	unsigned thread_id;         /*!< Thread identifier. */
 } tcp_context_t;
@@ -108,7 +109,9 @@ static int tcp_handle(tcp_context_t *tcp, int fd,
 	}
 
 	/* Timeout. */
+	rcu_read_lock();
 	struct timeval tmout = { conf()->max_conn_reply, 0 };
+	rcu_read_unlock();
 
 	/* Receive data. */
 	int ret = tcp_recv_msg(fd, rx->iov_base, rx->iov_len, &tmout);
@@ -164,17 +167,9 @@ int tcp_accept(int fd)
 	if (incoming < 0) {
 		int en = errno;
 		if (en != EINTR && en != EAGAIN) {
-			log_error("cannot accept connection (%d)", errno);
-			if (en == EMFILE || en == ENFILE ||
-			    en == ENOBUFS || en == ENOMEM) {
-				int throttle = tcp_throttle();
-				log_error("throttling TCP connection pool for "
-				          "%d seconds, too many allocated "
-				          "resources", throttle);
-				sleep(throttle);
-			}
-
+			return KNOT_EBUSY;
 		}
+		return KNOT_ERROR;
 	} else {
 		dbg_net("tcp: accepted connection fd=%d\n", incoming);
 		/* Set recv() timeout. */
@@ -230,7 +225,7 @@ int tcp_recv_data(int fd, uint8_t *buf, int len, struct timeval *timeout)
 		if (errno == EAGAIN || errno == EINTR) {
 			/* Continue only if timeout didn't expire. */
 			ret = tcp_wait_for_data(fd, timeout);
-			if (ret) {
+			if (ret > 0) {
 				continue;
 			} else {
 				return KNOT_ETIMEOUT;
@@ -299,7 +294,7 @@ static int tcp_event_accept(tcp_context_t *tcp, unsigned i)
 	/* Accept client. */
 	int fd = tcp->set.pfd[i].fd;
 	int client = tcp_accept(fd);
-	if (client >= 0) {
+	if (client > 0) {
 		/* Assign to fdset. */
 		int next_id = fdset_add(&tcp->set, client, POLLIN, NULL);
 		if (next_id < 0) {
@@ -311,9 +306,11 @@ static int tcp_event_accept(tcp_context_t *tcp, unsigned i)
 		rcu_read_lock();
 		fdset_set_watchdog(&tcp->set, next_id, conf()->max_conn_hs);
 		rcu_read_unlock();
+
+		return KNOT_EOK;
 	}
 
-	return KNOT_EOK;
+	return client;
 }
 
 static int tcp_event_serve(tcp_context_t *tcp, unsigned i)
@@ -342,6 +339,15 @@ static int tcp_wait_for_events(tcp_context_t *tcp)
 
 	/* Mark the time of last poll call. */
 	time_now(&tcp->last_poll_time);
+	bool is_throttled = (tcp->last_poll_time.tv_sec < tcp->throttle_end.tv_sec);
+	rcu_read_lock();
+	if (!is_throttled) {
+		/* Configuration limit, infer maximal pool size. */
+		unsigned max_per_set = MAX(conf()->max_tcp_clients / conf_tcp_threads(conf()), 1);
+		/* Subtract master sockets check limits. */
+		is_throttled = (set->n - tcp->client_threshold) >= max_per_set;
+	}
+	rcu_read_unlock();
 
 	/* Process events. */
 	unsigned i = 0;
-- 
GitLab