Hi Stéphane,

On Tue, May 29, 2018 at 12:38:40PM +0200, Stéphane Cottin wrote:
> Hi,
> 
> This simple test config file :
> 
>     resolvers mydns
>         nameserver ns1 10.0.0.1:53
>     listen mysql
>       bind unix@/tmp/mysql.sock user www-data mode 600
>       option mysql-check user haproxy post-41
>       server MYSQL mysql.my.domain:3306 maxconn 100 check resolvers mydns
> 
> makes haproxy 1.8.9 eat a full cpu core, unless you remove the server
> resolvers option.
> 
> The same config with haproxy 1.8.8 only consume a few cpu cycles.
> 

Oops you're right indeed. There's a bug in the pollers revamp that has been
done recently.
The attached patch should fix it.

Thanks for reporting !

Olivier
>From 837f376310b3077740289bc2ced1a0a97a1f964f Mon Sep 17 00:00:00 2001
From: Olivier Houchard <ohouch...@haproxy.com>
Date: Tue, 29 May 2018 14:42:22 +0200
Subject: [PATCH] BUG/MEDIUM: fd: Only check update_mask against
 all_threads_mask.

To decide if we have to insert a fd into the update_list, we check its
update_mask. We set the update_mask to fdtab[fd].thread_mask when adding it
or updating, and when each thread will remove its bit once it has been taken
care of.
However, even if all threads did their job, update_mask may be non-zero,
because for fds that want all threads, the mask will be 0xffffffffffffffff,
so except when we run with 64 threads, there will be bits left over.

So, to decide if nobody had any update for that fd, we have to check
(update_mask & all_threads_mask) == 0, instead of update_mask == 0. Not
doing so means fd events can be missed, or fd not removed from the poller,
making poller waking with no need, and using 100% of the CPU.

This should only be applied on 1.8.
---
 include/proto/fd.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/include/proto/fd.h b/include/proto/fd.h
index b6199ccf..8d5e162f 100644
--- a/include/proto/fd.h
+++ b/include/proto/fd.h
@@ -126,7 +126,7 @@ static inline void updt_fd_polling(const int fd)
                /* If update_mask is non-nul, then it's already in the list
                 * so we don't have to add it.
                 */
-               if (fdtab[fd].update_mask == 0) {
+               if ((fdtab[fd].update_mask & all_threads_mask) == 0) {
                        if (update_list.first == -1) {
                                update_list.first = update_list.last = fd;
                                fdtab[fd].update.next = fdtab[fd].update.prev = 
-1;
-- 
2.14.3

Reply via email to