diff --git a/include/haproxy/stick_table-t.h b/include/haproxy/stick_table-t.h index c915edce6..132422980 100644 --- a/include/haproxy/stick_table-t.h +++ b/include/haproxy/stick_table-t.h @@ -208,6 +208,7 @@ struct stktable { unsigned int update; /* uses updt_lock */ unsigned int localupdate; /* uses updt_lock */ unsigned int commitupdate;/* used to identify the latest local updates pending for sync, uses updt_lock */ + __decl_thread(HA_RWLOCK_T updt_lock); /* lock protecting the updates part */ }; extern struct stktable_data_type stktable_data_types[STKTABLE_DATA_TYPES]; diff --git a/src/peers.c b/src/peers.c index 616b6e4f8..011c1ed89 100644 --- a/src/peers.c +++ b/src/peers.c @@ -1576,9 +1576,9 @@ static inline int peer_send_teachmsgs(struct appctx *appctx, struct peer *p, new_pushed = 1; if (locked) - HA_RWLOCK_WRTORD(STK_TABLE_LOCK, &st->table->lock); - else - HA_RWLOCK_RDLOCK(STK_TABLE_LOCK, &st->table->lock); + HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &st->table->lock); + + HA_RWLOCK_RDLOCK(STK_TABLE_LOCK, &st->table->updt_lock); while (1) { struct stksess *ts; @@ -1600,10 +1600,10 @@ static inline int peer_send_teachmsgs(struct appctx *appctx, struct peer *p, } HA_ATOMIC_INC(&ts->ref_cnt); - HA_RWLOCK_RDUNLOCK(STK_TABLE_LOCK, &st->table->lock); + HA_RWLOCK_RDUNLOCK(STK_TABLE_LOCK, &st->table->updt_lock); ret = peer_send_updatemsg(st, appctx, ts, updateid, new_pushed, use_timed); - HA_RWLOCK_RDLOCK(STK_TABLE_LOCK, &st->table->lock); + HA_RWLOCK_RDLOCK(STK_TABLE_LOCK, &st->table->updt_lock); HA_ATOMIC_DEC(&ts->ref_cnt); if (ret <= 0) break; @@ -1635,7 +1635,7 @@ static inline int peer_send_teachmsgs(struct appctx *appctx, struct peer *p, } out: - HA_RWLOCK_RDUNLOCK(STK_TABLE_LOCK, &st->table->lock); + HA_RWLOCK_RDUNLOCK(STK_TABLE_LOCK, &st->table->updt_lock); if (locked) HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &st->table->lock); diff --git a/src/stick_table.c b/src/stick_table.c index 6ba26ffa7..1e04e7b37 100644 --- a/src/stick_table.c +++ b/src/stick_table.c @@ -119,7 +119,11 @@ int __stksess_kill(struct stktable *t, struct stksess *ts) return 0; eb32_delete(&ts->exp); - eb32_delete(&ts->upd); + if (ts->upd.node.leaf_p) { + HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &t->updt_lock); + eb32_delete(&ts->upd); + HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &t->updt_lock); + } ebmb_delete(&ts->key); __stksess_free(t, ts); return 1; @@ -278,7 +282,11 @@ int __stktable_trash_oldest(struct stktable *t, int to_batch) /* session expired, trash it */ ebmb_delete(&ts->key); - eb32_delete(&ts->upd); + if (ts->upd.node.leaf_p) { + HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &t->updt_lock); + eb32_delete(&ts->upd); + HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &t->updt_lock); + } __stksess_free(t, ts); batched++; } @@ -441,7 +449,7 @@ void stktable_touch_with_exp(struct stktable *t, struct stksess *ts, int local, * or not scheduled for at least one peer. */ if (!locked++) - HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &t->lock); + HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &t->updt_lock); if (!ts->upd.node.leaf_p || (int)(t->commitupdate - ts->upd.key) >= 0 @@ -460,7 +468,7 @@ void stktable_touch_with_exp(struct stktable *t, struct stksess *ts, int local, else { /* If this entry is not in the tree */ if (!locked++) - HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &t->lock); + HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &t->updt_lock); if (!ts->upd.node.leaf_p) { ts->upd.key= (++t->update)+(2147483648U); @@ -474,7 +482,7 @@ void stktable_touch_with_exp(struct stktable *t, struct stksess *ts, int local, } if (locked) - HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &t->lock); + HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &t->updt_lock); if (decrefcnt) HA_ATOMIC_DEC(&ts->ref_cnt); @@ -664,6 +672,7 @@ struct task *process_table_expire(struct task *task, void *context, unsigned int struct stktable *t = context; struct stksess *ts; struct eb32_node *eb; + int updt_locked = 0; int looped = 0; int exp_next; @@ -726,7 +735,13 @@ struct task *process_table_expire(struct task *task, void *context, unsigned int /* session expired, trash it */ ebmb_delete(&ts->key); - eb32_delete(&ts->upd); + if (ts->upd.node.leaf_p) { + if (!updt_locked) { + updt_locked = 1; + HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &t->updt_lock); + } + eb32_delete(&ts->upd); + } __stksess_free(t, ts); } @@ -735,6 +750,8 @@ struct task *process_table_expire(struct task *task, void *context, unsigned int out_unlock: task->expire = exp_next; + if (updt_locked) + HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &t->updt_lock); HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &t->lock); return task; }