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 f624abb..0b310ee 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -455,6 +455,7 @@
* Performance tuning
- maxconn
- maxconnrate
+ - maxcomprate
- maxpipes
- maxsslconn
- noepoll
@@ -672,6 +673,15 @@
value close to its expected share. Also, lowering tune.maxaccept can improve
fairness.
+maxcomprate <number>
+ Sets the maximum per-process input compression rate to <number> 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 <number>
Sets the maximum per-process number of pipes to <number>. Currently, pipes
are only used by kernel-based tcp splicing. Since a pipe contains two file
@@ -11110,6 +11120,11 @@
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 <value>
+ 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 <table> key <key> data.<data_type> <value>
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 cfb10d1..6b267fb 100644
--- a/include/types/global.h
+++ b/include/types/global.h
@@ -80,7 +80,10 @@
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 5f22b24..c601cbc 100644
--- a/src/cfgparse.c
+++ b/src/cfgparse.c
@@ -844,6 +844,14 @@
}
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 4c942aa..ae43cd3 100644
--- a/src/compression.c
+++ b/src/compression.c
@@ -31,6 +31,7 @@
#include <types/compression.h>
#include <proto/compression.h>
+#include <proto/freq_ctr.h>
#include <proto/proto_http.h>
@@ -261,6 +262,10 @@
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 @@
*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 @@
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 da84f2a..0ee6641 100644
--- a/src/dumpstats.c
+++ b/src/dumpstats.c
@@ -1246,8 +1246,21 @@
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 @@
"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 @@
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 b322244..cfd6f84 100644
--- a/src/haproxy.c
+++ b/src/haproxy.c
@@ -113,6 +113,7 @@
.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 7f15107..d768b87 100644
--- a/src/proto_http.c
+++ b/src/proto_http.c
@@ -2087,6 +2087,11 @@
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;