From: William Lallemand Date: Fri, 9 Nov 2012 16:05:39 +0000 (+0100) Subject: MINOR: compression: maximum compression rate limit X-Git-Tag: v1.5-dev13~65 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d85f917daf90ac0a84f28a27ac5904ccc0b3b345;p=thirdparty%2Fhaproxy.git MINOR: compression: maximum compression rate limit This patch adds input and output rate calcutation on the HTTP compresion feature. Compression can be limited with a maximum rate value in kilobytes per second. The rate is set with the global 'maxcomprate' option. You can change this value dynamicaly with 'set rate-limit http-compression global' on the UNIX socket. --- diff --git a/doc/configuration.txt b/doc/configuration.txt index f624abbbc9..0b310ee301 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -455,6 +455,7 @@ The following keywords are supported in the "global" section : * Performance tuning - maxconn - maxconnrate + - maxcomprate - maxpipes - maxsslconn - noepoll @@ -672,6 +673,15 @@ maxconnrate value close to its expected share. Also, lowering tune.maxaccept can improve fairness. +maxcomprate + Sets the maximum per-process input compression rate to kilobytes + pers second. For each session, if the maximum is reached, the compression + level will be decreased during the session. If the maximum is reached at the + beginning of a session, the session will not compress at all. If the maximum + is not reached, the compression level will be increased up to + tune.comp.maxlevel. A value of zero means there is no limit, this is the + default value. + maxpipes Sets the maximum per-process number of pipes to . Currently, pipes are only used by kernel-based tcp splicing. Since a pipe contains two file @@ -11110,6 +11120,11 @@ set rate-limit connections global applies to all frontends and the change has an immediate effect. The value is passed in number of connections per second. +set rate-limit http-compression global + Change the maximum input compression rate, which is set by the global + 'maxcomprate' setting. A value of zero disables the limitation. The value is + passed in number of kilobytes per second. + set table key data. Create or update a stick-table entry in the table. If the key is not present, an entry is inserted. See stick-table in section 4.2 to find all possible diff --git a/include/types/global.h b/include/types/global.h index cfb10d1f1f..6b267fbfcc 100644 --- a/include/types/global.h +++ b/include/types/global.h @@ -80,7 +80,10 @@ struct global { char *connect_default_ciphers; #endif struct freq_ctr conn_per_sec; + struct freq_ctr comp_bps_in; /* bytes per second, before http compression */ + struct freq_ctr comp_bps_out; /* bytes per second, after http compression */ int cps_lim, cps_max; + int comp_rate_lim; /* HTTP compression rate limit */ int maxpipes; /* max # of pipes */ int maxsock; /* max # of sockets */ int rlimit_nofile; /* default ulimit-n value : 0=unset */ diff --git a/src/cfgparse.c b/src/cfgparse.c index 5f22b24248..c601cbc8e3 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -844,6 +844,14 @@ int cfg_parse_global(const char *file, int linenum, char **args, int kwm) } global.cps_lim = atol(args[1]); } + else if (!strcmp(args[0], "maxcomprate")) { + if (*(args[1]) == 0) { + Alert("parsing [%s:%d] : '%s' expects an integer argument in kb/s.\n", file, linenum, args[0]); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + global.comp_rate_lim = atoi(args[1]) * 1024; + } else if (!strcmp(args[0], "maxpipes")) { if (global.maxpipes != 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 4c942aad70..ae43cd3759 100644 --- a/src/compression.c +++ b/src/compression.c @@ -31,6 +31,7 @@ #include #include +#include #include @@ -261,6 +262,10 @@ int http_compression_buffer_end(struct session *s, struct buffer **in, struct bu to_forward = ob->i; + /* update input rate */ + if (s->comp_ctx.cur_lvl > 0) + update_freq_ctr(&global.comp_bps_in, ib->o - ob->o); + /* copy the remaining data in the tmp buffer. */ if (ib->i > 0) { left = ib->i - bi_contig_data(ib); @@ -276,6 +281,9 @@ int http_compression_buffer_end(struct session *s, struct buffer **in, struct bu *in = ob; *out = ib; + if (s->comp_ctx.cur_lvl > 0) + update_freq_ctr(&global.comp_bps_out, to_forward); + /* forward the new chunk without remaining data */ b_adv(ob, to_forward); @@ -490,6 +498,23 @@ int deflate_flush(struct comp_ctx *comp_ctx, struct buffer *out, int flag) out_len = (out->size - buffer_len(out)) - strm->avail_out; out->i += out_len; + /* compression rate limit */ + if (global.comp_rate_lim > 0) { + + if (read_freq_ctr(&global.comp_bps_out) > global.comp_rate_lim) { + /* decrease level */ + if (comp_ctx->cur_lvl > 0) { + comp_ctx->cur_lvl--; + deflateParams(&comp_ctx->strm, comp_ctx->cur_lvl, Z_DEFAULT_STRATEGY); + } + + } else if (comp_ctx->cur_lvl < global.comp_rate_lim) { + /* increase level */ + comp_ctx->cur_lvl++ ; + deflateParams(&comp_ctx->strm, comp_ctx->cur_lvl, Z_DEFAULT_STRATEGY); + } + } + return out_len; } diff --git a/src/dumpstats.c b/src/dumpstats.c index da84f2a3de..0ee664164a 100644 --- a/src/dumpstats.c +++ b/src/dumpstats.c @@ -1246,8 +1246,21 @@ static int stats_sock_parse_request(struct stream_interface *si, char *line) return 1; } } + else if (strcmp(args[2], "http-compression") == 0) { + if (strcmp(args[3], "global") == 0) { + int v; + + v = atoi(args[4]); + global.comp_rate_lim = v * 1024; /* Kilo to bytes. */ + } + else { + si->applet.ctx.cli.msg = "'set rate-limit http-compression' only supports 'global'.\n"; + si->applet.st0 = STAT_CLI_PRINT; + return 1; + } + } else { - si->applet.ctx.cli.msg = "'set rate-limit' only supports 'connections'.\n"; + si->applet.ctx.cli.msg = "'set rate-limit' supports 'connections' and 'http-compression'.\n"; si->applet.st0 = STAT_CLI_PRINT; return 1; } @@ -1708,6 +1721,8 @@ static int stats_dump_raw_to_buffer(struct stream_interface *si) "ConnRate: %d\n" "ConnRateLimit: %d\n" "MaxConnRate: %d\n" + "CompressBpsIn: %u\n" + "CompressBpsOut: %u\n" "Tasks: %d\n" "Run_queue: %d\n" "Idle_pct: %d\n" @@ -1724,6 +1739,7 @@ static int stats_dump_raw_to_buffer(struct stream_interface *si) global.maxsock, global.maxconn, global.hardmaxconn, global.maxpipes, actconn, pipes_used, pipes_free, read_freq_ctr(&global.conn_per_sec), global.cps_lim, global.cps_max, + read_freq_ctr(&global.comp_bps_in), read_freq_ctr(&global.comp_bps_out), nb_tasks_cur, run_queue_cur, idle_pct, global.node, global.desc?global.desc:"" ); diff --git a/src/haproxy.c b/src/haproxy.c index b322244fc4..cfd6f84396 100644 --- a/src/haproxy.c +++ b/src/haproxy.c @@ -113,6 +113,7 @@ struct global global = { .req_count = 0, .logsrvs = LIST_HEAD_INIT(global.logsrvs), .maxzlibmem = 0, + .comp_rate_lim = 0, .unix_bind = { .ux = { .uid = -1, diff --git a/src/proto_http.c b/src/proto_http.c index 7f15107647..d768b87ac0 100644 --- a/src/proto_http.c +++ b/src/proto_http.c @@ -2087,6 +2087,11 @@ int select_compression_response_header(struct session *s, struct buffer *res) ctx.idx = 0; + /* limit compression rate */ + if (global.comp_rate_lim > 0) + if (read_freq_ctr(&global.comp_bps_in) > global.comp_rate_lim) + goto fail; + /* initialize compression */ if (s->comp_algo->init(&s->comp_ctx, global.tune.comp_maxlevel) < 0) goto fail;