]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: compression: limit RAM usage
authorWilliam Lallemand <wlallemand@exceliance.fr>
Wed, 7 Nov 2012 15:12:57 +0000 (16:12 +0100)
committerWilly Tarreau <w@1wt.eu>
Thu, 8 Nov 2012 14:23:30 +0000 (15:23 +0100)
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.

doc/configuration.txt
include/types/global.h
src/cfgparse.c
src/compression.c
src/haproxy.c

index eb249889b9d9c7e65e3a0bd0d72a80a165d04005..c6eed082e8739519d11bef58d6936cd0a6750f21 100644 (file)
@@ -688,6 +688,12 @@ maxsslconn <number>
   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
index 2f41be5589b1a35234ffb1c566660492df6287dd..e4e317bd26f079d3e35aac01f2679a351af82dd0 100644 (file)
@@ -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;
index 4a1ca758ac93a28e3b22aa58ea8e2ab760586ad0..d5ada1dcfff4d63ee1ce6c40b3fad8edcde1748d 100644 (file)
@@ -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]);
index 3c88a6c9d32a85508b094cc50ae4a5f976948ed9..4c942aad702f12573e0ced7b9cd06bcf5965ef47 100644 (file)
@@ -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 */
index d85a46afeed72af8426ac835379cd37650058e68..d0e740b7db1718643ff62c2750b25c6172ae7a00 100644 (file)
@@ -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,