mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2025-02-20 20:57:00 +00:00
MEDIUM: stick-table: set the track-sc limit at boottime via tune.stick-counters
The number of stick-counter entries usable by track-sc rules is currently set at build time. There is no good value for this since the vast majority of users don't need any, most need only a few and rare users need more. Adding more counters for everyone increases memory and CPU usages for no reason. This patch moves the per-session and per-stream arrays to a pool of a size defined at boot time. This way it becomes possible to set the number of entries at boot time via a new global setting "tune.stick-counters" that sets the limit for the whole process. When not set, the MAX_SESS_STR_CTR value still applies, or 3 if not set, as before. It is also possible to lower the value to 0 to save a bit of memory if not used at all. Note that a few low-level sample-fetch functions had to be protected due to the ability to use sample-fetches in the global section to set some variables.
This commit is contained in:
parent
3120284c29
commit
6c0117168e
@ -1158,6 +1158,7 @@ The following keywords are supported in the "global" section :
|
||||
- tune.sched.low-latency
|
||||
- tune.sndbuf.client
|
||||
- tune.sndbuf.server
|
||||
- tune.stick-counters
|
||||
- tune.ssl.cachesize
|
||||
- tune.ssl.capture-buffer-size
|
||||
- tune.ssl.capture-cipherlist-size (deprecated)
|
||||
@ -3305,6 +3306,21 @@ tune.ssl.ssl-ctx-cache-size <number>
|
||||
dynamically is expensive, they are cached. The default cache size is set to
|
||||
1000 entries.
|
||||
|
||||
tune.stick-counters <number>
|
||||
Sets the number of stick-counters that may be tracked at the same time by a
|
||||
connection or a request via "track-sc*" actions in "tcp-request" or
|
||||
"http-request" rules. The defaut value is set at build time by the macro
|
||||
MAX_SESS_STK_CTR, and defaults to 3. With this setting it is possible to
|
||||
change the value and ignore the one passed at build time. Increasing this
|
||||
value may be needed when porting complex configurations to haproxy, but users
|
||||
are warned against the costs: each entry takes 16 bytes per connection and
|
||||
16 bytes per request, all of which need to be allocated and zeroed for all
|
||||
requests even when not used. As such a value of 10 will inflate the memory
|
||||
consumption per request by 320 bytes and will cause this memory to be erased
|
||||
for each request, which does have measurable CPU impacts. Conversely, when
|
||||
no "track-sc" rules are used, the value may be lowered (0 being valid to
|
||||
entirely disable stick-counters).
|
||||
|
||||
tune.vars.global-max-size <size>
|
||||
tune.vars.proc-max-size <size>
|
||||
tune.vars.reqres-max-size <size>
|
||||
@ -7617,9 +7633,10 @@ http-request track-sc2 <key> [table <table>] [ { if | unless } <condition> ]
|
||||
|
||||
This enables tracking of sticky counters from current request. These rules do
|
||||
not stop evaluation and do not change default action. The number of counters
|
||||
that may be simultaneously tracked by the same connection is set in
|
||||
MAX_SESS_STKCTR at build time (reported in haproxy -vv) which defaults to 3,
|
||||
so the track-sc number is between 0 and (MAX_SESS_STKCTR-1). The first
|
||||
that may be simultaneously tracked by the same connection is set by the
|
||||
global "tune.stick-counters" setting, which defaults to MAX_SESS_STKCTR if
|
||||
set at build time (it is reported in haproxy -vv) and which defaults to 3,
|
||||
so the track-sc number is between 0 and (tune.stick-counters-1). The first
|
||||
"track-sc0" rule executed enables tracking of the counters of the specified
|
||||
table as the first set. The first "track-sc1" rule executed enables tracking
|
||||
of the counters of the specified table as the second set. The first
|
||||
@ -18924,12 +18941,12 @@ TCP/IP addresses and ports, as well as elements from stick-tables related to
|
||||
the incoming connection. For retrieving a value from a sticky counters, the
|
||||
counter number can be explicitly set as 0, 1, or 2 using the pre-defined
|
||||
"sc0_", "sc1_", or "sc2_" prefix. These three pre-defined prefixes can only be
|
||||
used if MAX_SESS_STKCTR value does not exceed 3, otherwise the counter number
|
||||
can be specified as the first integer argument when using the "sc_" prefix.
|
||||
Starting from "sc_0" to "sc_N" where N is (MAX_SESS_STKCTR-1). An optional
|
||||
table may be specified with the "sc*" form, in which case the currently
|
||||
tracked key will be looked up into this alternate table instead of the table
|
||||
currently being tracked.
|
||||
used if the global "tune.stick-counters" value does not exceed 3, otherwise the
|
||||
counter number can be specified as the first integer argument when using the
|
||||
"sc_" prefix starting from "sc_0" to "sc_N" where N is (tune.stick-counters-1).
|
||||
An optional table may be specified with the "sc*" form, in which case the
|
||||
currently tracked key will be looked up into this alternate table instead of
|
||||
the table currently being tracked.
|
||||
|
||||
bc_dst : ip
|
||||
This is the destination ip address of the connection on the server side,
|
||||
|
@ -162,6 +162,7 @@ struct global {
|
||||
int pool_high_count; /* max number of opened fd before we start killing idle connections when creating new connections */
|
||||
size_t pool_cache_size; /* per-thread cache size per pool (defaults to CONFIG_HAP_POOL_CACHE_SIZE) */
|
||||
unsigned short idle_timer; /* how long before an empty buffer is considered idle (ms) */
|
||||
int nb_stk_ctr; /* number of stick counters, defaults to MAX_SESS_STKCTR */
|
||||
#ifdef USE_QUIC
|
||||
unsigned int quic_backend_max_idle_timeout;
|
||||
unsigned int quic_frontend_max_idle_timeout;
|
||||
|
@ -50,7 +50,7 @@ struct session {
|
||||
enum obj_type *origin; /* the connection / applet which initiated this session */
|
||||
struct timeval accept_date; /* date of the session's accept() in user date */
|
||||
struct timeval tv_accept; /* date of the session's accept() in internal date (monotonic) */
|
||||
struct stkctr stkctr[MAX_SESS_STKCTR]; /* stick counters for tcp-connection */
|
||||
struct stkctr *stkctr; /* stick counters for tcp-connection */
|
||||
struct vars vars; /* list of variables for the session scope. */
|
||||
struct task *task; /* handshake timeout processing */
|
||||
long t_handshake; /* handshake duration, -1 = not completed */
|
||||
|
@ -50,7 +50,10 @@ static inline void session_store_counters(struct session *sess)
|
||||
int i;
|
||||
struct stksess *ts;
|
||||
|
||||
for (i = 0; i < MAX_SESS_STKCTR; i++) {
|
||||
if (unlikely(!sess->stkctr)) // pool not allocated yet
|
||||
return;
|
||||
|
||||
for (i = 0; i < global.tune.nb_stk_ctr; i++) {
|
||||
struct stkctr *stkctr = &sess->stkctr[i];
|
||||
|
||||
ts = stkctr_entry(stkctr);
|
||||
@ -80,7 +83,10 @@ static inline void session_inc_http_req_ctr(struct session *sess)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_SESS_STKCTR; i++)
|
||||
if (unlikely(!sess->stkctr)) // pool not allocated yet
|
||||
return;
|
||||
|
||||
for (i = 0; i < global.tune.nb_stk_ctr; i++)
|
||||
stkctr_inc_http_req_ctr(&sess->stkctr[i]);
|
||||
}
|
||||
|
||||
@ -94,7 +100,10 @@ static inline void session_inc_http_err_ctr(struct session *sess)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_SESS_STKCTR; i++)
|
||||
if (unlikely(!sess->stkctr)) // pool not allocated yet
|
||||
return;
|
||||
|
||||
for (i = 0; i < global.tune.nb_stk_ctr; i++)
|
||||
stkctr_inc_http_err_ctr(&sess->stkctr[i]);
|
||||
}
|
||||
|
||||
@ -107,7 +116,10 @@ static inline void session_inc_http_fail_ctr(struct session *sess)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_SESS_STKCTR; i++)
|
||||
if (unlikely(!sess->stkctr)) // pool not allocated yet
|
||||
return;
|
||||
|
||||
for (i = 0; i < global.tune.nb_stk_ctr; i++)
|
||||
stkctr_inc_http_fail_ctr(&sess->stkctr[i]);
|
||||
}
|
||||
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include <haproxy/ticks.h>
|
||||
|
||||
extern struct stktable *stktables_list;
|
||||
extern struct pool_head *pool_head_stk_ctr;
|
||||
extern struct stktable_type stktable_types[];
|
||||
|
||||
#define stktable_data_size(type) (sizeof(((union stktable_data*)0)->type))
|
||||
|
@ -245,7 +245,7 @@ struct stream {
|
||||
struct stktable *table;
|
||||
} store[8]; /* tracked stickiness values to store */
|
||||
|
||||
struct stkctr stkctr[MAX_SESS_STKCTR]; /* content-aware stick counters */
|
||||
struct stkctr *stkctr; /* content-aware stick counters */
|
||||
|
||||
struct strm_flt strm_flt; /* current state of filters active on this stream */
|
||||
|
||||
|
@ -116,7 +116,10 @@ static inline void stream_store_counters(struct stream *s)
|
||||
int i;
|
||||
struct stksess *ts;
|
||||
|
||||
for (i = 0; i < MAX_SESS_STKCTR; i++) {
|
||||
if (unlikely(!s->stkctr)) // pool not allocated yet
|
||||
return;
|
||||
|
||||
for (i = 0; i < global.tune.nb_stk_ctr; i++) {
|
||||
ts = stkctr_entry(&s->stkctr[i]);
|
||||
if (!ts)
|
||||
continue;
|
||||
@ -152,7 +155,10 @@ static inline void stream_stop_content_counters(struct stream *s)
|
||||
void *ptr;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_SESS_STKCTR; i++) {
|
||||
if (unlikely(!s->stkctr)) // pool not allocated yet
|
||||
return;
|
||||
|
||||
for (i = 0; i < global.tune.nb_stk_ctr; i++) {
|
||||
ts = stkctr_entry(&s->stkctr[i]);
|
||||
if (!ts)
|
||||
continue;
|
||||
@ -231,7 +237,10 @@ static inline void stream_inc_http_req_ctr(struct stream *s)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_SESS_STKCTR; i++) {
|
||||
if (unlikely(!s->stkctr)) // pool not allocated yet
|
||||
return;
|
||||
|
||||
for (i = 0; i < global.tune.nb_stk_ctr; i++) {
|
||||
if (!stkctr_inc_http_req_ctr(&s->stkctr[i]))
|
||||
stkctr_inc_http_req_ctr(&s->sess->stkctr[i]);
|
||||
}
|
||||
@ -244,7 +253,10 @@ static inline void stream_inc_be_http_req_ctr(struct stream *s)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_SESS_STKCTR; i++) {
|
||||
if (unlikely(!s->stkctr)) // pool not allocated yet
|
||||
return;
|
||||
|
||||
for (i = 0; i < global.tune.nb_stk_ctr; i++) {
|
||||
if (!stkctr_entry(&s->stkctr[i]) || !(stkctr_flags(&s->stkctr[i]) & STKCTR_TRACK_BACKEND))
|
||||
continue;
|
||||
|
||||
@ -262,7 +274,10 @@ static inline void stream_inc_http_err_ctr(struct stream *s)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_SESS_STKCTR; i++) {
|
||||
if (unlikely(!s->stkctr)) // pool not allocated yet
|
||||
return;
|
||||
|
||||
for (i = 0; i < global.tune.nb_stk_ctr; i++) {
|
||||
if (!stkctr_inc_http_err_ctr(&s->stkctr[i]))
|
||||
stkctr_inc_http_err_ctr(&s->sess->stkctr[i]);
|
||||
}
|
||||
@ -277,7 +292,10 @@ static inline void stream_inc_http_fail_ctr(struct stream *s)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_SESS_STKCTR; i++) {
|
||||
if (unlikely(!s->stkctr)) // pool not allocated yet
|
||||
return;
|
||||
|
||||
for (i = 0; i < global.tune.nb_stk_ctr; i++) {
|
||||
if (!stkctr_inc_http_fail_ctr(&s->stkctr[i]))
|
||||
stkctr_inc_http_fail_ctr(&s->sess->stkctr[i]);
|
||||
}
|
||||
|
@ -1564,9 +1564,13 @@ cfg_parse_track_sc_num(unsigned int *track_sc_num,
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (num >= MAX_SESS_STKCTR) {
|
||||
memprintf(errmsg, "%u track-sc number exceeding "
|
||||
"%d (MAX_SESS_STKCTR-1) value", num, MAX_SESS_STKCTR - 1);
|
||||
if (num >= global.tune.nb_stk_ctr) {
|
||||
if (!global.tune.nb_stk_ctr)
|
||||
memprintf(errmsg, "%u track-sc number not usable, stick-counters "
|
||||
"are disabled by tune.stick-counters", num);
|
||||
else
|
||||
memprintf(errmsg, "%u track-sc number exceeding "
|
||||
"%d (tune.stick-counters-1) value", num, global.tune.nb_stk_ctr - 1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -204,6 +204,7 @@ struct global global = {
|
||||
#else
|
||||
.idle_timer = 1000, /* 1 second */
|
||||
#endif
|
||||
.nb_stk_ctr = MAX_SESS_STKCTR,
|
||||
#ifdef USE_QUIC
|
||||
.quic_backend_max_idle_timeout = QUIC_TP_DFLT_BACK_MAX_IDLE_TIMEOUT,
|
||||
.quic_frontend_max_idle_timeout = QUIC_TP_DFLT_FRONT_MAX_IDLE_TIMEOUT,
|
||||
|
@ -46,7 +46,13 @@ struct session *session_new(struct proxy *fe, struct listener *li, enum obj_type
|
||||
sess->origin = origin;
|
||||
sess->accept_date = date; /* user-visible date for logging */
|
||||
sess->tv_accept = now; /* corrected date for internal use */
|
||||
memset(sess->stkctr, 0, sizeof(sess->stkctr));
|
||||
sess->stkctr = NULL;
|
||||
if (pool_head_stk_ctr) {
|
||||
sess->stkctr = pool_alloc(pool_head_stk_ctr);
|
||||
if (!sess->stkctr)
|
||||
goto out_fail_alloc;
|
||||
memset(sess->stkctr, 0, sizeof(sess->stkctr[0]) * global.tune.nb_stk_ctr);
|
||||
}
|
||||
vars_init_head(&sess->vars, SCOPE_SESS);
|
||||
sess->task = NULL;
|
||||
sess->t_handshake = -1; /* handshake not done yet */
|
||||
@ -60,6 +66,9 @@ struct session *session_new(struct proxy *fe, struct listener *li, enum obj_type
|
||||
sess->dst = NULL;
|
||||
}
|
||||
return sess;
|
||||
out_fail_alloc:
|
||||
pool_free(pool_head_session, sess);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void session_free(struct session *sess)
|
||||
@ -70,6 +79,7 @@ void session_free(struct session *sess)
|
||||
if (sess->listener)
|
||||
listener_release(sess->listener);
|
||||
session_store_counters(sess);
|
||||
pool_free(pool_head_stk_ctr, sess->stkctr);
|
||||
vars_prune_per_sess(&sess->vars);
|
||||
conn = objt_conn(sess->origin);
|
||||
if (conn != NULL && conn->mux)
|
||||
@ -116,7 +126,7 @@ static void session_count_new(struct session *sess)
|
||||
|
||||
proxy_inc_fe_sess_ctr(sess->listener, sess->fe);
|
||||
|
||||
for (i = 0; i < MAX_SESS_STKCTR; i++) {
|
||||
for (i = 0; i < global.tune.nb_stk_ctr; i++) {
|
||||
stkctr = &sess->stkctr[i];
|
||||
if (!stkctr_entry(stkctr))
|
||||
continue;
|
||||
|
@ -50,7 +50,7 @@
|
||||
/* structure used to return a table key built from a sample */
|
||||
static THREAD_LOCAL struct stktable_key static_table_key;
|
||||
static int (*smp_fetch_src)(const struct arg *, struct sample *, const char *, void *);
|
||||
|
||||
struct pool_head *pool_head_stk_ctr __read_mostly = NULL;
|
||||
struct stktable *stktables_list;
|
||||
struct eb_root stktable_by_name = EB_ROOT;
|
||||
|
||||
@ -2456,14 +2456,16 @@ static enum act_return action_inc_gpc1(struct act_rule *rule, struct proxy *px,
|
||||
struct session *sess, struct stream *s, int flags)
|
||||
{
|
||||
struct stksess *ts;
|
||||
struct stkctr *stkctr;
|
||||
struct stkctr *stkctr = NULL;
|
||||
unsigned int period = 0;
|
||||
|
||||
/* Extract the stksess, return OK if no stksess available. */
|
||||
if (s)
|
||||
if (s && s->stkctr)
|
||||
stkctr = &s->stkctr[rule->arg.gpc.sc];
|
||||
else
|
||||
else if (sess->stkctr)
|
||||
stkctr = &sess->stkctr[rule->arg.gpc.sc];
|
||||
else
|
||||
return ACT_RET_CONT;
|
||||
|
||||
ts = stkctr_entry(stkctr);
|
||||
if (ts) {
|
||||
@ -2522,6 +2524,11 @@ static enum act_parse_ret parse_inc_gpc(const char **args, int *arg, struct prox
|
||||
const char *cmd_name = args[*arg-1];
|
||||
char *error;
|
||||
|
||||
if (!global.tune.nb_stk_ctr) {
|
||||
memprintf(err, "Cannot use '%s', stick-counters are disabled via tune.stick-counters", args[*arg-1]);
|
||||
return ACT_RET_PRS_ERR;
|
||||
}
|
||||
|
||||
cmd_name += strlen("sc-inc-gpc");
|
||||
if (*cmd_name == '(') {
|
||||
cmd_name++; /* skip the '(' */
|
||||
@ -2538,9 +2545,9 @@ static enum act_parse_ret parse_inc_gpc(const char **args, int *arg, struct prox
|
||||
return ACT_RET_PRS_ERR;
|
||||
}
|
||||
|
||||
if (rule->arg.gpc.sc >= MAX_SESS_STKCTR) {
|
||||
memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
|
||||
args[*arg-1], MAX_SESS_STKCTR-1);
|
||||
if (rule->arg.gpc.sc >= global.tune.nb_stk_ctr) {
|
||||
memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d (tune.stick-counters)",
|
||||
args[*arg-1], global.tune.nb_stk_ctr-1);
|
||||
return ACT_RET_PRS_ERR;
|
||||
}
|
||||
}
|
||||
@ -2566,9 +2573,9 @@ static enum act_parse_ret parse_inc_gpc(const char **args, int *arg, struct prox
|
||||
return ACT_RET_PRS_ERR;
|
||||
}
|
||||
|
||||
if (rule->arg.gpc.sc >= MAX_SESS_STKCTR) {
|
||||
memprintf(err, "invalid stick table track ID. The max allowed ID is %d",
|
||||
MAX_SESS_STKCTR-1);
|
||||
if (rule->arg.gpc.sc >= global.tune.nb_stk_ctr) {
|
||||
memprintf(err, "invalid stick table track ID. The max allowed ID is %d (tune.stick-counters)",
|
||||
global.tune.nb_stk_ctr-1);
|
||||
return ACT_RET_PRS_ERR;
|
||||
}
|
||||
}
|
||||
@ -2599,16 +2606,18 @@ static enum act_return action_set_gpt(struct act_rule *rule, struct proxy *px,
|
||||
{
|
||||
void *ptr;
|
||||
struct stksess *ts;
|
||||
struct stkctr *stkctr;
|
||||
struct stkctr *stkctr = NULL;
|
||||
unsigned int value = 0;
|
||||
struct sample *smp;
|
||||
int smp_opt_dir;
|
||||
|
||||
/* Extract the stksess, return OK if no stksess available. */
|
||||
if (s)
|
||||
if (s && s->stkctr)
|
||||
stkctr = &s->stkctr[rule->arg.gpt.sc];
|
||||
else
|
||||
else if (sess->stkctr)
|
||||
stkctr = &sess->stkctr[rule->arg.gpt.sc];
|
||||
else
|
||||
return ACT_RET_CONT;
|
||||
|
||||
ts = stkctr_entry(stkctr);
|
||||
if (!ts)
|
||||
@ -2663,16 +2672,18 @@ static enum act_return action_set_gpt0(struct act_rule *rule, struct proxy *px,
|
||||
{
|
||||
void *ptr;
|
||||
struct stksess *ts;
|
||||
struct stkctr *stkctr;
|
||||
struct stkctr *stkctr = NULL;
|
||||
unsigned int value = 0;
|
||||
struct sample *smp;
|
||||
int smp_opt_dir;
|
||||
|
||||
/* Extract the stksess, return OK if no stksess available. */
|
||||
if (s)
|
||||
if (s && s->stkctr)
|
||||
stkctr = &s->stkctr[rule->arg.gpt.sc];
|
||||
else
|
||||
else if (sess->stkctr)
|
||||
stkctr = &sess->stkctr[rule->arg.gpt.sc];
|
||||
else
|
||||
return ACT_RET_CONT;
|
||||
|
||||
ts = stkctr_entry(stkctr);
|
||||
if (!ts)
|
||||
@ -2741,6 +2752,11 @@ static enum act_parse_ret parse_set_gpt(const char **args, int *arg, struct prox
|
||||
char *error;
|
||||
int smp_val;
|
||||
|
||||
if (!global.tune.nb_stk_ctr) {
|
||||
memprintf(err, "Cannot use '%s', stick-counters are disabled via tune.stick-counters", args[*arg-1]);
|
||||
return ACT_RET_PRS_ERR;
|
||||
}
|
||||
|
||||
cmd_name += strlen("sc-set-gpt");
|
||||
if (*cmd_name == '(') {
|
||||
cmd_name++; /* skip the '(' */
|
||||
@ -2757,9 +2773,9 @@ static enum act_parse_ret parse_set_gpt(const char **args, int *arg, struct prox
|
||||
return ACT_RET_PRS_ERR;
|
||||
}
|
||||
|
||||
if (rule->arg.gpt.sc >= MAX_SESS_STKCTR) {
|
||||
if (rule->arg.gpt.sc >= global.tune.nb_stk_ctr) {
|
||||
memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
|
||||
args[*arg-1], MAX_SESS_STKCTR-1);
|
||||
args[*arg-1], global.tune.nb_stk_ctr-1);
|
||||
return ACT_RET_PRS_ERR;
|
||||
}
|
||||
}
|
||||
@ -2783,9 +2799,9 @@ static enum act_parse_ret parse_set_gpt(const char **args, int *arg, struct prox
|
||||
return ACT_RET_PRS_ERR;
|
||||
}
|
||||
|
||||
if (rule->arg.gpt.sc >= MAX_SESS_STKCTR) {
|
||||
if (rule->arg.gpt.sc >= global.tune.nb_stk_ctr) {
|
||||
memprintf(err, "invalid stick table track ID '%s'. The max allowed ID is %d",
|
||||
args[*arg-1], MAX_SESS_STKCTR-1);
|
||||
args[*arg-1], global.tune.nb_stk_ctr-1);
|
||||
return ACT_RET_PRS_ERR;
|
||||
}
|
||||
}
|
||||
@ -2914,15 +2930,19 @@ smp_fetch_sc_stkctr(struct session *sess, struct stream *strm, const struct arg
|
||||
* the sc[0-9]_ form, or even higher using sc_(num) if needed.
|
||||
* args[arg] is the first optional argument. We first lookup the
|
||||
* ctr form the stream, then from the session if it was not there.
|
||||
* But we must be sure the counter does not exceed MAX_SESS_STKCTR.
|
||||
* But we must be sure the counter does not exceed global.tune.nb_stk_ctr.
|
||||
*/
|
||||
if (num >= MAX_SESS_STKCTR)
|
||||
if (num >= global.tune.nb_stk_ctr)
|
||||
return NULL;
|
||||
|
||||
if (strm)
|
||||
stkptr = NULL;
|
||||
if (strm && strm->stkctr)
|
||||
stkptr = &strm->stkctr[num];
|
||||
if (!strm || !stkctr_entry(stkptr)) {
|
||||
stkptr = &sess->stkctr[num];
|
||||
if (!strm || !stkptr || !stkctr_entry(stkptr)) {
|
||||
if (sess->stkctr)
|
||||
stkptr = &sess->stkctr[num];
|
||||
else
|
||||
return NULL;
|
||||
if (!stkctr_entry(stkptr))
|
||||
return NULL;
|
||||
}
|
||||
@ -4990,6 +5010,45 @@ static void cli_release_show_table(struct appctx *appctx)
|
||||
}
|
||||
}
|
||||
|
||||
static int stk_parse_stick_counters(char **args, int section_type, struct proxy *curpx,
|
||||
const struct proxy *defpx, const char *file, int line,
|
||||
char **err)
|
||||
{
|
||||
char *error;
|
||||
int counters;
|
||||
|
||||
counters = strtol(args[1], &error, 10);
|
||||
if (*error != 0) {
|
||||
memprintf(err, "%s: '%s' is an invalid number", args[0], args[1]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (counters < 0) {
|
||||
memprintf(err, "%s: the number of stick-counters may not be negative (was %d)", args[0], counters);
|
||||
return -1;
|
||||
}
|
||||
|
||||
global.tune.nb_stk_ctr = counters;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This function creates the stk_ctr pools after the configuration parsing. It
|
||||
* returns 0 on success otherwise ERR_*. If nb_stk_ctr is 0, the pool remains
|
||||
* NULL.
|
||||
*/
|
||||
static int stkt_create_stk_ctr_pool(void)
|
||||
{
|
||||
if (!global.tune.nb_stk_ctr)
|
||||
return 0;
|
||||
|
||||
pool_head_stk_ctr = create_pool("stk_ctr", sizeof(*((struct session*)0)->stkctr) * global.tune.nb_stk_ctr, MEM_F_SHARED);
|
||||
if (!pool_head_stk_ctr) {
|
||||
ha_alert("out of memory while creating the stick-counters pool.\n");
|
||||
return ERR_ABORT;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void stkt_late_init(void)
|
||||
{
|
||||
struct sample_fetch *f;
|
||||
@ -4997,6 +5056,7 @@ static void stkt_late_init(void)
|
||||
f = find_sample_fetch("src", strlen("src"));
|
||||
if (f)
|
||||
smp_fetch_src = f->process;
|
||||
hap_register_post_check(stkt_create_stk_ctr_pool);
|
||||
}
|
||||
|
||||
INITCALL0(STG_INIT, stkt_late_init);
|
||||
@ -5273,3 +5333,10 @@ static struct sample_conv_kw_list sample_conv_kws = {ILH, {
|
||||
}};
|
||||
|
||||
INITCALL1(STG_REGISTER, sample_register_convs, &sample_conv_kws);
|
||||
|
||||
static struct cfg_kw_list cfg_kws = {{ },{
|
||||
{ CFG_GLOBAL, "tune.stick-counters", stk_parse_stick_counters },
|
||||
{ /* END */ }
|
||||
}};
|
||||
|
||||
INITCALL1(STG_REGISTER, cfg_register_keywords, &cfg_kws);
|
||||
|
28
src/stream.c
28
src/stream.c
@ -388,13 +388,20 @@ struct stream *stream_new(struct session *sess, struct stconn *sc, struct buffer
|
||||
s->last_rule_file = NULL;
|
||||
s->last_rule_line = 0;
|
||||
|
||||
/* Copy SC counters for the stream. We don't touch refcounts because
|
||||
* any reference we have is inherited from the session. Since the stream
|
||||
* doesn't exist without the session, the session's existence guarantees
|
||||
* we don't lose the entry. During the store operation, the stream won't
|
||||
* touch these ones.
|
||||
*/
|
||||
memcpy(s->stkctr, sess->stkctr, sizeof(s->stkctr));
|
||||
s->stkctr = NULL;
|
||||
if (pool_head_stk_ctr) {
|
||||
s->stkctr = pool_alloc(pool_head_stk_ctr);
|
||||
if (!s->stkctr)
|
||||
goto out_fail_alloc;
|
||||
|
||||
/* Copy SC counters for the stream. We don't touch refcounts because
|
||||
* any reference we have is inherited from the session. Since the stream
|
||||
* doesn't exist without the session, the session's existence guarantees
|
||||
* we don't lose the entry. During the store operation, the stream won't
|
||||
* touch these ones.
|
||||
*/
|
||||
memcpy(s->stkctr, sess->stkctr, sizeof(s->stkctr[0]) * global.tune.nb_stk_ctr);
|
||||
}
|
||||
|
||||
s->sess = sess;
|
||||
|
||||
@ -582,6 +589,8 @@ struct stream *stream_new(struct session *sess, struct stconn *sc, struct buffer
|
||||
out_fail_attach_scf:
|
||||
task_destroy(t);
|
||||
out_fail_alloc:
|
||||
if (s)
|
||||
pool_free(pool_head_stk_ctr, s->stkctr);
|
||||
pool_free(pool_head_stream, s);
|
||||
DBG_TRACE_DEVEL("leaving on error", STRM_EV_STRM_NEW|STRM_EV_STRM_ERR);
|
||||
return NULL;
|
||||
@ -701,6 +710,7 @@ void stream_free(struct stream *s)
|
||||
vars_prune(&s->vars_reqres, s->sess, s);
|
||||
|
||||
stream_store_counters(s);
|
||||
pool_free(pool_head_stk_ctr, s->stkctr);
|
||||
|
||||
list_for_each_entry_safe(bref, back, &s->back_refs, users) {
|
||||
/* we have to unlink all watchers. We must not relink them if
|
||||
@ -797,7 +807,7 @@ void stream_process_counters(struct stream *s)
|
||||
if (sess->listener && sess->listener->counters)
|
||||
_HA_ATOMIC_ADD(&sess->listener->counters->bytes_in, bytes);
|
||||
|
||||
for (i = 0; i < MAX_SESS_STKCTR; i++) {
|
||||
for (i = 0; i < global.tune.nb_stk_ctr; i++) {
|
||||
if (!stkctr_inc_bytes_in_ctr(&s->stkctr[i], bytes))
|
||||
stkctr_inc_bytes_in_ctr(&sess->stkctr[i], bytes);
|
||||
}
|
||||
@ -815,7 +825,7 @@ void stream_process_counters(struct stream *s)
|
||||
if (sess->listener && sess->listener->counters)
|
||||
_HA_ATOMIC_ADD(&sess->listener->counters->bytes_out, bytes);
|
||||
|
||||
for (i = 0; i < MAX_SESS_STKCTR; i++) {
|
||||
for (i = 0; i < global.tune.nb_stk_ctr; i++) {
|
||||
if (!stkctr_inc_bytes_out_ctr(&s->stkctr[i], bytes))
|
||||
stkctr_inc_bytes_out_ctr(&sess->stkctr[i], bytes);
|
||||
}
|
||||
|
@ -1058,7 +1058,7 @@ static int tcp_parse_request_rule(char **args, int arg, int section_type,
|
||||
memprintf(err,
|
||||
"'%s %s' expects 'accept', 'reject', 'capture', 'expect-proxy', 'expect-netscaler-cip', 'track-sc0' ... 'track-sc%d', %s "
|
||||
"in %s '%s' (got '%s').%s%s%s\n",
|
||||
args[0], args[1], MAX_SESS_STKCTR-1,
|
||||
args[0], args[1], global.tune.nb_stk_ctr-1,
|
||||
trash.area, proxy_type_str(curpx),
|
||||
curpx->id, args[arg],
|
||||
best ? " Did you mean '" : "",
|
||||
|
Loading…
Reference in New Issue
Block a user