From: William Lallemand Date: Wed, 7 Nov 2012 15:12:57 +0000 (+0100) Subject: MEDIUM: compression: limit RAM usage X-Git-Tag: v1.5-dev13~74 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=9d5f5480fdf4eac3c1440c377f1b75652a92bc25;p=thirdparty%2Fhaproxy.git MEDIUM: compression: limit RAM usage With the global maxzlibmem option, you are able ton control the maximum amount of RAM usable for HTTP compression. A test is done before each zlib allocation, if the there isn't available memory, the test fail and so the zlib initialization, so data won't be compressed. --- diff --git a/doc/configuration.txt b/doc/configuration.txt index eb249889b9..c6eed082e8 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -688,6 +688,12 @@ maxsslconn that the limit applies both to incoming and outgoing connections, so one connection which is deciphered then ciphered accounts for 2 SSL connections. +maxzlibmem + Sets the maximum amount of RAM in megabytes per process usable by the zlib. + When the maximum amount is reached, future sessions will not compress as long + as RAM is unavailable. When sets to 0, there is no limit. + The default value is 0. + noepoll Disables the use of the "epoll" event polling system on Linux. It is equivalent to the command-line argument "-de". The next polling system diff --git a/include/types/global.h b/include/types/global.h index 2f41be5589..e4e317bd26 100644 --- a/include/types/global.h +++ b/include/types/global.h @@ -85,6 +85,7 @@ struct global { int maxsock; /* max # of sockets */ int rlimit_nofile; /* default ulimit-n value : 0=unset */ int rlimit_memmax; /* default ulimit-d in megs value : 0=unset */ + int maxzlibmem; /* max RAM for zlib in megs */ int mode; unsigned int req_count; /* HTTP request counter */ int last_checks; diff --git a/src/cfgparse.c b/src/cfgparse.c index 4a1ca758ac..d5ada1dcff 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -841,6 +841,14 @@ int cfg_parse_global(const char *file, int linenum, char **args, int kwm) } global.maxpipes = atol(args[1]); } + else if (!strcmp(args[0], "maxzlibmem")) { + 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.maxzlibmem = atol(args[1]); + } else if (!strcmp(args[0], "ulimit-n")) { if (global.rlimit_nofile != 0) { Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]); diff --git a/src/compression.c b/src/compression.c index 3c88a6c9d3..4c942aad70 100644 --- a/src/compression.c +++ b/src/compression.c @@ -43,6 +43,9 @@ static struct pool_head *zlib_pool_prev = NULL; static struct pool_head *zlib_pool_head = NULL; static struct pool_head *zlib_pool_pending_buf = NULL; +static long long zlib_memory_available = -1; + + #endif @@ -341,6 +344,11 @@ static void *alloc_zlib(void *opaque, unsigned int items, unsigned int size) static char round = 0; /* order in deflateInit2 */ void *buf = NULL; + if (global.maxzlibmem > 0 && zlib_memory_available < items * size){ + buf = NULL; + goto end; + } + switch (round) { case 0: if (zlib_pool_deflate_state == NULL) @@ -372,6 +380,10 @@ static void *alloc_zlib(void *opaque, unsigned int items, unsigned int size) ctx->zlib_pending_buf = buf = pool_alloc2(zlib_pool_pending_buf); break; } + if (buf != NULL && global.maxzlibmem > 0) + zlib_memory_available -= items * size; + +end: round = (round + 1) % 5; /* there are 5 zalloc call in deflateInit2 */ return buf; @@ -380,18 +392,22 @@ static void *alloc_zlib(void *opaque, unsigned int items, unsigned int size) static void free_zlib(void *opaque, void *ptr) { struct comp_ctx *ctx = opaque; + struct pool_head *pool; if (ptr == ctx->zlib_window) - pool_free2(zlib_pool_window, ptr); + pool = zlib_pool_window; else if (ptr == ctx->zlib_deflate_state) - pool_free2(zlib_pool_deflate_state, ptr); + pool = zlib_pool_deflate_state; else if (ptr == ctx->zlib_prev) - pool_free2(zlib_pool_prev, ptr); + pool = zlib_pool_prev; else if (ptr == ctx->zlib_head) - pool_free2(zlib_pool_head, ptr); + pool = zlib_pool_head; else if (ptr == ctx->zlib_pending_buf) - pool_free2(zlib_pool_pending_buf, ptr); + pool = zlib_pool_pending_buf; + pool_free2(pool, ptr); + if (global.maxzlibmem > 0) + zlib_memory_available += pool->size; } @@ -402,6 +418,9 @@ int gzip_init(struct comp_ctx *comp_ctx, int level) { z_stream *strm = &comp_ctx->strm; + if (global.maxzlibmem > 0 && zlib_memory_available < 0) + zlib_memory_available = global.maxzlibmem * 1024 * 1024; /* Megabytes to bytes */ + strm->zalloc = alloc_zlib; strm->zfree = free_zlib; strm->opaque = comp_ctx; @@ -487,10 +506,10 @@ int deflate_end(struct comp_ctx *comp_ctx) { z_stream *strm = &comp_ctx->strm; - if (deflateEnd(strm) == Z_OK) - return 0; + if (deflateEnd(strm) != Z_OK) + return -1; - return -1; + return 0; } #endif /* USE_ZLIB */ diff --git a/src/haproxy.c b/src/haproxy.c index d85a46afee..d0e740b7db 100644 --- a/src/haproxy.c +++ b/src/haproxy.c @@ -112,6 +112,7 @@ int relative_pid = 1; /* process id starting at 1 */ struct global global = { .req_count = 0, .logsrvs = LIST_HEAD_INIT(global.logsrvs), + .maxzlibmem = 0, .unix_bind = { .ux = { .uid = -1,