From: Olivier Houchard Date: Fri, 2 May 2025 11:29:05 +0000 (+0000) Subject: MEDIUM: peers: Give up if we fail to take locks in hot path X-Git-Tag: v3.2-dev14~10 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b3ad7b6371e10cee4e0c23f80191e62d1da7415f;p=thirdparty%2Fhaproxy.git MEDIUM: peers: Give up if we fail to take locks in hot path In peer_send_msgs(), give up in order to retry later if we failed at getting the update read lock. Similarly, in __process_running_peer_sync(), give up and just reschedule the task if we failed to get the peer lock. There is an heavy contention on both those locks, so we could spend a lot of time trying to get them. This helps getting peers perform better under heavy load. --- diff --git a/src/peers.c b/src/peers.c index abc00026e..f13d9d393 100644 --- a/src/peers.c +++ b/src/peers.c @@ -2639,7 +2639,10 @@ static inline int peer_send_msgs(struct appctx *appctx, if (!(peer->flags & PEER_F_TEACH_PROCESS)) { int must_send; - HA_RWLOCK_RDLOCK(STK_TABLE_UPDT_LOCK, &st->table->updt_lock); + if (HA_RWLOCK_TRYRDLOCK(STK_TABLE_UPDT_LOCK, &st->table->updt_lock)) { + applet_have_more_data(appctx); + return -1; + } must_send = (peer->learnstate == PEER_LR_ST_NOTASSIGNED) && (st->last_pushed != st->table->localupdate); HA_RWLOCK_RDUNLOCK(STK_TABLE_UPDT_LOCK, &st->table->updt_lock); @@ -3413,6 +3416,7 @@ static void __process_running_peer_sync(struct task *task, struct peers *peers, { struct peer *peer; struct shared_table *st; + int must_resched = 0; /* resync timeout set to TICK_ETERNITY means we just start * a new process and timer was not initialized. @@ -3440,7 +3444,10 @@ static void __process_running_peer_sync(struct task *task, struct peers *peers, /* For each session */ for (peer = peers->remote; peer; peer = peer->next) { - HA_SPIN_LOCK(PEER_LOCK, &peer->lock); + if (HA_SPIN_TRYLOCK(PEER_LOCK, &peer->lock) != 0) { + must_resched = 1; + continue; + } sync_peer_learn_state(peers, peer); sync_peer_app_state(peers, peer); @@ -3567,12 +3574,13 @@ static void __process_running_peer_sync(struct task *task, struct peers *peers, HA_ATOMIC_OR(&peers->flags, PEERS_F_RESYNC_REMOTE_FINISHED|PEERS_F_DBG_RESYNC_REMOTETIMEOUT); } - if ((peers->flags & PEERS_RESYNC_STATEMASK) != PEERS_RESYNC_FINISHED) { + if (!must_resched && (peers->flags & PEERS_RESYNC_STATEMASK) != PEERS_RESYNC_FINISHED) { /* Resync not finished*/ /* reschedule task to resync timeout if not expired, to ended resync if needed */ if (!tick_is_expired(peers->resync_timeout, now_ms)) task->expire = tick_first(task->expire, peers->resync_timeout); - } + } else if (must_resched) + task_wakeup(task, TASK_WOKEN_OTHER); } /* Process the sync task for a stopping process. It is called from process_peer_sync() only */