MINOR: global: add a new "thread-group" directive

This registers a mapping of threads to groups by enumerating for each thread
what group it belongs to, and marking the group as assigned. It takes care of
checking for redefinitions, overlaps, and holes. It supports both individual
numbers and ranges. The thread group is referenced from the thread config.
This commit is contained in:
Willy Tarreau 2021-09-27 13:55:10 +02:00
parent c33b969e35
commit d04bc3ac21
3 changed files with 104 additions and 0 deletions

View File

@ -2070,6 +2070,17 @@ stats maxconn <connections>
By default, the stats socket is limited to 10 concurrent connections. It is By default, the stats socket is limited to 10 concurrent connections. It is
possible to change this value with "stats maxconn". possible to change this value with "stats maxconn".
thread-group <group> [<thread-range>...]
This setting is only available when support for threads was built in. It
enumerates the list of threads that will compose thread group <group>.
Thread numbers and group numbers start at 1. Thread ranges are defined either
using a single thread number at once, or by specifying the lower and upper
bounds delimited by a dash '-' (e.g. "1-16"). Unassigned threads will be
automatically assigned to unassigned thread groups, and thread groups
defined with this directive will never receive more threads than those
defined. Defining the same group multiple times overrides previous
definitions with the new one. See also "nbthread" and "thread-groups".
thread-groups <number> thread-groups <number>
This setting is only available when support for threads was built in. It This setting is only available when support for threads was built in. It
makes HAProxy split its threads into <number> independent groups. At the makes HAProxy split its threads into <number> independent groups. At the

View File

@ -58,6 +58,8 @@ struct tgroup_info {
* thread-local "ti" pointer. * thread-local "ti" pointer.
*/ */
struct thread_info { struct thread_info {
const struct tgroup_info *tg; /* config of the thread-group this thread belongs to */
/* pad to cache line (64B) */ /* pad to cache line (64B) */
char __pad[0]; /* unused except to check remaining room */ char __pad[0]; /* unused except to check remaining room */
char __end[0] __attribute__((aligned(64))); char __end[0] __attribute__((aligned(64)));

View File

@ -1042,6 +1042,96 @@ static int cfg_parse_nbthread(char **args, int section_type, struct proxy *curpx
return 0; return 0;
} }
/* Parse the "thread-group" global directive, which takes an integer argument
* that designates a thread group, and a list of threads to put into that group.
*/
static int cfg_parse_thread_group(char **args, int section_type, struct proxy *curpx,
const struct proxy *defpx, const char *file, int line,
char **err)
{
char *errptr;
long tnum, tend, tgroup;
int arg, tot;
tgroup = strtol(args[1], &errptr, 10);
if (!*args[1] || *errptr) {
memprintf(err, "'%s' passed a missing or unparsable integer value in '%s'", args[0], args[1]);
return -1;
}
if (tgroup < 1 || tgroup > MAX_TGROUPS) {
memprintf(err, "'%s' thread-group number must be between 1 and %d (was %ld)", args[0], MAX_TGROUPS, tgroup);
return -1;
}
/* look for a preliminary definition of any thread pointing to this
* group, and remove them.
*/
if (ha_tgroup_info[tgroup-1].count) {
ha_warning("parsing [%s:%d] : '%s %ld' was already defined and will be overridden.\n",
file, line, args[0], tgroup);
for (tnum = ha_tgroup_info[tgroup-1].base;
tnum < ha_tgroup_info[tgroup-1].base + ha_tgroup_info[tgroup-1].count;
tnum++) {
if (ha_thread_info[tnum-1].tg == &ha_tgroup_info[tgroup-1])
ha_thread_info[tnum-1].tg = NULL;
}
ha_tgroup_info[tgroup-1].count = ha_tgroup_info[tgroup-1].base = 0;
}
tot = 0;
for (arg = 2; args[arg] && *args[arg]; arg++) {
tend = tnum = strtol(args[arg], &errptr, 10);
if (*errptr == '-')
tend = strtol(errptr + 1, &errptr, 10);
if (*errptr || tnum < 1 || tend < 1 || tnum > MAX_THREADS || tend > MAX_THREADS) {
memprintf(err, "'%s %ld' passed an unparsable or invalid thread number '%s' (valid range is 1 to %d)", args[0], tgroup, args[arg], MAX_THREADS);
return -1;
}
for(; tnum <= tend; tnum++) {
if (ha_thread_info[tnum-1].tg == &ha_tgroup_info[tgroup-1]) {
ha_warning("parsing [%s:%d] : '%s %ld': thread %ld assigned more than once on the same line.\n",
file, line, args[0], tgroup, tnum);
} else if (ha_thread_info[tnum-1].tg) {
ha_warning("parsing [%s:%d] : '%s %ld': thread %ld was previously assigned to thread group %ld and will be overridden.\n",
file, line, args[0], tgroup, tnum,
(long)(ha_thread_info[tnum-1].tg - &ha_tgroup_info[0] + 1));
}
if (!ha_tgroup_info[tgroup-1].count) {
ha_tgroup_info[tgroup-1].base = tnum-1;
ha_tgroup_info[tgroup-1].count = 1;
}
else if (tnum >= ha_tgroup_info[tgroup-1].base + ha_tgroup_info[tgroup-1].count) {
ha_tgroup_info[tgroup-1].count = tnum - ha_tgroup_info[tgroup-1].base;
}
else if (tnum < ha_tgroup_info[tgroup-1].base) {
ha_tgroup_info[tgroup-1].count += ha_tgroup_info[tgroup-1].base - tnum-1;
ha_tgroup_info[tgroup-1].base = tnum - 1;
}
ha_thread_info[tnum-1].tg = &ha_tgroup_info[tgroup-1];
tot++;
}
}
if (ha_tgroup_info[tgroup-1].count > tot) {
memprintf(err, "'%s %ld' assigned sparse threads, only contiguous supported", args[0], tgroup);
return -1;
}
if (ha_tgroup_info[tgroup-1].count > MAX_THREADS_PER_GROUP) {
memprintf(err, "'%s %ld' assigned too many threads (%d, max=%d)", args[0], tgroup, tot, MAX_THREADS_PER_GROUP);
return -1;
}
return 0;
}
/* Parse the "thread-groups" global directive, which takes an integer argument /* Parse the "thread-groups" global directive, which takes an integer argument
* that contains the desired number of thread groups. * that contains the desired number of thread groups.
*/ */
@ -1084,6 +1174,7 @@ static int cfg_parse_thread_groups(char **args, int section_type, struct proxy *
/* config keyword parsers */ /* config keyword parsers */
static struct cfg_kw_list cfg_kws = {ILH, { static struct cfg_kw_list cfg_kws = {ILH, {
{ CFG_GLOBAL, "nbthread", cfg_parse_nbthread, 0 }, { CFG_GLOBAL, "nbthread", cfg_parse_nbthread, 0 },
{ CFG_GLOBAL, "thread-group", cfg_parse_thread_group, 0 },
{ CFG_GLOBAL, "thread-groups", cfg_parse_thread_groups, 0 }, { CFG_GLOBAL, "thread-groups", cfg_parse_thread_groups, 0 },
{ 0, NULL, NULL } { 0, NULL, NULL }
}}; }};