diff --git a/doc/configuration.txt b/doc/configuration.txt index 50f82e577..84fc9c921 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -381,8 +381,10 @@ The following keywords are supported in the "global" section : - nosepoll - nosplice - spread-checks + - tune.bufsize - tune.maxaccept - tune.maxpollevents + - tune.maxrewrite * Debugging - debug @@ -557,6 +559,16 @@ spread-checks <0..50, in percent> 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. +tune.bufsize + 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 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, @@ -574,6 +586,18 @@ tune.maxpollevents latency at the expense of network bandwidth, and increasing it above 200 tends to trade latency for slightly increased bandwidth. +tune.maxrewrite + 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 -------------- diff --git a/include/types/global.h b/include/types/global.h index aefee3226..4d349c313 100644 --- a/include/types/global.h +++ b/include/types/global.h @@ -79,6 +79,8 @@ struct global { int maxaccept; /* max number of consecutive accept() */ int options; /* various tuning options */ 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; struct listener stats_sock; /* unix socket listener for statistics */ struct proxy *stats_fe; /* the frontend holding the stats settings */ diff --git a/src/buffers.c b/src/buffers.c index 55b79639b..a20f3f499 100644 --- a/src/buffers.c +++ b/src/buffers.c @@ -17,6 +17,7 @@ #include #include #include +#include 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. */ 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; } diff --git a/src/cfgparse.c b/src/cfgparse.c index a6b9f07ce..382881225 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -445,6 +445,26 @@ int cfg_parse_global(const char *file, int linenum, char **args, int kwm) } 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")) { if (global.uid != 0) { 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; } - if (stat.st_size <= BUFSIZE) { + if (stat.st_size <= global.tune.bufsize) { errlen = stat.st_size; } else { 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; - errlen = BUFSIZE; + errlen = global.tune.bufsize; } err = malloc(errlen); /* malloc() must succeed during parsing */ diff --git a/src/client.c b/src/client.c index 92baefc63..76ea122c9 100644 --- a/src/client.c +++ b/src/client.c @@ -384,7 +384,7 @@ int event_accept(int fd) { if ((s->req = pool_alloc2(pool2_buffer)) == NULL) goto out_fail_req; /* no memory */ - s->req->size = BUFSIZE; + s->req->size = global.tune.bufsize; buffer_init(s->req); s->req->prod = &s->si[0]; 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 */ 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 */ } @@ -411,7 +411,7 @@ int event_accept(int fd) { if ((s->rep = pool_alloc2(pool2_buffer)) == NULL) goto out_fail_rep; /* no memory */ - s->rep->size = BUFSIZE; + s->rep->size = global.tune.bufsize; buffer_init(s->rep); s->rep->prod = &s->si[1]; s->rep->cons = &s->si[0]; diff --git a/src/haproxy.c b/src/haproxy.c index 09f828809..dd03e32aa 100644 --- a/src/haproxy.c +++ b/src/haproxy.c @@ -122,7 +122,11 @@ struct global global = { .mode = 0, } } - } + }, + .tune = { + .bufsize = BUFSIZE, + .maxrewrite = MAXREWRITE, + }, /* others NULL OK */ }; @@ -177,7 +181,10 @@ void display_build_opts() #ifdef BUILD_OPTIONS "\n OPTIONS = " BUILD_OPTIONS #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) 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)) { /* command line debug mode inhibits configuration mode */ global.mode &= ~(MODE_DAEMON | MODE_QUIET); diff --git a/src/proto_uxst.c b/src/proto_uxst.c index 0cd6a3586..c811f64a8 100644 --- a/src/proto_uxst.c +++ b/src/proto_uxst.c @@ -482,7 +482,7 @@ int uxst_event_accept(int fd) { if ((s->req = pool_alloc2(pool2_buffer)) == NULL) goto out_free_task; - s->req->size = BUFSIZE; + s->req->size = global.tune.bufsize; buffer_init(s->req); s->req->prod = &s->si[0]; s->req->cons = &s->si[1]; @@ -499,7 +499,7 @@ int uxst_event_accept(int fd) { if ((s->rep = pool_alloc2(pool2_buffer)) == NULL) goto out_free_req; - s->rep->size = BUFSIZE; + s->rep->size = global.tune.bufsize; buffer_init(s->rep); s->rep->prod = &s->si[1]; diff --git a/src/session.c b/src/session.c index 23c4409c6..f0c2d8658 100644 --- a/src/session.c +++ b/src/session.c @@ -330,7 +330,7 @@ void sess_establish(struct session *s, struct stream_interface *si) } } 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; /* reset hdr_idx which was already initialized by the request. * right now, the http parser does it.