From e03d05c6ce7a1c6179eb4fce79c11f9b14cda016 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Wed, 23 Aug 2023 11:58:24 +0200 Subject: [PATCH] MINOR: check: remember when we migrate a check The goal here is to explicitly mark that a check was migrated so that we don't do it again. This will allow us to perform other actions on the target thread while still knowing that we don't want to be migrated again. The new READY bit combine with SLEEPING to form 4 possible states: SLP RDY State Description 0 0 - (reserved) 0 1 RUNNING Check is bound to current thread and running 1 0 SLEEPING Check is sleeping, not bound to a thread 1 1 MIGRATING Check is migrating to another thread Thus we set READY upon migration, and check for it before migrating, this is sufficient to prevent a second migration. To make things a bit clearer, the SLEEPING bit was switched with FASTINTER so that SLEEPING and READY are adjacent. --- include/haproxy/check-t.h | 13 +++++++++++-- src/check.c | 15 +++++++++++---- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/include/haproxy/check-t.h b/include/haproxy/check-t.h index 26290b44b..b4ee5489c 100644 --- a/include/haproxy/check-t.h +++ b/include/haproxy/check-t.h @@ -56,8 +56,17 @@ enum chk_result { #define CHK_ST_OUT_ALLOC 0x0080 /* check blocked waiting for output buffer allocation */ #define CHK_ST_CLOSE_CONN 0x0100 /* check is waiting that the connection gets closed */ #define CHK_ST_PURGE 0x0200 /* check must be freed */ -#define CHK_ST_SLEEPING 0x0400 /* check was sleeping, i.e. not currently bound to a thread */ -#define CHK_ST_FASTINTER 0x0800 /* force fastinter check */ +#define CHK_ST_FASTINTER 0x0400 /* force fastinter check */ +#define CHK_ST_READY 0x0800 /* check ready to migrate or run, see below */ +#define CHK_ST_SLEEPING 0x1000 /* check was sleeping, i.e. not currently bound to a thread, see below */ + +/* 4 possible states for CHK_ST_SLEEPING and CHK_ST_READY: + * SLP RDY State Description + * 0 0 - (reserved) + * 0 1 RUNNING Check is bound to current thread and running + * 1 0 SLEEPING Check is sleeping, not bound to a thread + * 1 1 MIGRATING Check is migrating to another thread + */ /* check status */ enum healthcheck_status { diff --git a/src/check.c b/src/check.c index 32c03da4c..c69ab49bf 100644 --- a/src/check.c +++ b/src/check.c @@ -1132,13 +1132,12 @@ struct task *process_chk_conn(struct task *t, void *context, unsigned int state) * than half of the current thread's load, and if so we'll * bounce the task there. It's possible because it's not yet * tied to the current thread. The other thread will not bounce - * the task again because we're removing CHK_ST_SLEEPING. + * the task again because we're setting CHK_ST_READY indicating + * a migration. */ uint my_load = HA_ATOMIC_LOAD(&th_ctx->rq_total); - check->state &= ~CHK_ST_SLEEPING; - - if (my_load >= 2) { + if (!(check->state & CHK_ST_READY) && my_load >= 2) { uint new_tid = statistical_prng_range(global.nbthread); uint new_load = HA_ATOMIC_LOAD(&ha_thread_ctx[new_tid].rq_total); @@ -1149,6 +1148,7 @@ struct task *process_chk_conn(struct task *t, void *context, unsigned int state) * BUG_ON() as we're not allowed to call task_queue() for a * foreign thread. The recipient will restore the expiration. */ + check->state |= CHK_ST_READY; task_unlink_wq(t); t->expire = TICK_ETERNITY; task_set_thread(t, new_tid); @@ -1160,8 +1160,14 @@ struct task *process_chk_conn(struct task *t, void *context, unsigned int state) /* OK we're keeping it so this check is ours now */ task_set_thread(t, tid); + check->state &= ~CHK_ST_SLEEPING; + + /* OK let's run, now we cannot roll back anymore */ + check->state |= CHK_ST_READY; } + /* at this point, CHK_ST_SLEEPING = 0 and CHK_ST_READY = 1*/ + if (check->server) HA_SPIN_LOCK(SERVER_LOCK, &check->server->lock); @@ -1313,6 +1319,7 @@ struct task *process_chk_conn(struct task *t, void *context, unsigned int state) check_release_buf(check, &check->bi); check_release_buf(check, &check->bo); check->state &= ~(CHK_ST_INPROGRESS|CHK_ST_IN_ALLOC|CHK_ST_OUT_ALLOC); + check->state &= ~CHK_ST_READY; check->state |= CHK_ST_SLEEPING; update_timer: