mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-09-21 22:01:31 +02:00
[MEDIUM] http: don't use trash to realign large buffers
The trash buffer may now be smaller than a buffer because we can tune it at run time. This causes a risk when we're trying to use it as a temporary buffer to realign unaligned requests, because we may have to put up to a full buffer into it. Instead of doing a double copy, we're now relying on an open-coded bouncing copy algorithm. The principle is that we move one byte at a time to its final place, and if that place also holds a byte, then we move it too, and so on. We finish when we've moved all the buffer. It limits the number of memory accesses, but since it proceeds one byte at a time and with random walk, it's not cache friendly and should be slower than a double copy. However, it's only used in extreme situations and the difference will not be noticeable. It has been extensively tested and works reliably.
This commit is contained in:
parent
329f74d463
commit
b97f199d4b
@ -2,7 +2,7 @@
|
|||||||
* include/proto/buffers.h
|
* include/proto/buffers.h
|
||||||
* Buffer management definitions, macros and inline functions.
|
* Buffer management definitions, macros and inline functions.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2000-2009 Willy Tarreau - w@1wt.eu
|
* Copyright (C) 2000-2010 Willy Tarreau - w@1wt.eu
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
@ -429,6 +429,8 @@ int buffer_replace(struct buffer *b, char *pos, char *end, const char *str);
|
|||||||
int buffer_replace2(struct buffer *b, char *pos, char *end, const char *str, int len);
|
int buffer_replace2(struct buffer *b, char *pos, char *end, const char *str, int len);
|
||||||
int buffer_insert_line2(struct buffer *b, char *pos, const char *str, int len);
|
int buffer_insert_line2(struct buffer *b, char *pos, const char *str, int len);
|
||||||
void buffer_dump(FILE *o, struct buffer *b, int from, int to);
|
void buffer_dump(FILE *o, struct buffer *b, int from, int to);
|
||||||
|
void buffer_bounce_realign(struct buffer *buf);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* writes the chunk <chunk> to buffer <buf>. Returns -1 in case of success,
|
/* writes the chunk <chunk> to buffer <buf>. Returns -1 in case of success,
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Buffer management functions.
|
* Buffer management functions.
|
||||||
*
|
*
|
||||||
* Copyright 2000-2009 Willy Tarreau <w@1wt.eu>
|
* Copyright 2000-2010 Willy Tarreau <w@1wt.eu>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
@ -298,6 +298,68 @@ int buffer_insert_line2(struct buffer *b, char *pos, const char *str, int len)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Realigns a possibly non-contiguous buffer by bouncing bytes from source to
|
||||||
|
* destination. It does not use any intermediate buffer and does the move in
|
||||||
|
* place, though it will be slower than a simple memmove() on contiguous data,
|
||||||
|
* so it's desirable to use it only on non-contiguous buffers. No pointers are
|
||||||
|
* changed, the caller is responsible for that.
|
||||||
|
*/
|
||||||
|
void buffer_bounce_realign(struct buffer *buf)
|
||||||
|
{
|
||||||
|
int advance, to_move;
|
||||||
|
char *from, *to;
|
||||||
|
|
||||||
|
advance = buf->data + buf->size - buf->w;
|
||||||
|
if (!advance)
|
||||||
|
return;
|
||||||
|
|
||||||
|
from = buf->w;
|
||||||
|
to_move = buf->l;
|
||||||
|
while (to_move) {
|
||||||
|
char last, save;
|
||||||
|
|
||||||
|
last = *from;
|
||||||
|
to = from + advance;
|
||||||
|
if (to >= buf->data + buf->size)
|
||||||
|
to -= buf->size;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
save = *to;
|
||||||
|
*to = last;
|
||||||
|
last = save;
|
||||||
|
to_move--;
|
||||||
|
if (!to_move)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* check if we went back home after rotating a number of bytes */
|
||||||
|
if (to == from)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* if we ended up in the empty area, let's walk to next place. The
|
||||||
|
* empty area is either between buf->r and from or before from or
|
||||||
|
* after buf->r.
|
||||||
|
*/
|
||||||
|
if (from > buf->r) {
|
||||||
|
if (to >= buf->r && to < from)
|
||||||
|
break;
|
||||||
|
} else if (from < buf->r) {
|
||||||
|
if (to < from || to >= buf->r)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* we have overwritten a byte of the original set, let's move it */
|
||||||
|
to += advance;
|
||||||
|
if (to >= buf->data + buf->size)
|
||||||
|
to -= buf->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
from++;
|
||||||
|
if (from >= buf->data + buf->size)
|
||||||
|
from -= buf->size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Does an snprintf() at the end of chunk <chk>, respecting the limit of
|
* Does an snprintf() at the end of chunk <chk>, respecting the limit of
|
||||||
* at most chk->size chars. If the chk->len is over, nothing is added. Returns
|
* at most chk->size chars. If the chk->len is over, nothing is added. Returns
|
||||||
|
@ -2262,18 +2262,11 @@ void http_buffer_heavy_realign(struct buffer *buf, struct http_msg *msg)
|
|||||||
* - the buffer is in two blocks, we move it via the trash
|
* - the buffer is in two blocks, we move it via the trash
|
||||||
*/
|
*/
|
||||||
if (buf->l) {
|
if (buf->l) {
|
||||||
int block1 = buf->l;
|
if (buf->r <= buf->w)
|
||||||
int block2 = 0;
|
|
||||||
if (buf->r <= buf->w) {
|
|
||||||
/* non-contiguous block */
|
/* non-contiguous block */
|
||||||
block1 = buf->data + buf->size - buf->w;
|
buffer_bounce_realign(buf);
|
||||||
block2 = buf->r - buf->data;
|
else
|
||||||
}
|
memmove(buf->data, buf->w, buf->l);
|
||||||
if (block2)
|
|
||||||
memcpy(trash, buf->data, block2);
|
|
||||||
memmove(buf->data, buf->w, block1);
|
|
||||||
if (block2)
|
|
||||||
memcpy(buf->data + block1, trash, block2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* adjust all known pointers */
|
/* adjust all known pointers */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user