[MEDIUM] make it possible to change the buffer size in the configuration

The new tune.bufsize and tune.maxrewrite global directives allow one to
change the buffer size and the maxrewrite size. Right now, setting bufsize
too low will block stats sockets which will not be able to write at all.
An error checking must be added to buffer_write_chunk() so that if it
cannot write its message to an empty buffer, it causes the caller to abort.
This commit is contained in:
Willy Tarreau 2009-08-17 07:23:33 +02:00
parent a07a34eb24
commit 27a674efb8
8 changed files with 69 additions and 12 deletions

View File

@ -381,8 +381,10 @@ The following keywords are supported in the "global" section :
- nosepoll - nosepoll
- nosplice - nosplice
- spread-checks - spread-checks
- tune.bufsize
- tune.maxaccept - tune.maxaccept
- tune.maxpollevents - tune.maxpollevents
- tune.maxrewrite
* Debugging * Debugging
- debug - debug
@ -557,6 +559,16 @@ spread-checks <0..50, in percent>
some randomness in the check interval between 0 and +/- 50%. A value between some randomness in the check interval between 0 and +/- 50%. A value between
2 and 5 seems to show good results. The default value remains at 0. 2 and 5 seems to show good results. The default value remains at 0.
tune.bufsize <number>
Sets the buffer size to this size (in bytes). Lower values allow more
sessions to coexist in the same amount of RAM, and higher values allow some
applications with very large cookies to work. The default value is 16384 and
can be changed at build time. It is strongly recommended not to change this
from the default value, as very low values will break some services such as
statistics, and values larger than default size will increase memory usage,
possibly causing the system to run out of memory. At least the global maxconn
parameter should be decreased by the same factor as this one is increased.
tune.maxaccept <number> tune.maxaccept <number>
Sets the maximum number of consecutive accepts that a process may perform on Sets the maximum number of consecutive accepts that a process may perform on
a single wake up. High values give higher priority to high connection rates, a single wake up. High values give higher priority to high connection rates,
@ -574,6 +586,18 @@ tune.maxpollevents <number>
latency at the expense of network bandwidth, and increasing it above 200 latency at the expense of network bandwidth, and increasing it above 200
tends to trade latency for slightly increased bandwidth. tends to trade latency for slightly increased bandwidth.
tune.maxrewrite <number>
Sets the reserved buffer space to this size in bytes. The reserved space is
used for header rewriting or appending. The first reads on sockets will never
fill more than bufsize-maxrewrite. Historically it has defaulted to half of
bufsize, though that does not make much sense since there are rarely large
numbers of headers to add. Setting it too high prevents processing of large
requests or responses. Setting it too low prevents addition of new headers
to already large requests or to POST requests. It is generally wise to set it
to about 1024. It is automatically readjusted to half of bufsize if it is
larger than that. This means you don't have to worry about it when changing
bufsize.
3.3. Debugging 3.3. Debugging
-------------- --------------

View File

@ -79,6 +79,8 @@ struct global {
int maxaccept; /* max number of consecutive accept() */ int maxaccept; /* max number of consecutive accept() */
int options; /* various tuning options */ int options; /* various tuning options */
int recv_enough; /* how many input bytes at once are "enough" */ int recv_enough; /* how many input bytes at once are "enough" */
int bufsize; /* buffer size in bytes, defaults to BUFSIZE */
int maxrewrite; /* buffer max rewrite size in bytes, defaults to MAXREWRITE */
} tune; } tune;
struct listener stats_sock; /* unix socket listener for statistics */ struct listener stats_sock; /* unix socket listener for statistics */
struct proxy *stats_fe; /* the frontend holding the stats settings */ struct proxy *stats_fe; /* the frontend holding the stats settings */

View File

