]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: check: remember when we migrate a check
authorWilly Tarreau <w@1wt.eu>
Wed, 23 Aug 2023 09:58:24 +0000 (11:58 +0200)
committerWilly Tarreau <w@1wt.eu>
Fri, 1 Sep 2023 06:26:06 +0000 (08:26 +0200)
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
src/check.c

index 26290b44bc9c536c6adfb6e67fe0693dc3db97c4..b4ee5489c3ca601465a2024f26bbe2ecd3cce8e6 100644 (file)
@@ -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 {
index 32c03da4c9c195af2d5e42f48d91a05f887cba31..c69ab49bf04f8b252e4bfd6a14ccb8bf603b6f0f 100644 (file)
@@ -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: