From 50440457e3aeee92a51df484465a880ed3a83c8c Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Fri, 3 Feb 2023 15:52:07 +0100 Subject: [PATCH] MEDIUM: config: restrict shards, not bind_conf to one group each Now that we're using thread_sets there's no need to restrict an entire bind_conf to 1 group, the real concern being the FD, we can move that restriction to the shard only. This means that as long as we have enough shards and that they're properly aligned on group boundaries (i.e. shards are an integer divider of the number of threads), we can support "bind" lines spanning more than one group. The check is still performed for shards to span more than one group, and an error is emitted when this happens. But at least now it becomes possible to have this: global nbthread 256 frontend foo bind :1111 shards 4 bind :2222 shards by-thread --- src/cfgparse.c | 60 ++++++++++++++++++++++++++++++++++---------------- 1 file changed, 41 insertions(+), 19 deletions(-) diff --git a/src/cfgparse.c b/src/cfgparse.c index fc8c7f2ba4..2788d67011 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -2960,41 +2960,63 @@ init_proxies_list_stage1: free(err); cfgerr++; } - else if (bind_conf->thread_set.nbgrp > 1) { - ha_alert("Proxy '%s': 'thread' spans more than one group in 'bind %s' at [%s:%d].\n", - curproxy->id, bind_conf->arg, bind_conf->file, bind_conf->line); - cfgerr++; - } /* apply thread masks and groups to all receivers */ list_for_each_entry(li, &bind_conf->listeners, by_bind) { struct listener *new_li; - int shard, shards, todo, done, bit; - ulong mask; + struct thread_set new_ts; + int shard, shards, todo, done, grp; + ulong mask, bit; shards = bind_conf->settings.shards; - todo = my_popcountl(thread_set_first_tmask(&bind_conf->thread_set)); + todo = thread_set_count(&bind_conf->thread_set); /* no more shards than total threads */ if (shards > todo) shards = todo; - shard = done = bit = 0; + shard = done = grp = bit = mask = 0; new_li = li; - while (1) { - mask = 0; - while (done < todo) { - /* enlarge mask to cover next bit of bind_thread */ - while (!(thread_set_first_tmask(&bind_conf->thread_set) & (1UL << bit))) - bit++; - mask |= (1UL << bit); - bit++; + while (shard < shards) { + memset(&new_ts, 0, sizeof(new_ts)); + while (grp < global.nbtgroups && done < todo) { + /* enlarge mask to cover next bit of bind_thread till we + * have enough bits for one shard. We restart from the + * current grp+bit. + */ + + /* first let's find the first non-empty group starting at */ + if (!(bind_conf->thread_set.rel[grp] & ha_tgroup_info[grp].threads_enabled & ~mask)) { + grp++; + mask = 0; + continue; + } + + /* take next unassigned bit */ + bit = (bind_conf->thread_set.rel[grp] & ~mask) & -(bind_conf->thread_set.rel[grp] & ~mask); + new_ts.rel[grp] |= bit; + mask |= bit; + + if (!atleast2(new_ts.rel[grp])) // first time we add a bit: new group + new_ts.nbgrp++; + done += shards; + }; + + BUG_ON(!new_ts.nbgrp); // no more bits left unassigned + + if (new_ts.nbgrp > 1) { + ha_alert("Proxy '%s': shard number %d spans %d groups in 'bind %s' at [%s:%d]\n", + curproxy->id, shard, new_ts.nbgrp, bind_conf->arg, bind_conf->file, bind_conf->line); + cfgerr++; + err_code |= ERR_FATAL | ERR_ALERT; + goto out; } - new_li->rx.bind_thread = thread_set_first_tmask(&bind_conf->thread_set) & mask; - new_li->rx.bind_tgroup = thread_set_first_group(&bind_conf->thread_set); + /* assign the first (and only) thread and group */ + new_li->rx.bind_thread = thread_set_first_tmask(&new_ts); + new_li->rx.bind_tgroup = thread_set_first_group(&new_ts); done -= todo; shard++; -- 2.39.5