mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2025-01-13 17:20:52 +00:00
MEDIUM: buffer: add a new buf_wanted dummy buffer to report failed allocations
Doing so ensures that even when no memory is available, we leave the channel in a sane condition. There's a special case in proto_http.c regarding the compression, we simply pre-allocate the tmpbuf to point to the dummy buffer. Not reusing &buf_empty for this allows the rest of the code to differenciate an empty buffer that's not used from an empty buffer that results from a failed allocation which has the same semantics as a buffer full.
This commit is contained in:
parent
2a4b54359b
commit
f2f7d6b27b
@ -41,6 +41,7 @@ struct buffer {
|
||||
|
||||
extern struct pool_head *pool2_buffer;
|
||||
extern struct buffer buf_empty;
|
||||
extern struct buffer buf_wanted;
|
||||
|
||||
int init_buffer();
|
||||
int buffer_replace2(struct buffer *b, char *pos, char *end, const char *str, int len);
|
||||
@ -396,18 +397,23 @@ static inline void b_reset(struct buffer *buf)
|
||||
buf->p = buf->data;
|
||||
}
|
||||
|
||||
/* Allocates a buffer and replaces *buf with this buffer. No control is made
|
||||
* to check if *buf already pointed to another buffer. The allocated buffer
|
||||
* is returned, or NULL in case no memory is available.
|
||||
/* Allocates a buffer and replaces *buf with this buffer. If no memory is
|
||||
* available, &buf_wanted is used instead. No control is made to check if *buf
|
||||
* already pointed to another buffer. The allocated buffer is returned, or
|
||||
* NULL in case no memory is available.
|
||||
*/
|
||||
static inline struct buffer *b_alloc(struct buffer **buf)
|
||||
{
|
||||
*buf = pool_alloc_dirty(pool2_buffer);
|
||||
if (likely(*buf)) {
|
||||
(*buf)->size = pool2_buffer->size - sizeof(struct buffer);
|
||||
b_reset(*buf);
|
||||
struct buffer *b;
|
||||
|
||||
*buf = &buf_wanted;
|
||||
b = pool_alloc_dirty(pool2_buffer);
|
||||
if (likely(b)) {
|
||||
b->size = pool2_buffer->size - sizeof(struct buffer);
|
||||
b_reset(b);
|
||||
*buf = b;
|
||||
}
|
||||
return *buf;
|
||||
return b;
|
||||
}
|
||||
|
||||
/* Releases buffer *buf (no check of emptiness) */
|
||||
|
@ -22,10 +22,14 @@
|
||||
|
||||
struct pool_head *pool2_buffer;
|
||||
|
||||
/* this buffer is used to have a valid pointer to an empty buffer in channels
|
||||
* which convey no more data.
|
||||
/* These buffers are used to always have a valid pointer to an empty buffer in
|
||||
* channels. The first buffer is set once a buffer is empty. The second one is
|
||||
* set when a buffer is desired but no more are available. It helps knowing
|
||||
* what channel wants a buffer. They can reliably be exchanged, the split
|
||||
* between the two is only an optimization.
|
||||
*/
|
||||
struct buffer buf_empty = { .p = buf_empty.data };
|
||||
struct buffer buf_wanted = { .p = buf_wanted.data };
|
||||
|
||||
/* perform minimal intializations, report 0 in case of error, 1 if OK. */
|
||||
int init_buffer()
|
||||
|
@ -6516,7 +6516,7 @@ int http_response_forward_body(struct session *s, struct channel *res, int an_bi
|
||||
{
|
||||
struct http_txn *txn = &s->txn;
|
||||
struct http_msg *msg = &s->txn.rsp;
|
||||
static struct buffer *tmpbuf = NULL;
|
||||
static struct buffer *tmpbuf = &buf_empty;
|
||||
int compressing = 0;
|
||||
int ret;
|
||||
|
||||
@ -6570,7 +6570,7 @@ int http_response_forward_body(struct session *s, struct channel *res, int an_bi
|
||||
* output of compressed data, and in CRLF state to let the
|
||||
* TRAILERS state finish the job of removing the trailing CRLF.
|
||||
*/
|
||||
if (unlikely(tmpbuf == NULL)) {
|
||||
if (unlikely(!tmpbuf->size)) {
|
||||
/* this is the first time we need the compression buffer */
|
||||
if (b_alloc(&tmpbuf) == NULL)
|
||||
goto aborted_xfer; /* no memory */
|
||||
|
Loading…
Reference in New Issue
Block a user