diff --git a/src/controller/ha.c b/src/controller/ha.c index 894e1eb1..d2d878cc 100644 --- a/src/controller/ha.c +++ b/src/controller/ha.c @@ -186,10 +186,13 @@ static void *probe_thread(void *arg) int sr; do { sr = SSL_connect(ssl); - } while (sr <= 0 && - (SSL_get_error(ssl, sr) == SSL_ERROR_WANT_READ || - SSL_get_error(ssl, sr) == SSL_ERROR_WANT_WRITE) && - !atomic_load(ctx->election_done)); + if (sr <= 0) { + int ssl_err = SSL_get_error(ssl, sr); + if (ssl_err != SSL_ERROR_WANT_READ && + ssl_err != SSL_ERROR_WANT_WRITE) + break; + } + } while (sr <= 0 && !atomic_load(ctx->election_done)); SSL_shutdown(ssl); SSL_free(ssl); if (sr <= 0 || atomic_load(ctx->election_done)) @@ -326,13 +329,21 @@ void ha_check_priority_stepdown(ha_state_t *ha, int sender_priority, if (my_term > 0 || sender_term > 0) return; /* term-based election took over — don't interfere */ - ctrl_role_t role = (ctrl_role_t)atomic_load_explicit(&ha->role, - memory_order_acquire); - if (role == CTRL_PRIMARY) { - WARN("HA: stepping down — higher-priority peer (priority=%d) present at term=0", - sender_priority); - ha_do_demote(ha); + /* Hold lock to make the role-check + demote atomic, preventing a + * concurrent promotion from racing between the two operations. */ + pthread_mutex_lock(&ha->lock); + /* Re-check term under lock in case a concurrent promotion raced us */ + my_term = atomic_load_explicit(&ha->term, memory_order_acquire); + if (my_term == 0 && sender_term == 0) { + ctrl_role_t role = (ctrl_role_t)atomic_load_explicit(&ha->role, + memory_order_acquire); + if (role == CTRL_PRIMARY) { + WARN("HA: stepping down — higher-priority peer (priority=%d) at term=0", + sender_priority); + ha_do_demote(ha); + } } + pthread_mutex_unlock(&ha->lock); } /*