Commit 5384a036 authored by Geoff Simmons's avatar Geoff Simmons

trackrdrd: implemented graceful restart

parent ff9e53c1
...@@ -97,12 +97,24 @@ case "$1" in ...@@ -97,12 +97,24 @@ case "$1" in
getstatus_trackrdrd getstatus_trackrdrd
exit 0 exit 0
;; ;;
reload)
check_varnishd
echo -n "Reloading service trackrdrd ... "
checkproc ${TRACKRDRD_BIN}
if [ $? -ne 0 ]; then
echo "FAILED trackrdrd NOT RUNNING"
exit 1
fi
kill -USR1 $(cat ${TRACKRDRD_PID})
getstatus_trackrdrd
exit 0
;;
status) status)
getstatus_trackrdrd getstatus_trackrdrd
exit 0 exit 0
;; ;;
*) *)
echo "Usage: $0 {start|stop|restart|status}" echo "Usage: $0 {start|stop|restart|reload|status}"
exit 1 exit 1
;; ;;
esac esac
......
...@@ -32,7 +32,7 @@ ...@@ -32,7 +32,7 @@
PARENT(SIGTERM, terminate_action); PARENT(SIGTERM, terminate_action);
PARENT(SIGINT, terminate_action); PARENT(SIGINT, terminate_action);
PARENT(SIGUSR1, ignore_action); PARENT(SIGUSR1, restart_action);
PARENT(SIGUSR2, ignore_action); PARENT(SIGUSR2, ignore_action);
PARENT(SIGABRT, stacktrace_action); PARENT(SIGABRT, stacktrace_action);
PARENT(SIGSEGV, stacktrace_action); PARENT(SIGSEGV, stacktrace_action);
......
...@@ -20,9 +20,9 @@ CMD="../trackrdrd -D -f varnish.binlog -l - -d -c test.conf" ...@@ -20,9 +20,9 @@ CMD="../trackrdrd -D -f varnish.binlog -l - -d -c test.conf"
# the second sed removes the user under which the child process runs # the second sed removes the user under which the child process runs
# "Not running as root" filtered so that the test is independent of # "Not running as root" filtered so that the test is independent of
# the user running it # the user running it
CKSUM=$( $CMD | sed -e 's/\(initializing\) \(.*\)/\1/' | sed -e 's/\(, running as\) \(.*\)/\1/' | grep -v 'Not running as root' | cksum) CKSUM=$( $CMD | sed -e 's/\(initializing\) \(.*\)/\1/' | sed -e 's/\(Running as\) \([a-zA-Z0-9]*\)$/\1/' | grep -v 'Not running as root' | cksum)
if [ "$CKSUM" != '1127092118 232241' ]; then if [ "$CKSUM" != '2398306240 232246' ]; then
echo "ERROR: Regression test incorrect cksum: $CKSUM" echo "ERROR: Regression test incorrect cksum: $CKSUM"
exit 1 exit 1
fi fi
......
...@@ -92,12 +92,14 @@ ...@@ -92,12 +92,14 @@
strerror(errno)); \ strerror(errno)); \
} while(0) } while(0)
static void child_main(struct VSM_data *vd, int endless); static void child_main(struct VSM_data *vd, int endless, int readconfig);
static volatile sig_atomic_t term; static volatile sig_atomic_t term, reload;
static struct sigaction terminate_action, dump_action, ignore_action, static struct sigaction terminate_action, dump_action, ignore_action,
stacktrace_action, default_action; stacktrace_action, default_action, restart_action;
static char cli_config_filename[BUFSIZ] = "";
/*--------------------------------------------------------------------*/ /*--------------------------------------------------------------------*/
...@@ -277,6 +279,19 @@ OSL_Track(void *priv, enum VSL_tag_e tag, unsigned fd, unsigned len, ...@@ -277,6 +279,19 @@ OSL_Track(void *priv, enum VSL_tag_e tag, unsigned fd, unsigned len,
/* Handle for the PID file */ /* Handle for the PID file */
struct vpf_fh *pfh = NULL; struct vpf_fh *pfh = NULL;
static void
read_default_config(void) {
if (access(DEFAULT_CONFIG, F_OK) == 0) {
if (access(DEFAULT_CONFIG, R_OK) != 0) {
perror(DEFAULT_CONFIG);
exit(EXIT_FAILURE);
}
printf("Reading config from %s\n", DEFAULT_CONFIG);
if (CONF_ReadFile(DEFAULT_CONFIG) != 0)
exit(EXIT_FAILURE);
}
}
static void static void
assert_failure(const char *func, const char *file, int line, const char *cond, assert_failure(const char *func, const char *file, int line, const char *cond,
int err, int xxx) int err, int xxx)
...@@ -328,6 +343,13 @@ terminate(int sig) ...@@ -328,6 +343,13 @@ terminate(int sig)
term = 1; term = 1;
} }
static void
restart(int sig)
{
(void) sig;
reload = 1;
}
static void static void
stacktrace_abort(int sig) stacktrace_abort(int sig)
{ {
...@@ -357,6 +379,32 @@ parent_shutdown(int status, pid_t child_pid) ...@@ -357,6 +379,32 @@ parent_shutdown(int status, pid_t child_pid)
exit(status); exit(status);
} }
static pid_t
child_restart(pid_t child_pid, struct VSM_data *vd, int endless, int readconfig)
{
int errnum;
if (readconfig) {
LOG_Log(LOG_INFO, "Sending TERM signal to worker process %d",
child_pid);
if ((errnum = kill(child_pid, SIGTERM)) != 0) {
LOG_Log(LOG_ALERT, "Signal TERM delivery to process %d failed: %s",
strerror(errnum));
parent_shutdown(EXIT_FAILURE, 0);
}
}
LOG_Log0(LOG_INFO, "Restarting child process");
child_pid = fork();
if (child_pid == -1) {
LOG_Log(LOG_ALERT, "Cannot fork: %s", strerror(errno));
parent_shutdown(EXIT_FAILURE, child_pid);
}
else if (child_pid == 0)
child_main(vd, endless, readconfig);
return child_pid;
}
static void static void
parent_main(pid_t child_pid, struct VSM_data *vd, int endless) parent_main(pid_t child_pid, struct VSM_data *vd, int endless)
{ {
...@@ -366,6 +414,7 @@ parent_main(pid_t child_pid, struct VSM_data *vd, int endless) ...@@ -366,6 +414,7 @@ parent_main(pid_t child_pid, struct VSM_data *vd, int endless)
LOG_Log0(LOG_INFO, "Management process starting"); LOG_Log0(LOG_INFO, "Management process starting");
term = 0; term = 0;
reload = 0;
/* install signal handlers */ /* install signal handlers */
#define PARENT(SIG,disp) SIGDISP(SIG,disp) #define PARENT(SIG,disp) SIGDISP(SIG,disp)
#define CHILD(SIG,disp) ((void) 0) #define CHILD(SIG,disp) ((void) 0)
...@@ -374,11 +423,16 @@ parent_main(pid_t child_pid, struct VSM_data *vd, int endless) ...@@ -374,11 +423,16 @@ parent_main(pid_t child_pid, struct VSM_data *vd, int endless)
#undef CHILD #undef CHILD
while (!term) { while (!term) {
wpid = waitpid(child_pid, &status, 0); wpid = wait(&status);
if (wpid == -1) { if (wpid == -1) {
if (errno == EINTR) { if (errno == EINTR) {
if (term) if (term)
parent_shutdown(EXIT_SUCCESS, child_pid); parent_shutdown(EXIT_SUCCESS, child_pid);
else if (reload) {
child_pid = child_restart(child_pid, vd, endless, reload);
reload = 0;
continue;
}
else { else {
LOG_Log0(LOG_WARNING, LOG_Log0(LOG_WARNING,
"Interrupted while waiting for worker process, " "Interrupted while waiting for worker process, "
...@@ -386,41 +440,30 @@ parent_main(pid_t child_pid, struct VSM_data *vd, int endless) ...@@ -386,41 +440,30 @@ parent_main(pid_t child_pid, struct VSM_data *vd, int endless)
continue; continue;
} }
} }
LOG_Log(LOG_ERR, "Cannot wait for worker process %d: %s", child_pid, LOG_Log(LOG_ERR, "Cannot wait for worker processes: %s",
strerror(errno)); strerror(errno));
parent_shutdown(EXIT_FAILURE, child_pid); parent_shutdown(EXIT_FAILURE, child_pid);
} }
assert(wpid == child_pid);
AZ(WIFSTOPPED(status)); AZ(WIFSTOPPED(status));
AZ(WIFCONTINUED(status)); AZ(WIFCONTINUED(status));
if (WIFEXITED(status)) if (WIFEXITED(status))
LOG_Log(LOG_INFO, "Worker process %d exited normally", child_pid);
else
LOG_Log(LOG_WARNING, "Worker process %d exited with status %d", LOG_Log(LOG_WARNING, "Worker process %d exited with status %d",
child_pid, WEXITSTATUS(status)); wpid, WEXITSTATUS(status));
if (WIFSIGNALED(status)) if (WIFSIGNALED(status))
LOG_Log(LOG_WARNING, LOG_Log(LOG_WARNING,
"Worker process %d exited due to signal %d (%s)", "Worker process %d exited due to signal %d (%s)",
child_pid, WTERMSIG(status), strsignal(WTERMSIG(status))); wpid, WTERMSIG(status), strsignal(WTERMSIG(status)));
if (wpid != child_pid)
continue;
if (config.restarts && restarts > config.restarts) { if (config.restarts && restarts > config.restarts) {
LOG_Log(LOG_ERR, "Too many restarts: %d", restarts); LOG_Log(LOG_ERR, "Too many restarts: %d", restarts);
parent_shutdown(EXIT_FAILURE, 0); parent_shutdown(EXIT_FAILURE, 0);
} }
LOG_Log0(LOG_INFO, "Restarting child process"); child_pid = child_restart(child_pid, vd, endless, 0);
child_pid = fork(); restarts++;
switch(child_pid) {
case -1:
LOG_Log(LOG_ALERT, "Cannot fork: %s", strerror(errno));
parent_shutdown(EXIT_FAILURE, child_pid);
break;
case 0:
child_main(vd, endless);
break;
default:
restarts++;
}
} }
} }
...@@ -438,18 +481,34 @@ vsl_diag(void *priv, const char *fmt, ...) ...@@ -438,18 +481,34 @@ vsl_diag(void *priv, const char *fmt, ...)
} }
static void static void
child_main(struct VSM_data *vd, int endless) child_main(struct VSM_data *vd, int endless, int readconfig)
{ {
int errnum; int errnum;
const char *errmsg; const char *errmsg;
pthread_t monitor; pthread_t monitor;
struct passwd *pw; struct passwd *pw;
LOG_Log0(LOG_INFO, "Worker process starting");
/* XXX: does not re-configure logging. Feature or bug? */
if (readconfig) {
LOG_Log0(LOG_INFO, "Re-reading config");
CONF_Init();
read_default_config();
if (! EMPTY(cli_config_filename))
LOG_Log(LOG_INFO, "Reading config from %s", cli_config_filename);
/* XXX: CONF_ReadFile prints err messages to stderr */
if (CONF_ReadFile(cli_config_filename) != 0) {
LOG_Log(LOG_ERR, "Error reading config from %s",
cli_config_filename);
exit(EXIT_FAILURE);
}
}
PRIV_Sandbox(); PRIV_Sandbox();
pw = getpwuid(geteuid()); pw = getpwuid(geteuid());
AN(pw); AN(pw);
LOG_Log(LOG_INFO, "Running as %s", pw->pw_name);
LOG_Log(LOG_INFO, "Worker process starting, running as %s", pw->pw_name);
/* install signal handlers */ /* install signal handlers */
#define CHILD(SIG,disp) SIGDISP(SIG,disp) #define CHILD(SIG,disp) SIGDISP(SIG,disp)
...@@ -457,7 +516,7 @@ child_main(struct VSM_data *vd, int endless) ...@@ -457,7 +516,7 @@ child_main(struct VSM_data *vd, int endless)
#include "signals.h" #include "signals.h"
#undef PARENT #undef PARENT
#undef CHILD #undef CHILD
if (DATA_Init() != 0) { if (DATA_Init() != 0) {
LOG_Log(LOG_ERR, "Cannot init data table: %s", strerror(errno)); LOG_Log(LOG_ERR, "Cannot init data table: %s", strerror(errno));
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
...@@ -548,16 +607,7 @@ main(int argc, char * const *argv) ...@@ -548,16 +607,7 @@ main(int argc, char * const *argv)
VSL_Setup(vd); VSL_Setup(vd);
CONF_Init(); CONF_Init();
read_default_config();
if (access(DEFAULT_CONFIG, F_OK) == 0) {
if (access(DEFAULT_CONFIG, R_OK) != 0) {
perror(DEFAULT_CONFIG);
exit(EXIT_FAILURE);
}
printf("Reading config from %s\n", DEFAULT_CONFIG);
if (CONF_ReadFile(DEFAULT_CONFIG) != 0)
exit(EXIT_FAILURE);
}
while ((c = getopt(argc, argv, "u:P:Vn:hl:df:y:c:D")) != -1) { while ((c = getopt(argc, argv, "u:P:Vn:hl:df:y:c:D")) != -1) {
switch (c) { switch (c) {
...@@ -602,6 +652,7 @@ main(int argc, char * const *argv) ...@@ -602,6 +652,7 @@ main(int argc, char * const *argv)
usage(EXIT_FAILURE); usage(EXIT_FAILURE);
if (c_arg) { if (c_arg) {
strcpy(cli_config_filename, c_arg);
printf("Reading config from %s\n", c_arg); printf("Reading config from %s\n", c_arg);
if (CONF_ReadFile(c_arg) != 0) if (CONF_ReadFile(c_arg) != 0)
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
...@@ -615,7 +666,7 @@ main(int argc, char * const *argv) ...@@ -615,7 +666,7 @@ main(int argc, char * const *argv)
if (u_arg) { if (u_arg) {
err = CONF_Add("user", u_arg); err = CONF_Add("user", u_arg);
if (err) { if (err) {
LOG_Log(LOG_ALERT, "Unknown user: %s", u_arg); fprintf(stderr, "Unknown user: %s\n", u_arg);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
} }
...@@ -623,7 +674,7 @@ main(int argc, char * const *argv) ...@@ -623,7 +674,7 @@ main(int argc, char * const *argv)
if (y_arg) { if (y_arg) {
err = CONF_Add("syslog.facility", y_arg); err = CONF_Add("syslog.facility", y_arg);
if (err) { if (err) {
LOG_Log(LOG_ALERT, "Unknown syslog facility: %s", y_arg); fprintf(stderr, "Unknown syslog facility: %s\n", y_arg);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
} }
...@@ -683,6 +734,10 @@ main(int argc, char * const *argv) ...@@ -683,6 +734,10 @@ main(int argc, char * const *argv)
AZ(sigemptyset(&dump_action.sa_mask)); AZ(sigemptyset(&dump_action.sa_mask));
dump_action.sa_flags |= SA_RESTART; dump_action.sa_flags |= SA_RESTART;
restart_action.sa_handler = restart;
AZ(sigemptyset(&restart_action.sa_mask));
restart_action.sa_flags &= ~SA_RESTART;
stacktrace_action.sa_handler = stacktrace_abort; stacktrace_action.sa_handler = stacktrace_abort;
ignore_action.sa_handler = SIG_IGN; ignore_action.sa_handler = SIG_IGN;
...@@ -695,10 +750,10 @@ main(int argc, char * const *argv) ...@@ -695,10 +750,10 @@ main(int argc, char * const *argv)
LOG_Log(LOG_ALERT, LOG_Log(LOG_ALERT,
"Cannot fork (%s), running as single process", "Cannot fork (%s), running as single process",
strerror(errno)); strerror(errno));
child_main(vd, endless); child_main(vd, endless, 0);
break; break;
case 0: case 0:
child_main(vd, endless); child_main(vd, endless, 0);
break; break;
default: default:
parent_main(child_pid, vd, endless); parent_main(child_pid, vd, endless);
...@@ -707,6 +762,6 @@ main(int argc, char * const *argv) ...@@ -707,6 +762,6 @@ main(int argc, char * const *argv)
} }
else { else {
LOG_Log0(LOG_INFO, "Running as non-demon single process"); LOG_Log0(LOG_INFO, "Running as non-demon single process");
child_main(vd, endless); child_main(vd, endless, 0);
} }
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment