mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-09-22 06:11:32 +02:00
BUG/MEDIUM: stream-int: don't immediately enable reading when the buffer was reportedly full
There is a long-time issue which affects some applets, at least the stats applet. If a large stats page is read over a slow link, regularly the channel's buffer contains too many response data to allow another round of ci_putblk() to copy a new message. In this case the applet calls si_applet_cant_put() to mention that it failed to emit data into the channel's buffer, and wants to be called only once some room is made. The problem is that stream_int_update(), which is called from process_stream(), will clear this flag whenever it sees there's some spare room in the channel's buffer. It causes the applet to be woken again immediately. This is very visible when reading a large stats page over a slow link, because in this case haproxy will run at 100% CPU and strace shows mostly epoll_wait(0). It is very likely that some other applets like CLI, Lua, peers or SPOE have also been affected but that the effect were less noticeable because it was mixed with traffic. Ideally stream_int_update() should not touch these flags, but changing this would require a very careful auditing of all users. Instead here what we do is that we respect the flag if the channel still has output data. This way the flag will automatically disappear once the buffer is empty, and the applet function will be called only when input data remains, if at all. This patch alone is not enough to observe the behaviour change on the stats page because another bug takes over, addressed by next patch (BUG/MEDIUM: stats: don't ask for more data as long as we're responding). When both are applied, dumping stats for 5k backends over a 10 Mbps link take 1% CPU instead of 100%, with 1.5k epoll_wait() calls instead of 80k. This fix should be backported at least as far as 1.5.
This commit is contained in:
parent
616ac81dec
commit
171d5f203a
@ -780,7 +780,7 @@ void stream_int_update(struct stream_interface *si)
|
||||
ic->rex = TICK_ETERNITY;
|
||||
}
|
||||
}
|
||||
else {
|
||||
else if (!(si->flags & SI_FL_WAIT_ROOM) || !co_data(ic)) {
|
||||
/* (re)start reading and update timeout. Note: we don't recompute the timeout
|
||||
* everytime we get here, otherwise it would risk never to expire. We only
|
||||
* update it if is was not yet set. The stream socket handler will already
|
||||
|
Loading…
x
Reference in New Issue
Block a user