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.
This commit is contained in:
Olivier Houchard 2025-05-02 11:29:05 +00:00 committed by Willy Tarreau
parent 7a8d1a3122
commit b3ad7b6371

View File

@ -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 */