2006-12-31 01:02:27 +01:00
|
|
|
/* Copyright (C) 2003-2006 MySQL AB
|
2003-08-16 21:44:24 +04:00
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
2006-12-23 20:17:15 +01:00
|
|
|
the Free Software Foundation; version 2 of the License.
|
2003-08-16 21:44:24 +04:00
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program; if not, write to the Free Software
|
|
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
|
|
|
|
2005-03-22 02:04:14 +03:00
|
|
|
#include <my_global.h>
|
2004-10-23 11:32:52 +04:00
|
|
|
#include "manager.h"
|
2005-03-22 02:04:14 +03:00
|
|
|
|
2004-10-23 11:32:52 +04:00
|
|
|
#include "options.h"
|
|
|
|
#include "log.h"
|
|
|
|
|
2003-08-16 21:44:24 +04:00
|
|
|
#include <my_sys.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <signal.h>
|
2005-07-20 10:55:40 -05:00
|
|
|
#ifndef __WIN__
|
2005-02-05 14:04:49 +03:00
|
|
|
#include <pwd.h>
|
|
|
|
#include <grp.h>
|
2003-08-16 21:44:24 +04:00
|
|
|
#include <sys/wait.h>
|
2005-07-20 10:55:40 -05:00
|
|
|
#endif
|
2004-10-12 16:35:15 +04:00
|
|
|
#include <sys/types.h>
|
2004-10-23 11:32:52 +04:00
|
|
|
#include <sys/stat.h>
|
2005-07-20 10:55:40 -05:00
|
|
|
#ifdef __WIN__
|
|
|
|
#include "windowsservice.h"
|
|
|
|
#endif
|
2003-08-16 21:44:24 +04:00
|
|
|
|
|
|
|
/*
|
2004-10-23 11:32:52 +04:00
|
|
|
Few notes about Instance Manager architecture:
|
2003-08-16 21:44:24 +04:00
|
|
|
Instance Manager consisits of two processes: the angel process, and the
|
|
|
|
instance manager process. Responsibilities of the angel process is to
|
|
|
|
monitor the instance manager process, and restart it in case of
|
|
|
|
failure/shutdown. The angel process is started only if startup option
|
|
|
|
'--run-as-service' is provided.
|
|
|
|
The Instance Manager process consists of several
|
|
|
|
subsystems (thread sets):
|
2004-10-23 11:32:52 +04:00
|
|
|
- the signal handling thread: it's responsibilities are to handle
|
2003-08-16 21:44:24 +04:00
|
|
|
user signals and propogate them to the other threads. All other threads
|
2004-10-23 11:32:52 +04:00
|
|
|
are accounted in the signal handler thread Thread Registry.
|
|
|
|
- the listener: listens all sockets. There is a listening
|
2003-08-16 21:44:24 +04:00
|
|
|
socket for each (mysql, http, snmp, rendezvous (?)) subsystem.
|
|
|
|
- mysql subsystem: Instance Manager acts like an ordinary MySQL Server,
|
2004-10-23 11:32:52 +04:00
|
|
|
but with very restricted command set. Each MySQL client connection is
|
2003-08-16 21:44:24 +04:00
|
|
|
handled in a separate thread. All MySQL client connections threads
|
|
|
|
constitute mysql subsystem.
|
2004-10-23 11:32:52 +04:00
|
|
|
- http subsystem: it is also possible to talk with Instance Manager via
|
2003-08-16 21:44:24 +04:00
|
|
|
http. One thread per http connection is used. Threads are pooled.
|
|
|
|
- 'snmp' connections (FIXME: I know nothing about it yet)
|
2004-10-23 11:32:52 +04:00
|
|
|
- rendezvous threads
|
2003-08-16 21:44:24 +04:00
|
|
|
*/
|
|
|
|
|
|
|
|
static void init_environment(char *progname);
|
2005-07-20 10:55:40 -05:00
|
|
|
#ifndef __WIN__
|
2003-08-16 21:44:24 +04:00
|
|
|
static void daemonize(const char *log_file_name);
|
|
|
|
static void angel(const Options &options);
|
2005-02-05 14:04:49 +03:00
|
|
|
static struct passwd *check_user(const char *user);
|
|
|
|
static int set_user(const char *user, struct passwd *user_info);
|
2005-07-20 10:55:40 -05:00
|
|
|
#else
|
|
|
|
int HandleServiceOptions(Options options);
|
|
|
|
#endif
|
2003-08-16 21:44:24 +04:00
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
main, entry point
|
|
|
|
- init environment
|
|
|
|
- handle options
|
|
|
|
- daemonize and run angel process (if necessary)
|
|
|
|
- run manager process
|
|
|
|
*/
|
|
|
|
|
|
|
|
int main(int argc, char *argv[])
|
|
|
|
{
|
2005-08-09 07:57:37 -06:00
|
|
|
int return_value= 1;
|
2003-08-16 21:44:24 +04:00
|
|
|
init_environment(argv[0]);
|
|
|
|
Options options;
|
2005-02-05 14:04:49 +03:00
|
|
|
|
2005-02-15 04:38:33 +03:00
|
|
|
if (options.load(argc, argv))
|
|
|
|
goto err;
|
2005-02-05 14:04:49 +03:00
|
|
|
|
2005-07-20 10:55:40 -05:00
|
|
|
#ifndef __WIN__
|
2006-02-10 02:15:55 +03:00
|
|
|
struct passwd *user_info;
|
|
|
|
|
2005-02-05 14:04:49 +03:00
|
|
|
if ((user_info= check_user(options.user)))
|
|
|
|
{
|
|
|
|
if (set_user(options.user, user_info))
|
2005-07-21 14:21:23 +04:00
|
|
|
goto err;
|
2005-02-05 14:04:49 +03:00
|
|
|
}
|
|
|
|
|
2003-08-16 21:44:24 +04:00
|
|
|
if (options.run_as_service)
|
|
|
|
{
|
2004-10-23 11:32:52 +04:00
|
|
|
/* forks, and returns only in child */
|
2003-08-16 21:44:24 +04:00
|
|
|
daemonize(options.log_file_name);
|
2004-10-23 11:32:52 +04:00
|
|
|
/* forks again, and returns only in child: parent becomes angel */
|
2003-08-16 21:44:24 +04:00
|
|
|
angel(options);
|
|
|
|
}
|
2005-07-20 10:55:40 -05:00
|
|
|
#else
|
2005-09-13 14:53:19 -05:00
|
|
|
if (!options.stand_alone)
|
|
|
|
{
|
|
|
|
if (HandleServiceOptions(options))
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
else
|
2005-07-20 10:55:40 -05:00
|
|
|
#endif
|
|
|
|
|
Fix for BUG#24415: Instance manager test im_daemon_life_cycle fails randomly.
The cause of im_daemon_life_cycle.imtest random failures was the following
behaviour of some implementations of LINUX threads: let's suppose that a
process has several threads (in LINUX threads, there is a separate process for
each thread). When the main process gets killed, the parent receives SIGCHLD
before all threads (child processes) die. In other words, the parent receives
SIGCHLD, when its child is not completely dead.
In terms of IM, that means that IM-angel receives SIGCHLD when IM-main is not dead
and still holds some resources. After receiving SIGCHLD, IM-angel restarts
IM-main, but IM-main failed to initialize, because previous instance (copy) of
IM-main still holds server socket (TCP-port).
Another problem here was that IM-angel restarted IM-main only if it was killed
by signal. If it exited with error, IM-angel thought it's intended / graceful
shutdown and exited itself.
So, when the second instance of IM-main failed to initialize, IM-angel thought
it's intended shutdown and quit.
The fix is
1. to change IM-angel so that it restarts IM-main if it exited with error code;
2. to change IM-main so that it returns proper exit code in case of failure.
mysql-test/t/disabled.def:
Enable im_daemon_life_cycle.
server-tools/instance-manager/listener.cc:
Set error status if Listener failed to initialize.
server-tools/instance-manager/manager.cc:
Return exit code from the manager.
server-tools/instance-manager/manager.h:
Return exit code from the manager.
server-tools/instance-manager/mysqlmanager.cc:
1. Restart IM-main if exit code is not EXIT_SUCCESS (0).
2. Log IM-main exit code in case of failure.
server-tools/instance-manager/thread_registry.cc:
Add support for exit code.
server-tools/instance-manager/thread_registry.h:
Add support for exit code.
2007-02-20 22:31:50 +03:00
|
|
|
return_value= manager(options);
|
2005-08-09 07:57:37 -06:00
|
|
|
|
2005-02-15 04:38:33 +03:00
|
|
|
err:
|
2005-08-09 07:57:37 -06:00
|
|
|
options.cleanup();
|
2005-02-15 04:38:33 +03:00
|
|
|
my_end(0);
|
2005-08-09 07:57:37 -06:00
|
|
|
return return_value;
|
2003-08-16 21:44:24 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/******************* Auxilary functions implementation **********************/
|
|
|
|
|
2005-07-20 10:55:40 -05:00
|
|
|
#if !defined(__WIN__) && !defined(OS2) && !defined(__NETWARE__)
|
2005-02-05 14:04:49 +03:00
|
|
|
/* Change to run as another user if started with --user */
|
|
|
|
|
|
|
|
static struct passwd *check_user(const char *user)
|
|
|
|
{
|
|
|
|
struct passwd *user_info;
|
|
|
|
uid_t user_id= geteuid();
|
|
|
|
|
|
|
|
/* Don't bother if we aren't superuser */
|
|
|
|
if (user_id)
|
|
|
|
{
|
|
|
|
if (user)
|
|
|
|
{
|
|
|
|
/* Don't give a warning, if real user is same as given with --user */
|
|
|
|
user_info= getpwnam(user);
|
|
|
|
if ((!user_info || user_id != user_info->pw_uid))
|
|
|
|
log_info("One can only use the --user switch if running as root\n");
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
if (!user)
|
|
|
|
{
|
|
|
|
log_info("You are running mysqlmanager as root! This might introduce security problems. It is safer to use --user option istead.\n");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
if (!strcmp(user, "root"))
|
|
|
|
return NULL; /* Avoid problem with dynamic libraries */
|
|
|
|
if (!(user_info= getpwnam(user)))
|
|
|
|
{
|
|
|
|
/* Allow a numeric uid to be used */
|
|
|
|
const char *pos;
|
2005-05-16 01:54:02 +04:00
|
|
|
for (pos= user; my_isdigit(default_charset_info, *pos); pos++)
|
|
|
|
{}
|
2005-02-05 14:04:49 +03:00
|
|
|
if (*pos) /* Not numeric id */
|
|
|
|
goto err;
|
|
|
|
if (!(user_info= getpwuid(atoi(user))))
|
|
|
|
goto err;
|
|
|
|
else
|
|
|
|
return user_info;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return user_info;
|
|
|
|
|
|
|
|
err:
|
|
|
|
log_error("Fatal error: Can't change to run as user '%s' ; Please check that the user exists!\n", user);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int set_user(const char *user, struct passwd *user_info)
|
|
|
|
{
|
|
|
|
DBUG_ASSERT(user_info);
|
|
|
|
#ifdef HAVE_INITGROUPS
|
|
|
|
initgroups((char*) user,user_info->pw_gid);
|
|
|
|
#endif
|
|
|
|
if (setgid(user_info->pw_gid) == -1)
|
|
|
|
{
|
|
|
|
log_error("setgid() failed");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
if (setuid(user_info->pw_uid) == -1)
|
|
|
|
{
|
|
|
|
log_error("setuid() failed");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2005-07-20 10:55:40 -05:00
|
|
|
#endif
|
2005-02-05 14:04:49 +03:00
|
|
|
|
2003-08-16 21:44:24 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
Init environment, common for daemon and non-daemon
|
|
|
|
*/
|
|
|
|
|
|
|
|
static void init_environment(char *progname)
|
|
|
|
{
|
|
|
|
MY_INIT(progname);
|
|
|
|
log_init();
|
|
|
|
umask(0117);
|
2007-02-22 16:59:57 +02:00
|
|
|
srand((uint) time(0));
|
2003-08-16 21:44:24 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-07-20 10:55:40 -05:00
|
|
|
#ifndef __WIN__
|
2003-08-16 21:44:24 +04:00
|
|
|
/*
|
|
|
|
Become a UNIX service
|
|
|
|
SYNOPSYS
|
|
|
|
daemonize()
|
|
|
|
*/
|
|
|
|
|
|
|
|
static void daemonize(const char *log_file_name)
|
|
|
|
{
|
|
|
|
pid_t pid= fork();
|
|
|
|
switch (pid) {
|
|
|
|
case -1: // parent, fork error
|
|
|
|
die("daemonize(): fork failed, %s", strerror(errno));
|
|
|
|
case 0: // child, fork ok
|
|
|
|
int fd;
|
|
|
|
/*
|
2003-08-19 19:55:20 +04:00
|
|
|
Become a session leader: setsid must succeed because child is
|
2004-10-23 11:32:52 +04:00
|
|
|
guaranteed not to be a process group leader (it belongs to the
|
|
|
|
process group of the parent.)
|
2003-08-16 21:44:24 +04:00
|
|
|
The goal is not to have a controlling terminal.
|
|
|
|
*/
|
2003-08-19 19:55:20 +04:00
|
|
|
setsid();
|
2003-08-16 21:44:24 +04:00
|
|
|
/*
|
|
|
|
As we now don't have a controlling terminal we will not receive
|
|
|
|
tty-related signals - no need to ignore them.
|
|
|
|
*/
|
|
|
|
|
|
|
|
close(STDIN_FILENO);
|
|
|
|
|
2004-10-23 11:32:52 +04:00
|
|
|
fd= open(log_file_name, O_WRONLY | O_CREAT | O_APPEND | O_NOCTTY,
|
2003-08-16 21:44:24 +04:00
|
|
|
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
|
|
|
|
if (fd < 0)
|
|
|
|
die("daemonize(): failed to open log file %s, %s", log_file_name,
|
|
|
|
strerror(errno));
|
|
|
|
dup2(fd, STDOUT_FILENO);
|
|
|
|
dup2(fd, STDERR_FILENO);
|
|
|
|
if (fd != STDOUT_FILENO && fd != STDERR_FILENO)
|
|
|
|
close(fd);
|
|
|
|
|
|
|
|
/* TODO: chroot() and/or chdir() here */
|
|
|
|
break;
|
2004-10-23 11:32:52 +04:00
|
|
|
default:
|
2003-08-16 21:44:24 +04:00
|
|
|
/* successfully exit from parent */
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
enum { CHILD_OK= 0, CHILD_NEED_RESPAWN, CHILD_EXIT_ANGEL };
|
|
|
|
|
|
|
|
static volatile sig_atomic_t child_status= CHILD_OK;
|
Fix for BUG#24415: Instance manager test im_daemon_life_cycle fails randomly.
The cause of im_daemon_life_cycle.imtest random failures was the following
behaviour of some implementations of LINUX threads: let's suppose that a
process has several threads (in LINUX threads, there is a separate process for
each thread). When the main process gets killed, the parent receives SIGCHLD
before all threads (child processes) die. In other words, the parent receives
SIGCHLD, when its child is not completely dead.
In terms of IM, that means that IM-angel receives SIGCHLD when IM-main is not dead
and still holds some resources. After receiving SIGCHLD, IM-angel restarts
IM-main, but IM-main failed to initialize, because previous instance (copy) of
IM-main still holds server socket (TCP-port).
Another problem here was that IM-angel restarted IM-main only if it was killed
by signal. If it exited with error, IM-angel thought it's intended / graceful
shutdown and exited itself.
So, when the second instance of IM-main failed to initialize, IM-angel thought
it's intended shutdown and quit.
The fix is
1. to change IM-angel so that it restarts IM-main if it exited with error code;
2. to change IM-main so that it returns proper exit code in case of failure.
mysql-test/t/disabled.def:
Enable im_daemon_life_cycle.
server-tools/instance-manager/listener.cc:
Set error status if Listener failed to initialize.
server-tools/instance-manager/manager.cc:
Return exit code from the manager.
server-tools/instance-manager/manager.h:
Return exit code from the manager.
server-tools/instance-manager/mysqlmanager.cc:
1. Restart IM-main if exit code is not EXIT_SUCCESS (0).
2. Log IM-main exit code in case of failure.
server-tools/instance-manager/thread_registry.cc:
Add support for exit code.
server-tools/instance-manager/thread_registry.h:
Add support for exit code.
2007-02-20 22:31:50 +03:00
|
|
|
static volatile sig_atomic_t child_exit_code= 0;
|
2003-08-16 21:44:24 +04:00
|
|
|
|
2004-10-23 11:32:52 +04:00
|
|
|
/*
|
Fix for BUG#24415: Instance manager test im_daemon_life_cycle fails randomly.
The cause of im_daemon_life_cycle.imtest random failures was the following
behaviour of some implementations of LINUX threads: let's suppose that a
process has several threads (in LINUX threads, there is a separate process for
each thread). When the main process gets killed, the parent receives SIGCHLD
before all threads (child processes) die. In other words, the parent receives
SIGCHLD, when its child is not completely dead.
In terms of IM, that means that IM-angel receives SIGCHLD when IM-main is not dead
and still holds some resources. After receiving SIGCHLD, IM-angel restarts
IM-main, but IM-main failed to initialize, because previous instance (copy) of
IM-main still holds server socket (TCP-port).
Another problem here was that IM-angel restarted IM-main only if it was killed
by signal. If it exited with error, IM-angel thought it's intended / graceful
shutdown and exited itself.
So, when the second instance of IM-main failed to initialize, IM-angel thought
it's intended shutdown and quit.
The fix is
1. to change IM-angel so that it restarts IM-main if it exited with error code;
2. to change IM-main so that it returns proper exit code in case of failure.
mysql-test/t/disabled.def:
Enable im_daemon_life_cycle.
server-tools/instance-manager/listener.cc:
Set error status if Listener failed to initialize.
server-tools/instance-manager/manager.cc:
Return exit code from the manager.
server-tools/instance-manager/manager.h:
Return exit code from the manager.
server-tools/instance-manager/mysqlmanager.cc:
1. Restart IM-main if exit code is not EXIT_SUCCESS (0).
2. Log IM-main exit code in case of failure.
server-tools/instance-manager/thread_registry.cc:
Add support for exit code.
server-tools/instance-manager/thread_registry.h:
Add support for exit code.
2007-02-20 22:31:50 +03:00
|
|
|
Signal handler for SIGCHLD: reap child, analyze child exit code, and set
|
2003-08-16 21:44:24 +04:00
|
|
|
child_status appropriately.
|
|
|
|
*/
|
|
|
|
|
|
|
|
void reap_child(int __attribute__((unused)) signo)
|
2004-10-23 11:32:52 +04:00
|
|
|
{
|
Fix for BUG#24415: Instance manager test im_daemon_life_cycle fails randomly.
The cause of im_daemon_life_cycle.imtest random failures was the following
behaviour of some implementations of LINUX threads: let's suppose that a
process has several threads (in LINUX threads, there is a separate process for
each thread). When the main process gets killed, the parent receives SIGCHLD
before all threads (child processes) die. In other words, the parent receives
SIGCHLD, when its child is not completely dead.
In terms of IM, that means that IM-angel receives SIGCHLD when IM-main is not dead
and still holds some resources. After receiving SIGCHLD, IM-angel restarts
IM-main, but IM-main failed to initialize, because previous instance (copy) of
IM-main still holds server socket (TCP-port).
Another problem here was that IM-angel restarted IM-main only if it was killed
by signal. If it exited with error, IM-angel thought it's intended / graceful
shutdown and exited itself.
So, when the second instance of IM-main failed to initialize, IM-angel thought
it's intended shutdown and quit.
The fix is
1. to change IM-angel so that it restarts IM-main if it exited with error code;
2. to change IM-main so that it returns proper exit code in case of failure.
mysql-test/t/disabled.def:
Enable im_daemon_life_cycle.
server-tools/instance-manager/listener.cc:
Set error status if Listener failed to initialize.
server-tools/instance-manager/manager.cc:
Return exit code from the manager.
server-tools/instance-manager/manager.h:
Return exit code from the manager.
server-tools/instance-manager/mysqlmanager.cc:
1. Restart IM-main if exit code is not EXIT_SUCCESS (0).
2. Log IM-main exit code in case of failure.
server-tools/instance-manager/thread_registry.cc:
Add support for exit code.
server-tools/instance-manager/thread_registry.h:
Add support for exit code.
2007-02-20 22:31:50 +03:00
|
|
|
/* NOTE: As we have only one child, no need to cycle waitpid(). */
|
|
|
|
|
|
|
|
int exit_code;
|
|
|
|
|
|
|
|
if (waitpid(0, &exit_code, WNOHANG) > 0)
|
2003-08-16 21:44:24 +04:00
|
|
|
{
|
Fix for BUG#24415: Instance manager test im_daemon_life_cycle fails randomly.
The cause of im_daemon_life_cycle.imtest random failures was the following
behaviour of some implementations of LINUX threads: let's suppose that a
process has several threads (in LINUX threads, there is a separate process for
each thread). When the main process gets killed, the parent receives SIGCHLD
before all threads (child processes) die. In other words, the parent receives
SIGCHLD, when its child is not completely dead.
In terms of IM, that means that IM-angel receives SIGCHLD when IM-main is not dead
and still holds some resources. After receiving SIGCHLD, IM-angel restarts
IM-main, but IM-main failed to initialize, because previous instance (copy) of
IM-main still holds server socket (TCP-port).
Another problem here was that IM-angel restarted IM-main only if it was killed
by signal. If it exited with error, IM-angel thought it's intended / graceful
shutdown and exited itself.
So, when the second instance of IM-main failed to initialize, IM-angel thought
it's intended shutdown and quit.
The fix is
1. to change IM-angel so that it restarts IM-main if it exited with error code;
2. to change IM-main so that it returns proper exit code in case of failure.
mysql-test/t/disabled.def:
Enable im_daemon_life_cycle.
server-tools/instance-manager/listener.cc:
Set error status if Listener failed to initialize.
server-tools/instance-manager/manager.cc:
Return exit code from the manager.
server-tools/instance-manager/manager.h:
Return exit code from the manager.
server-tools/instance-manager/mysqlmanager.cc:
1. Restart IM-main if exit code is not EXIT_SUCCESS (0).
2. Log IM-main exit code in case of failure.
server-tools/instance-manager/thread_registry.cc:
Add support for exit code.
server-tools/instance-manager/thread_registry.h:
Add support for exit code.
2007-02-20 22:31:50 +03:00
|
|
|
child_exit_code= exit_code;
|
|
|
|
child_status= exit_code ? CHILD_NEED_RESPAWN : CHILD_EXIT_ANGEL;
|
2003-08-16 21:44:24 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-10-23 11:32:52 +04:00
|
|
|
static volatile sig_atomic_t is_terminated= 0;
|
2003-08-16 21:44:24 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
Signal handler for terminate signals - SIGTERM, SIGHUP, SIGINT.
|
|
|
|
Set termination status and return.
|
|
|
|
(q) do we need to handle SIGQUIT?
|
|
|
|
*/
|
|
|
|
|
|
|
|
void terminate(int signo)
|
|
|
|
{
|
2004-11-15 14:53:30 +03:00
|
|
|
is_terminated= signo;
|
2003-08-16 21:44:24 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
Fork a child and monitor it.
|
|
|
|
User can explicitly kill the angel process with SIGTERM/SIGHUP/SIGINT.
|
|
|
|
Angel process will exit silently if mysqlmanager exits normally.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static void angel(const Options &options)
|
|
|
|
{
|
|
|
|
/* install signal handlers */
|
|
|
|
sigset_t zeromask; // to sigsuspend in parent
|
|
|
|
struct sigaction sa_chld, sa_term;
|
|
|
|
struct sigaction sa_chld_out, sa_term_out, sa_int_out, sa_hup_out;
|
2003-08-19 19:55:20 +04:00
|
|
|
|
|
|
|
sigemptyset(&zeromask);
|
|
|
|
sigemptyset(&sa_chld.sa_mask);
|
|
|
|
sigemptyset(&sa_term.sa_mask);
|
|
|
|
|
2003-08-16 21:44:24 +04:00
|
|
|
sa_chld.sa_handler= reap_child;
|
|
|
|
sa_chld.sa_flags= SA_NOCLDSTOP;
|
|
|
|
sa_term.sa_handler= terminate;
|
|
|
|
sa_term.sa_flags= 0;
|
2003-08-19 19:55:20 +04:00
|
|
|
|
|
|
|
/* sigaction can fail only on wrong arguments */
|
|
|
|
sigaction(SIGCHLD, &sa_chld, &sa_chld_out);
|
|
|
|
sigaction(SIGTERM, &sa_term, &sa_term_out);
|
|
|
|
sigaction(SIGINT, &sa_term, &sa_int_out);
|
|
|
|
sigaction(SIGHUP, &sa_term, &sa_hup_out);
|
2003-08-16 21:44:24 +04:00
|
|
|
|
|
|
|
/* spawn a child */
|
|
|
|
spawn:
|
|
|
|
pid_t pid= fork();
|
|
|
|
switch (pid) {
|
|
|
|
case -1:
|
2004-10-23 11:32:52 +04:00
|
|
|
die("angel(): fork failed, %s", strerror(errno));
|
2003-08-16 21:44:24 +04:00
|
|
|
case 0: // child, success
|
|
|
|
/*
|
|
|
|
restore default actions for signals to let the manager work with
|
|
|
|
signals as he wishes
|
2004-10-23 11:32:52 +04:00
|
|
|
*/
|
2003-08-19 19:55:20 +04:00
|
|
|
sigaction(SIGCHLD, &sa_chld_out, 0);
|
|
|
|
sigaction(SIGTERM, &sa_term_out, 0);
|
|
|
|
sigaction(SIGINT, &sa_int_out, 0);
|
|
|
|
sigaction(SIGHUP, &sa_hup_out, 0);
|
2004-10-23 11:32:52 +04:00
|
|
|
/* Here we return to main, and fall into manager */
|
|
|
|
break;
|
2003-08-16 21:44:24 +04:00
|
|
|
default: // parent, success
|
2006-05-06 13:57:56 +04:00
|
|
|
pid= getpid(); /* Get our pid. */
|
|
|
|
|
|
|
|
log_info("Angel pid file: '%s'; PID: %d.",
|
|
|
|
(const char *) options.angel_pid_file_name,
|
|
|
|
(int) pid);
|
|
|
|
|
|
|
|
create_pid_file(Options::angel_pid_file_name, pid);
|
|
|
|
|
2003-08-16 21:44:24 +04:00
|
|
|
while (child_status == CHILD_OK && is_terminated == 0)
|
|
|
|
sigsuspend(&zeromask);
|
2003-08-19 19:55:20 +04:00
|
|
|
|
2003-08-16 21:44:24 +04:00
|
|
|
if (is_terminated)
|
2004-11-17 01:52:33 +03:00
|
|
|
log_info("angel got signal %d, exiting", is_terminated);
|
2003-08-16 21:44:24 +04:00
|
|
|
else if (child_status == CHILD_NEED_RESPAWN)
|
2004-10-23 11:32:52 +04:00
|
|
|
{
|
2003-08-16 21:44:24 +04:00
|
|
|
child_status= CHILD_OK;
|
Fix for BUG#24415: Instance manager test im_daemon_life_cycle fails randomly.
The cause of im_daemon_life_cycle.imtest random failures was the following
behaviour of some implementations of LINUX threads: let's suppose that a
process has several threads (in LINUX threads, there is a separate process for
each thread). When the main process gets killed, the parent receives SIGCHLD
before all threads (child processes) die. In other words, the parent receives
SIGCHLD, when its child is not completely dead.
In terms of IM, that means that IM-angel receives SIGCHLD when IM-main is not dead
and still holds some resources. After receiving SIGCHLD, IM-angel restarts
IM-main, but IM-main failed to initialize, because previous instance (copy) of
IM-main still holds server socket (TCP-port).
Another problem here was that IM-angel restarted IM-main only if it was killed
by signal. If it exited with error, IM-angel thought it's intended / graceful
shutdown and exited itself.
So, when the second instance of IM-main failed to initialize, IM-angel thought
it's intended shutdown and quit.
The fix is
1. to change IM-angel so that it restarts IM-main if it exited with error code;
2. to change IM-main so that it returns proper exit code in case of failure.
mysql-test/t/disabled.def:
Enable im_daemon_life_cycle.
server-tools/instance-manager/listener.cc:
Set error status if Listener failed to initialize.
server-tools/instance-manager/manager.cc:
Return exit code from the manager.
server-tools/instance-manager/manager.h:
Return exit code from the manager.
server-tools/instance-manager/mysqlmanager.cc:
1. Restart IM-main if exit code is not EXIT_SUCCESS (0).
2. Log IM-main exit code in case of failure.
server-tools/instance-manager/thread_registry.cc:
Add support for exit code.
server-tools/instance-manager/thread_registry.h:
Add support for exit code.
2007-02-20 22:31:50 +03:00
|
|
|
log_error("angel(): mysqlmanager exited abnormally (exit code: %d):"
|
|
|
|
"respawning...",
|
|
|
|
(int) child_exit_code);
|
2003-08-16 21:44:24 +04:00
|
|
|
sleep(1); /* don't respawn too fast */
|
|
|
|
goto spawn;
|
|
|
|
}
|
2007-02-24 13:18:09 +03:00
|
|
|
|
|
|
|
/* Delete IM-angel pid file. */
|
|
|
|
my_delete(Options::angel_pid_file_name, MYF(0));
|
|
|
|
|
2004-10-23 11:32:52 +04:00
|
|
|
/*
|
|
|
|
mysqlmanager successfully exited, let's silently evaporate
|
|
|
|
If we return to main we fall into the manager() function, so let's
|
|
|
|
simply exit().
|
|
|
|
*/
|
|
|
|
exit(0);
|
2003-08-16 21:44:24 +04:00
|
|
|
}
|
|
|
|
}
|
2004-10-23 11:32:52 +04:00
|
|
|
|
2005-07-20 10:55:40 -05:00
|
|
|
#endif
|