@ -17,6 +17,7 @@
#include <common/config.h> #include <common/config.h>
#include <common/memory.h> #include <common/memory.h>
#include <proto/buffers.h> #include <proto/buffers.h>
#include <types/global.h>
struct pool_head *pool2_buffer; struct pool_head *pool2_buffer;
@ -24,7 +25,7 @@ struct pool_head *pool2_buffer;
/* perform minimal intializations, report 0 in case of error, 1 if OK. */ /* perform minimal intializations, report 0 in case of error, 1 if OK. */
int init_buffer() int init_buffer()
{ {
pool2_buffer = create_pool("buffer", sizeof(struct buffer) + BUFSIZE, MEM_F_SHARED); pool2_buffer = create_pool("buffer", sizeof(struct buffer) + global.tune.bufsize, MEM_F_SHARED);
return pool2_buffer != NULL; return pool2_buffer != NULL;
} }

View File

@ -445,6 +445,26 @@ int cfg_parse_global(const char *file, int linenum, char **args, int kwm)
} }
global.tune.maxaccept = atol(args[1]); global.tune.maxaccept = atol(args[1]);
} }
else if (!strcmp(args[0], "tune.bufsize")) {
if (*(args[1]) == 0) {
Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
global.tune.bufsize = atol(args[1]);
if (global.tune.maxrewrite >= global.tune.bufsize / 2)
global.tune.maxrewrite = global.tune.bufsize / 2;
}
else if (!strcmp(args[0], "tune.maxrewrite")) {
if (*(args[1]) == 0) {
Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
global.tune.maxrewrite = atol(args[1]);
if (global.tune.maxrewrite >= global.tune.bufsize / 2)
global.tune.maxrewrite = global.tune.bufsize / 2;
}
else if (!strcmp(args[0], "uid")) { else if (!strcmp(args[0], "uid")) {
if (global.uid != 0) { if (global.uid != 0) {
Alert("parsing [%s:%d] : user/uid already specified. Continuing.\n", file, linenum); Alert("parsing [%s:%d] : user/uid already specified. Continuing.\n", file, linenum);
@ -3482,13 +3502,13 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
goto out; goto out;
} }
if (stat.st_size <= BUFSIZE) { if (stat.st_size <= global.tune.bufsize) {
errlen = stat.st_size; errlen = stat.st_size;
} else { } else {
Warning("parsing [%s:%d] : custom error message file <%s> larger than %d bytes. Truncating.\n", Warning("parsing [%s:%d] : custom error message file <%s> larger than %d bytes. Truncating.\n",
file, linenum, args[2], BUFSIZE); file, linenum, args[2], global.tune.bufsize);
err_code |= ERR_WARN; err_code |= ERR_WARN;
errlen = BUFSIZE; errlen = global.tune.bufsize;
} }
err = malloc(errlen); /* malloc() must succeed during parsing */ err = malloc(errlen); /* malloc() must succeed during parsing */

View File

@ -384,7 +384,7 @@ int event_accept(int fd) {
if ((s->req = pool_alloc2(pool2_buffer)) == NULL) if ((s->req = pool_alloc2(pool2_buffer)) == NULL)
goto out_fail_req; /* no memory */ goto out_fail_req; /* no memory */
s->req->size = BUFSIZE; s->req->size = global.tune.bufsize;
buffer_init(s->req); buffer_init(s->req);
s->req->prod = &s->si[0]; s->req->prod = &s->si[0];
s->req->cons = &s->si[1]; s->req->cons = &s->si[1];
@ -393,7 +393,7 @@ int event_accept(int fd) {
s->req->flags |= BF_READ_ATTACHED; /* the producer is already connected */ s->req->flags |= BF_READ_ATTACHED; /* the producer is already connected */
if (p->mode == PR_MODE_HTTP) { /* reserve some space for header rewriting */ if (p->mode == PR_MODE_HTTP) { /* reserve some space for header rewriting */
s->req->max_len -= MAXREWRITE; s->req->max_len -= global.tune.maxrewrite;
s->req->flags |= BF_READ_DONTWAIT; /* one read is usually enough */ s->req->flags |= BF_READ_DONTWAIT; /* one read is usually enough */
} }
@ -411,7 +411,7 @@ int event_accept(int fd) {
if ((s->rep = pool_alloc2(pool2_buffer)) == NULL) if ((s->rep = pool_alloc2(pool2_buffer)) == NULL)
goto out_fail_rep; /* no memory */ goto out_fail_rep; /* no memory */
s->rep->size = BUFSIZE; s->rep->size = global.tune.bufsize;
buffer_init(s->rep); buffer_init(s->rep);
s->rep->prod = &s->si[1]; s->rep->prod = &s->si[1];
s->rep->cons = &s->si[0]; s->rep->cons = &s->si[0];

View File

@ -122,7 +122,11 @@ struct global global = {
.mode = 0, .mode = 0,
} }
} }
} },
.tune = {
.bufsize = BUFSIZE,
.maxrewrite = MAXREWRITE,
},
/* others NULL OK */ /* others NULL OK */
}; };
@ -177,7 +181,10 @@ void display_build_opts()
#ifdef BUILD_OPTIONS #ifdef BUILD_OPTIONS
"\n OPTIONS = " BUILD_OPTIONS "\n OPTIONS = " BUILD_OPTIONS
#endif #endif
"\n\n"); "\n\nDefault settings :"
"\n maxconn = %d, bufsize = %d, maxrewrite = %d, maxpollevents = %d"
"\n\n",
DEFAULT_MAXCONN, BUFSIZE, MAXREWRITE, MAX_POLL_EVENTS);
} }
/* /*
@ -604,6 +611,9 @@ void init(int argc, char **argv)
if (global.tune.recv_enough == 0) if (global.tune.recv_enough == 0)
global.tune.recv_enough = MIN_RECV_AT_ONCE_ENOUGH; global.tune.recv_enough = MIN_RECV_AT_ONCE_ENOUGH;
if (global.tune.maxrewrite >= global.tune.bufsize / 2)
global.tune.maxrewrite = global.tune.bufsize / 2;
if (arg_mode & (MODE_DEBUG | MODE_FOREGROUND)) { if (arg_mode & (MODE_DEBUG | MODE_FOREGROUND)) {
/* command line debug mode inhibits configuration mode */ /* command line debug mode inhibits configuration mode */
global.mode &= ~(MODE_DAEMON | MODE_QUIET); global.mode &= ~(MODE_DAEMON | MODE_QUIET);

