stick-table type {ip | integer | string [len <length>] | binary [len <length>]}
size <size> [expire <expire>] [nopurge] [peers <peersect>] [srvkey <srvkey>]
- [write-to <wtable>] [store <data_type>]*
+ [write-to <wtable>] [store <data_type>]* [brates-factor <factor>]
Configure the stickiness table for the current section
May be used in the following contexts: tcp, http
the type between parenthesis. See below for the supported data
types and their arguments.
+ <factor> is used to define a factor to be applied on in/out bytes rate.
+ Instead of counting each bytes, blocks of bytes are counted.
+ Internally, rates are defined on 32-bits counters. By using this
+ parameter, it is possible to have rates exceeding the 4G on the
+ defined period. The factor must be greater than 0 and lower or
+ equal to 1024.
+
The data types that can be stored with an entry are the following :
- server_id : this is an integer which holds the numeric ID of the server a
request was assigned to. It is used by the "stick match", "stick store",
ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_BYTES_IN_RATE);
if (ptr2)
update_freq_ctr_period(&stktable_data_cast(ptr2, std_t_frqp),
- stkctr->table->data_arg[STKTABLE_DT_BYTES_IN_RATE].u, bytes);
+ stkctr->table->data_arg[STKTABLE_DT_BYTES_IN_RATE].u,
+ div64_32(bytes + stkctr->table->brates_factor - 1, stkctr->table->brates_factor));
HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_BYTES_OUT_RATE);
if (ptr2)
update_freq_ctr_period(&stktable_data_cast(ptr2, std_t_frqp),
- stkctr->table->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u, bytes);
+ stkctr->table->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u,
+ div64_32(bytes + stkctr->table->brates_factor - 1, stkctr->table->brates_factor));
HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
struct bwlim_config *conf = FLT_CONF(filter);
struct bwlim_state *st = filter->ctx;
struct freq_ctr *bytes_rate;
- unsigned int period, limit, remain, tokens, users;
+ uint64_t remain;
+ unsigned int period, limit, tokens, users, factor;
unsigned int wait = 0;
int overshoot, ret = 0;
period = conf->table.t->data_arg[type].u;
limit = conf->limit;
users = st->ts->ref_cnt;
+ factor = conf->table.t->brates_factor;
}
else {
/* On per-stream mode, the freq-counter is private to the
period = (st->period ? st->period : conf->period);
limit = (st->limit ? st->limit : conf->limit);
users = 1;
+ factor = 1;
}
/* Be sure the current rate does not exceed the limit over the current
}
/* Get the allowed quota per user. */
- remain = freq_ctr_remain_period(bytes_rate, period, limit, 0);
+ remain = (uint64_t)freq_ctr_remain_period(bytes_rate, period, limit, 0) * factor;
tokens = div64_32((uint64_t)(remain + users - 1), users);
if (tokens < len) {
: conf->min_size;
if (ret <= remain)
- wait = div64_32((uint64_t)(ret - tokens) * period * users + limit - 1, limit);
+ wait = div64_32((uint64_t)(ret - tokens) * period * users + limit * factor - 1, limit * factor);
else
- ret = (limit < ret) ? remain : 0;
+ ret = (limit * factor < ret) ? remain : 0;
}
}
/* At the end, update the freq-counter and compute the waiting time if
* the stream is limited
*/
- update_freq_ctr_period(bytes_rate, period, ret);
+ update_freq_ctr_period(bytes_rate, period, div64_32((uint64_t)ret + factor -1, factor));
if (ret < len) {
wait += next_event_delay_period(bytes_rate, period, limit, MIN(len - ret, conf->min_size * users));
st->exp = tick_add(now_ms, (wait ? wait : 1));
t->conf.file = file;
t->conf.line = linenum;
t->write_to.name = NULL;
+ t->brates_factor = 1;
while (*args[idx]) {
const char *err;
t->write_to.name = strdup(write_to);
idx++;
}
+ else if (strcmp(args[idx], "brates-factor") == 0) {
+ idx++;
+ if (!*(args[idx])) {
+ ha_alert("parsing [%s:%d] : %s: missing argument after '%s'.\n",
+ file, linenum, args[0], args[idx-1]);
+ err_code |= ERR_ALERT | ERR_FATAL;
+ goto out;
+ }
+ if ((err = parse_size_err(args[idx], &t->brates_factor))) {
+ ha_alert("parsing [%s:%d] : %s: unexpected character '%c' in argument of '%s'.\n",
+ file, linenum, args[0], *err, args[idx-1]);
+ err_code |= ERR_ALERT | ERR_FATAL;
+ goto out;
+ }
+ if (t->brates_factor == 0 || t->brates_factor > 1024) {
+ ha_alert("parsing [%s:%d] : %s: argument '%s' must be greater than 0 and lower or equal than 1024.\n",
+ file, linenum, args[0], args[idx-1]);
+ err_code |= ERR_ALERT | ERR_FATAL;
+ goto out;
+ }
+ idx++;
+ }
else {
ha_alert("parsing [%s:%d] : %s: unknown argument '%s'.\n",
file, linenum, args[0], args[idx]);
ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_IN_RATE);
if (ptr)
- smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
- t->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
+ smp->data.u.sint = (uint64_t)read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
+ t->data_arg[STKTABLE_DT_BYTES_IN_RATE].u) * t->brates_factor;
stktable_release(t, ts);
return !!ptr;
ptr = stktable_data_ptr(t, ts, STKTABLE_DT_BYTES_OUT_RATE);
if (ptr)
- smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
- t->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
+ smp->data.u.sint = (uint64_t)read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
+ t->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u) * t->brates_factor;
+
stktable_release(t, ts);
return !!ptr;
HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
- smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
- stkctr->table->data_arg[STKTABLE_DT_BYTES_IN_RATE].u);
+ smp->data.u.sint = (uint64_t)read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
+ stkctr->table->data_arg[STKTABLE_DT_BYTES_IN_RATE].u) * stkctr->table->brates_factor;
HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
- smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
- stkctr->table->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u);
+ smp->data.u.sint = (uint64_t)read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
+ stkctr->table->data_arg[STKTABLE_DT_BYTES_OUT_RATE].u) * stkctr->table->brates_factor;
HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
for (dt = 0; dt < STKTABLE_DATA_TYPES; dt++) {
void *ptr;
+ long long data;
if (t->data_ofs[dt] == 0)
continue;
chunk_appendf(msg, "%llu", stktable_data_cast(ptr, std_t_ull));
break;
case STD_T_FRQP:
- chunk_appendf(msg, "%u",
- read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
- t->data_arg[dt].u));
+ data = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
+ t->data_arg[dt].u);
+ if (dt == STKTABLE_DT_BYTES_IN_RATE || dt == STKTABLE_DT_BYTES_OUT_RATE)
+ data *= t->brates_factor;
+ chunk_appendf(msg, "%llu", data);
break;
}
ptr = stktable_data_ptr_idx(t, entry, dt, ++idx);
chunk_appendf(msg, "%llu", stktable_data_cast(ptr, std_t_ull));
break;
case STD_T_FRQP:
- chunk_appendf(msg, "%u",
- read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
- t->data_arg[dt].u));
+ data = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
+ t->data_arg[dt].u);
+ if (dt == STKTABLE_DT_BYTES_IN_RATE || dt == STKTABLE_DT_BYTES_OUT_RATE)
+ data *= t->brates_factor;
+ chunk_appendf(msg, "%llu", data);
break;
case STD_T_DICT: {
struct dict_entry *de;
case STD_T_FRQP:
data = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
ctx->t->data_arg[dt].u);
+ if (dt == STKTABLE_DT_BYTES_IN_RATE || dt == STKTABLE_DT_BYTES_OUT_RATE)
+ data *= ctx->t->brates_factor;
break;
}