MEDIUM: stream-int: clean up the conditions to enable reading in si_conn_wake_cb

The condition to release the SI_FL_WAIT_ROOM flag was abnormally
complicated because it was inherited from 6 years ago before we used
to check for the buffer's emptiness. The CF_READ_PARTIAL flag had to be
removed, and the complex test was replaced with a simpler one checking
if *some* data were moved out or not.

The reason behind this change is to have a condition compatible with
both connections and applets, as applets currently don't work very
well in this area. Specifically, some optimizations on the applet
side cause them not to release the flag above until the buffer is
empty, which may prevent applets from taking together (eg: peers
over large haproxy buffers and small kernel buffers).
This commit is contained in:
Willy Tarreau 2015-09-23 19:37:00 +02:00
parent 388a2385a5
commit ea3cc48d64

View File

@ -573,25 +573,36 @@ static int si_conn_wake_cb(struct connection *conn)
si_chk_rcv(si_opposite(si));
}
/* process producer side.
* We might have some data the consumer is waiting for.
* We can do fast-forwarding, but we avoid doing this for partial
* buffers, because it is very likely that it will be done again
* immediately afterwards once the following data is parsed (eg:
* HTTP chunking).
/* Notify the other side when we've injected data into the IC that
* needs to be forwarded. We can do fast-forwarding as soon as there
* are output data, but we avoid doing this if some of the data are
* not yet scheduled for being forwarded, because it is very likely
* that it will be done again immediately afterwards once the following
* data are parsed (eg: HTTP chunking). We only SI_FL_WAIT_ROOM once
* we've emptied *some* of the output buffer, and not just when there
* is available room, because applets are often forced to stop before
* the buffer is full. We must not stop based on input data alone because
* an HTTP parser might need more data to complete the parsing.
*/
if (((ic->flags & CF_READ_PARTIAL) && !channel_is_empty(ic)) &&
(ic->pipe /* always try to send spliced data */ ||
(si_ib(si)->i == 0 && (si_opposite(si)->flags & SI_FL_WAIT_DATA)))) {
int last_len = ic->pipe ? ic->pipe->data : 0;
if (!channel_is_empty(ic) &&
(si_opposite(si)->flags & SI_FL_WAIT_DATA) &&
(ic->buf->i == 0 || ic->pipe)) {
int new_len, last_len;
last_len = ic->buf->o;
if (ic->pipe)
last_len += ic->pipe->data;
si_chk_snd(si_opposite(si));
new_len = ic->buf->o;
if (ic->pipe)
new_len += ic->pipe->data;
/* check if the consumer has freed some space either in the
* buffer or in the pipe.
*/
if (channel_may_recv(ic) &&
(!last_len || !ic->pipe || ic->pipe->data < last_len))
if (channel_may_recv(ic) && new_len < last_len)
si->flags &= ~SI_FL_WAIT_ROOM;
}