]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: global: add a new "thread-group" directive
authorWilly Tarreau <w@1wt.eu>
Mon, 27 Sep 2021 11:55:10 +0000 (13:55 +0200)
committerWilly Tarreau <w@1wt.eu>
Fri, 8 Oct 2021 15:22:26 +0000 (17:22 +0200)
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.

doc/configuration.txt
include/haproxy/tinfo-t.h
src/thread.c

index bc1e0a25f00129125e6fe3602fd0119a6b9bafb8..830aee9e65e6ffdcad40cf116e6237337432aebd 100644 (file)
@@ -2070,6 +2070,17 @@ stats maxconn <connections>
   By default, the stats socket is limited to 10 concurrent connections. It is
   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>
   This setting is only available when support for threads was built in. It
   makes HAProxy split its threads into <number> independent groups. At the
index 963d0a937d75b51ed1f7583eb9a59cb8e73799e0..e2779ab1097af3a32686ab12a1de7ea81812815e 100644 (file)
@@ -58,6 +58,8 @@ struct tgroup_info {
  * thread-local "ti" pointer.
  */
 struct thread_info {
+       const struct tgroup_info *tg;     /* config of the thread-group this thread belongs to */
+
        /* pad to cache line (64B) */
        char __pad[0];                    /* unused except to check remaining room */
        char __end[0] __attribute__((aligned(64)));
index 5788303d0a6ca2ffeb1ae0c40f9ac99ed9361623..7374a8eede9044a3d662847cd4393d0422490fd7 100644 (file)
@@ -1042,6 +1042,96 @@ static int cfg_parse_nbthread(char **args, int section_type, struct proxy *curpx
        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
  * 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 */
 static struct cfg_kw_list cfg_kws = {ILH, {
        { 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 },
        { 0, NULL, NULL }
 }};