MINOR: stick-tables: mark the seen stksess with a flag "seen"

Right now we're taking the stick-tables update lock for reads just for
the sake of checking if the update index is past it or not. That's
costly because even taking the read lock is sufficient to provoke a
cache line write, while when under load or attack it's frequent that
the update has not yet been propagated and wouldn't require anything.

This commit brings a new field to the stksess, "seen", which is zeroed
when the entry is updated, and set to one as soon as at least one peer
starts to consult it. This way it will reflect that the entry must be
updated again so that this peer can see it. Otherwise no update will
be necessary. For now the flag is only set/reset but not exploited.
A great care is taken to avoid writes whenever possible.
This commit is contained in:
Willy Tarreau 2024-04-02 18:49:53 +02:00
parent 15522fc243
commit 4c1480f13b
3 changed files with 20 additions and 4 deletions

View File

@ -147,7 +147,8 @@ struct stksess {
unsigned int expire; /* session expiration date */
unsigned int ref_cnt; /* reference count, can only purge when zero */
__decl_thread(HA_RWLOCK_T lock); /* lock related to the table entry */
int shard; /* shard */
int shard; /* shard number used by peers */
int seen; /* 0 only when no peer has seen this entry yet */
struct eb32_node exp; /* ebtree node used to hold the session in expiration tree */
struct eb32_node upd; /* ebtree node used to hold the update sequence tree */
struct ebmb_node key; /* ebtree node used to hold the session in table */

View File

@ -1478,6 +1478,7 @@ static inline int peer_send_error_protomsg(struct appctx *appctx)
static inline struct stksess *peer_teach_process_stksess_lookup(struct shared_table *st)
{
struct eb32_node *eb;
struct stksess *ret;
eb = eb32_lookup_ge(&st->table->updates, st->last_pushed+1);
if (!eb) {
@ -1497,7 +1498,10 @@ static inline struct stksess *peer_teach_process_stksess_lookup(struct shared_ta
return NULL;
}
return eb32_entry(eb, struct stksess, upd);
ret = eb32_entry(eb, struct stksess, upd);
if (!_HA_ATOMIC_LOAD(&ret->seen))
_HA_ATOMIC_STORE(&ret->seen, 1);
return ret;
}
/*
@ -1507,6 +1511,7 @@ static inline struct stksess *peer_teach_process_stksess_lookup(struct shared_ta
static inline struct stksess *peer_teach_stage1_stksess_lookup(struct shared_table *st)
{
struct eb32_node *eb;
struct stksess *ret;
eb = eb32_lookup_ge(&st->table->updates, st->last_pushed+1);
if (!eb) {
@ -1517,7 +1522,10 @@ static inline struct stksess *peer_teach_stage1_stksess_lookup(struct shared_tab
return NULL;
}
return eb32_entry(eb, struct stksess, upd);
ret = eb32_entry(eb, struct stksess, upd);
if (!_HA_ATOMIC_LOAD(&ret->seen))
_HA_ATOMIC_STORE(&ret->seen, 1);
return ret;
}
/*
@ -1527,6 +1535,7 @@ static inline struct stksess *peer_teach_stage1_stksess_lookup(struct shared_tab
static inline struct stksess *peer_teach_stage2_stksess_lookup(struct shared_table *st)
{
struct eb32_node *eb;
struct stksess *ret;
eb = eb32_lookup_ge(&st->table->updates, st->last_pushed+1);
if (!eb || eb->key > st->teaching_origin) {
@ -1534,7 +1543,10 @@ static inline struct stksess *peer_teach_stage2_stksess_lookup(struct shared_tab
return NULL;
}
return eb32_entry(eb, struct stksess, upd);
ret = eb32_entry(eb, struct stksess, upd);
if (!_HA_ATOMIC_LOAD(&ret->seen))
_HA_ATOMIC_STORE(&ret->seen, 1);
return ret;
}
/*

View File

@ -215,6 +215,7 @@ static struct stksess *__stksess_init(struct stktable *t, struct stksess * ts)
memset((void *)ts - t->data_size, 0, t->data_size);
ts->ref_cnt = 0;
ts->shard = 0;
ts->seen = 0;
ts->key.node.leaf_p = NULL;
ts->exp.node.leaf_p = NULL;
ts->upd.node.leaf_p = NULL;
@ -523,6 +524,7 @@ void stktable_touch_with_exp(struct stktable *t, struct stksess *ts, int local,
/* here we're write-locked */
ts->seen = 0;
ts->upd.key = ++t->update;
t->localupdate = t->update;
eb32_delete(&ts->upd);
@ -552,6 +554,7 @@ void stktable_touch_with_exp(struct stktable *t, struct stksess *ts, int local,
/* here we're write-locked */
ts->seen = 0;
ts->upd.key= (++t->update)+(2147483648U);
eb = eb32_insert(&t->updates, &ts->upd);
if (eb != &ts->upd) {