From: Olivier Houchard Date: Fri, 2 May 2025 12:07:53 +0000 (+0000) Subject: MEDIUM: stick-tables: Limit the number of entries we expire X-Git-Tag: v3.2-dev14~7 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=994cc58576f52d23c830a8acb6ab81a2a3e28477;p=thirdparty%2Fhaproxy.git MEDIUM: stick-tables: Limit the number of entries we expire In process_table_expire(), limit the number of entries we remove in one call, and just reschedule the task if there's more to do. Removing entries require to use the heavily contended update write lock, and we don't want to hold it for too long. This helps getting stick tables perform better under heavy load. --- diff --git a/src/stick_table.c b/src/stick_table.c index e4ac69847..9e7249fdc 100644 --- a/src/stick_table.c +++ b/src/stick_table.c @@ -884,7 +884,9 @@ struct task *process_table_expire(struct task *task, void *context, unsigned int struct stktable *t = context; struct stksess *ts; struct eb32_node *eb; + int need_resched = 0; int updt_locked; + int expired; int looped; int exp_next; int task_exp; @@ -897,6 +899,7 @@ struct task *process_table_expire(struct task *task, void *context, unsigned int looped = 0; HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &t->shards[shard].sh_lock); eb = eb32_lookup_ge(&t->shards[shard].exps, now_ms - TIMER_LOOK_BACK); + expired = 0; while (1) { if (unlikely(!eb)) { @@ -952,6 +955,14 @@ struct task *process_table_expire(struct task *task, void *context, unsigned int continue; } + if (updt_locked == 1) { + expired++; + if (expired == STKTABLE_MAX_UPDATES_AT_ONCE) { + need_resched = 1; + exp_next = TICK_ETERNITY; + goto out_unlock; + } + } /* if the entry is in the update list, we must be extremely careful * because peers can see it at any moment and start to use it. Peers * will take the table's updt_lock for reading when doing that, and @@ -986,13 +997,17 @@ struct task *process_table_expire(struct task *task, void *context, unsigned int HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &t->shards[shard].sh_lock); } - /* Reset the task's expiration. We do this under the lock so as not - * to ruin a call to task_queue() in stktable_requeue_exp() if we - * were to update with TICK_ETERNITY. - */ - HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &t->lock); - task->expire = task_exp; - HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &t->lock); + if (need_resched) { + task_wakeup(task, TASK_WOKEN_OTHER); + } else { + /* Reset the task's expiration. We do this under the lock so as not + * to ruin a call to task_queue() in stktable_requeue_exp() if we + * were to update with TICK_ETERNITY. + */ + HA_RWLOCK_WRLOCK(STK_TABLE_LOCK, &t->lock); + task->expire = task_exp; + HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &t->lock); + } return task; }