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 eb24988..c6eed08 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -688,6 +688,12 @@
that the limit applies both to incoming and outgoing connections, so one
connection which is deciphered then ciphered accounts for 2 SSL connections.
+maxzlibmem <number>
+ 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 2f41be5..e4e317b 100644
--- a/include/types/global.h
+++ b/include/types/global.h
@@ -85,6 +85,7 @@
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 4a1ca75..d5ada1d 100644
--- a/src/cfgparse.c
+++ b/src/cfgparse.c
@@ -841,6 +841,14 @@
}
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 3c88a6c..4c942aa 100644
--- a/src/compression.c
+++ b/src/compression.c
@@ -43,6 +43,9 @@
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 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 @@
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 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 @@
{
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 @@
{
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 d85a46a..d0e740b 100644
--- a/src/haproxy.c
+++ b/src/haproxy.c
@@ -112,6 +112,7 @@
struct global global = {
.req_count = 0,
.logsrvs = LIST_HEAD_INIT(global.logsrvs),
+ .maxzlibmem = 0,
.unix_bind = {
.ux = {
.uid = -1,