View File

@ -482,7 +482,7 @@ int uxst_event_accept(int fd) {
if ((s->req = pool_alloc2(pool2_buffer)) == NULL) if ((s->req = pool_alloc2(pool2_buffer)) == NULL)
goto out_free_task; goto out_free_task;
s->req->size = BUFSIZE; s->req->size = global.tune.bufsize;
buffer_init(s->req); buffer_init(s->req);
s->req->prod = &s->si[0]; s->req->prod = &s->si[0];
s->req->cons = &s->si[1]; s->req->cons = &s->si[1];
@ -499,7 +499,7 @@ int uxst_event_accept(int fd) {
if ((s->rep = pool_alloc2(pool2_buffer)) == NULL) if ((s->rep = pool_alloc2(pool2_buffer)) == NULL)
goto out_free_req; goto out_free_req;
s->rep->size = BUFSIZE; s->rep->size = global.tune.bufsize;
buffer_init(s->rep); buffer_init(s->rep);
s->rep->prod = &s->si[1]; s->rep->prod = &s->si[1];

View File

@ -330,7 +330,7 @@ void sess_establish(struct session *s, struct stream_interface *si)
} }
} }
else { else {
buffer_set_rlim(rep, req->size - MAXREWRITE); /* rewrite needed */ buffer_set_rlim(rep, req->size - global.tune.maxrewrite); /* rewrite needed */
s->txn.rsp.msg_state = HTTP_MSG_RPBEFORE; s->txn.rsp.msg_state = HTTP_MSG_RPBEFORE;
/* reset hdr_idx which was already initialized by the request. /* reset hdr_idx which was already initialized by the request.
* right now, the http parser does it. * right now, the http parser does it.