]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: mworker-prog: implements 'option start-on-reload'
authorWilliam Lallemand <wlallemand@haproxy.com>
Fri, 12 Apr 2019 14:09:22 +0000 (16:09 +0200)
committerWilly Tarreau <w@1wt.eu>
Tue, 16 Apr 2019 11:26:43 +0000 (13:26 +0200)
This option is already the default, but its opposite 'no option
start-on-reload' allows the master to keep a previous instance of a
program and don't start a new one upon a reload.

The old program will then appear as a current one in "show proc" and
could also trigger an exit-on-failure upon a segfault.

include/types/global.h
src/mworker-prog.c

index 607ba2d96f11091c04253fb203066ebcadd77c45..3216b5b168624e6673481830adeb7f5a676fd890 100644 (file)
@@ -187,6 +187,8 @@ struct global {
 #define PROC_O_TYPE_PROG             0x00000004
 /* 0x00000008 unused */
 #define PROC_O_LEAVING               0x00000010  /* this process should be leaving */
+/* 0x00000020 to 0x00000080 unused */
+#define PROC_O_START_RELOAD          0x00000100  /* Start the process even if the master was re-executed */
 
 /*
  * Structure used to describe the processes in master worker mode
index 340f8883de6745e1de91a00cca6a493cc9623cf5..8eefd85bad8e968fbc9e490a838aa73f107c106a 100644 (file)
@@ -35,13 +35,63 @@ int mworker_ext_launch_all()
 {
        int ret;
        struct mworker_proc *child;
+       struct mworker_proc *tmp;
+       int reexec = 0;
 
        if (!use_program)
                return 0;
 
+       reexec = getenv("HAPROXY_MWORKER_REEXEC") ? 1 : 0;
+
        /* find the right mworker_proc */
-       list_for_each_entry(child, &proc_list, list) {
+       list_for_each_entry_safe(child, tmp, &proc_list, list) {
                if (child->reloads == 0 && child->type == 'e') {
+
+                       if (reexec && (!(child->options & PROC_O_START_RELOAD))) {
+                               struct mworker_proc *old_child;
+
+                               /*
+                                * This is a reload and we don't want to fork a
+                                * new program so have to remove the entry in
+                                * the list.
+                                *
+                                * But before that, we need to mark the
+                                * previous program as not leaving, if we find one.
+                                */
+
+                               list_for_each_entry(old_child, &proc_list, list) {
+                                       if (old_child->type != 'e' || (!(old_child->options & PROC_O_LEAVING)))
+                                               continue;
+
+                                       if (!strcmp(old_child->id, child->id))
+                                               old_child->options &= ~PROC_O_LEAVING;
+                               }
+
+
+                               LIST_DEL(&child->list);
+                               if (child->command) {
+                                       int i;
+
+                                       for (i = 0; child->command[i]; i++) {
+                                               if (child->command[i]) {
+                                                       free(child->command[i]);
+                                                       child->command[i] = NULL;
+                                               }
+                                       }
+                                       free(child->command);
+                                       child->command = NULL;
+                               }
+                               if (child->id) {
+                                       free(child->id);
+                                       child->id = NULL;
+                               }
+
+                               free(child);
+                               child = NULL;
+
+                               continue;
+                       }
+
                        child->timestamp = now.tv_sec;
 
                        ret = fork();
@@ -109,6 +159,7 @@ int cfg_parse_program(const char *file, int linenum, char **args, int kwm)
                ext_child->timestamp = -1;
                ext_child->ipc_fd[0] = -1;
                ext_child->ipc_fd[1] = -1;
+               ext_child->options |= PROC_O_START_RELOAD; /* restart the programs by default */
                LIST_INIT(&ext_child->list);
 
                list_for_each_entry(child, &proc_list, list) {
@@ -162,6 +213,29 @@ int cfg_parse_program(const char *file, int linenum, char **args, int kwm)
                }
                ext_child->command[i] = NULL;
 
+       } else if (!strcmp(args[0], "option")) {
+
+               if (*(args[1]) == '\0') {
+                       ha_alert("parsing [%s:%d]: '%s' expects an option name.\n",
+                                file, linenum, args[0]);
+                       err_code |= ERR_ALERT | ERR_FATAL;
+                       goto error;
+               }
+
+               if (strcmp(args[1], "start-on-reload") == 0) {
+                       if (alertif_too_many_args_idx(0, 1, file, linenum, args, &err_code))
+                               goto error;
+                       if (kwm == KWM_STD)
+                               ext_child->options |= PROC_O_START_RELOAD;
+                       else if (kwm == KWM_NO)
+                               ext_child->options &= ~PROC_O_START_RELOAD;
+                       goto out;
+
+               } else {
+                       ha_alert("parsing [%s:%d] : unknown option '%s'.\n", file, linenum, args[1]);
+                       err_code |= ERR_ALERT | ERR_FATAL;
+                       goto error;
+               }
        } else {
                ha_alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "program");
                err_code |= ERR_ALERT | ERR_FATAL;
@@ -194,6 +268,7 @@ error:
        free(ext_child);
        ext_child = NULL;
 
+out:
        return err_code;
 
 }