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.
This commit is contained in:
Willy Tarreau 2023-08-23 11:58:24 +02:00
parent 3544c9f8a0
commit e03d05c6ce
2 changed files with 22 additions and 6 deletions

View 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 {

View 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: