mirror of
https://github.com/MariaDB/server.git
synced 2025-01-20 22:12:30 +01:00
5b7347bda3
- Remove bothersome warning messages. This change focuses on the warnings that are covered by the ignore file: support-files/compiler_warnings.supp. - Strings are guaranteed to be max uint in length
944 lines
23 KiB
C++
944 lines
23 KiB
C++
/* Copyright (C) 2004 MySQL AB
|
|
|
|
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
|
|
the Free Software Foundation; version 2 of the License.
|
|
|
|
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 */
|
|
|
|
#if defined(__GNUC__) && defined(USE_PRAGMA_IMPLEMENTATION)
|
|
#pragma implementation
|
|
#endif
|
|
|
|
#include <my_global.h>
|
|
#include <mysql.h>
|
|
|
|
#include <signal.h>
|
|
#ifndef __WIN__
|
|
#include <sys/wait.h>
|
|
#endif
|
|
|
|
#include "manager.h"
|
|
#include "guardian.h"
|
|
#include "instance.h"
|
|
#include "log.h"
|
|
#include "mysql_manager_error.h"
|
|
#include "portability.h"
|
|
#include "priv.h"
|
|
#include "thread_registry.h"
|
|
#include "instance_map.h"
|
|
|
|
|
|
/*************************************************************************
|
|
{{{ Platform-specific functions.
|
|
*************************************************************************/
|
|
|
|
#ifndef __WIN__
|
|
typedef pid_t My_process_info;
|
|
#else
|
|
typedef PROCESS_INFORMATION My_process_info;
|
|
#endif
|
|
|
|
/*
|
|
Wait for an instance
|
|
|
|
SYNOPSIS
|
|
wait_process()
|
|
pi Pointer to the process information structure
|
|
(platform-dependent).
|
|
|
|
RETURN
|
|
0 - Success
|
|
1 - Error
|
|
*/
|
|
|
|
#ifndef __WIN__
|
|
static int wait_process(My_process_info *pi)
|
|
{
|
|
/*
|
|
Here we wait for the child created. This process differs for systems
|
|
running LinuxThreads and POSIX Threads compliant systems. This is because
|
|
according to POSIX we could wait() for a child in any thread of the
|
|
process. While LinuxThreads require that wait() is called by the thread,
|
|
which created the child.
|
|
On the other hand we could not expect mysqld to return the pid, we
|
|
got in from fork(), to wait4() fucntion when running on LinuxThreads.
|
|
This is because MySQL shutdown thread is not the one, which was created
|
|
by our fork() call.
|
|
So basically we have two options: whether the wait() call returns only in
|
|
the creator thread, but we cannot use waitpid() since we have no idea
|
|
which pid we should wait for (in fact it should be the pid of shutdown
|
|
thread, but we don't know this one). Or we could use waitpid(), but
|
|
couldn't use wait(), because it could return in any wait() in the program.
|
|
*/
|
|
|
|
if (Manager::is_linux_threads())
|
|
wait(NULL); /* LinuxThreads were detected */
|
|
else
|
|
waitpid(*pi, NULL, 0);
|
|
|
|
return 0;
|
|
}
|
|
#else
|
|
static int wait_process(My_process_info *pi)
|
|
{
|
|
/* Wait until child process exits. */
|
|
WaitForSingleObject(pi->hProcess, INFINITE);
|
|
|
|
DWORD exitcode;
|
|
::GetExitCodeProcess(pi->hProcess, &exitcode);
|
|
|
|
/* Close process and thread handles. */
|
|
CloseHandle(pi->hProcess);
|
|
CloseHandle(pi->hThread);
|
|
|
|
/*
|
|
GetExitCodeProces returns zero on failure. We should revert this value
|
|
to report an error.
|
|
*/
|
|
return (!exitcode);
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
Launch an instance
|
|
|
|
SYNOPSIS
|
|
start_process()
|
|
instance_options Pointer to the options of the instance to be
|
|
launched.
|
|
pi Pointer to the process information structure
|
|
(platform-dependent).
|
|
|
|
RETURN
|
|
FALSE - Success
|
|
TRUE - Cannot create an instance
|
|
*/
|
|
|
|
#ifndef __WIN__
|
|
static bool start_process(Instance_options *instance_options,
|
|
My_process_info *pi)
|
|
{
|
|
#ifndef __QNX__
|
|
*pi= fork();
|
|
#else
|
|
/*
|
|
On QNX one cannot use fork() in multithreaded environment and we
|
|
should use spawn() or one of it's siblings instead.
|
|
Here we use spawnv(), which is a combination of fork() and execv()
|
|
in one call. It returns the pid of newly created process (>0) or -1
|
|
*/
|
|
*pi= spawnv(P_NOWAIT, instance_options->mysqld_path, instance_options->argv);
|
|
#endif
|
|
|
|
switch (*pi) {
|
|
case 0: /* never happens on QNX */
|
|
execv(instance_options->mysqld_path.str, instance_options->argv);
|
|
/* exec never returns */
|
|
exit(1);
|
|
case -1:
|
|
log_error("Instance '%s': can not start mysqld: fork() failed.",
|
|
(const char *) instance_options->instance_name.str);
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
#else
|
|
static bool start_process(Instance_options *instance_options,
|
|
My_process_info *pi)
|
|
{
|
|
STARTUPINFO si;
|
|
|
|
ZeroMemory(&si, sizeof(STARTUPINFO));
|
|
si.cb= sizeof(STARTUPINFO);
|
|
ZeroMemory(pi, sizeof(PROCESS_INFORMATION));
|
|
|
|
int cmdlen= 0;
|
|
for (int i= 0; instance_options->argv[i] != 0; i++)
|
|
cmdlen+= (uint) strlen(instance_options->argv[i]) + 3;
|
|
cmdlen++; /* make room for the null */
|
|
|
|
char *cmdline= new char[cmdlen];
|
|
if (cmdline == NULL)
|
|
return TRUE;
|
|
|
|
cmdline[0]= 0;
|
|
for (int i= 0; instance_options->argv[i] != 0; i++)
|
|
{
|
|
strcat(cmdline, "\"");
|
|
strcat(cmdline, instance_options->argv[i]);
|
|
strcat(cmdline, "\" ");
|
|
}
|
|
|
|
/* Start the child process */
|
|
BOOL result=
|
|
CreateProcess(NULL, /* Put it all in cmdline */
|
|
cmdline, /* Command line */
|
|
NULL, /* Process handle not inheritable */
|
|
NULL, /* Thread handle not inheritable */
|
|
FALSE, /* Set handle inheritance to FALSE */
|
|
0, /* No creation flags */
|
|
NULL, /* Use parent's environment block */
|
|
NULL, /* Use parent's starting directory */
|
|
&si, /* Pointer to STARTUPINFO structure */
|
|
pi); /* Pointer to PROCESS_INFORMATION structure */
|
|
delete cmdline;
|
|
|
|
return !result;
|
|
}
|
|
#endif
|
|
|
|
#ifdef __WIN__
|
|
|
|
BOOL SafeTerminateProcess(HANDLE hProcess, UINT uExitCode)
|
|
{
|
|
DWORD dwTID, dwCode, dwErr= 0;
|
|
HANDLE hProcessDup= INVALID_HANDLE_VALUE;
|
|
HANDLE hRT= NULL;
|
|
HINSTANCE hKernel= GetModuleHandle("Kernel32");
|
|
BOOL bSuccess= FALSE;
|
|
|
|
BOOL bDup= DuplicateHandle(GetCurrentProcess(),
|
|
hProcess, GetCurrentProcess(), &hProcessDup,
|
|
PROCESS_ALL_ACCESS, FALSE, 0);
|
|
|
|
// Detect the special case where the process is
|
|
// already dead...
|
|
if (GetExitCodeProcess((bDup) ? hProcessDup : hProcess, &dwCode) &&
|
|
(dwCode == STILL_ACTIVE))
|
|
{
|
|
FARPROC pfnExitProc;
|
|
|
|
pfnExitProc= GetProcAddress(hKernel, "ExitProcess");
|
|
|
|
hRT= CreateRemoteThread((bDup) ? hProcessDup : hProcess, NULL, 0,
|
|
(LPTHREAD_START_ROUTINE)pfnExitProc,
|
|
(PVOID)uExitCode, 0, &dwTID);
|
|
|
|
if (hRT == NULL)
|
|
dwErr= GetLastError();
|
|
}
|
|
else
|
|
dwErr= ERROR_PROCESS_ABORTED;
|
|
|
|
if (hRT)
|
|
{
|
|
// Must wait process to terminate to
|
|
// guarantee that it has exited...
|
|
WaitForSingleObject((bDup) ? hProcessDup : hProcess, INFINITE);
|
|
|
|
CloseHandle(hRT);
|
|
bSuccess= TRUE;
|
|
}
|
|
|
|
if (bDup)
|
|
CloseHandle(hProcessDup);
|
|
|
|
if (!bSuccess)
|
|
SetLastError(dwErr);
|
|
|
|
return bSuccess;
|
|
}
|
|
|
|
int kill(pid_t pid, int signum)
|
|
{
|
|
HANDLE processhandle= ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
|
|
if (signum == SIGTERM)
|
|
::SafeTerminateProcess(processhandle, 0);
|
|
else
|
|
::TerminateProcess(processhandle, -1);
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
/*************************************************************************
|
|
}}}
|
|
*************************************************************************/
|
|
|
|
|
|
/*************************************************************************
|
|
{{{ Static constants.
|
|
*************************************************************************/
|
|
|
|
const LEX_STRING
|
|
Instance::DFLT_INSTANCE_NAME= { C_STRING_WITH_LEN("mysqld") };
|
|
|
|
/*************************************************************************
|
|
}}}
|
|
*************************************************************************/
|
|
|
|
|
|
/*************************************************************************
|
|
{{{ Instance Monitor thread.
|
|
*************************************************************************/
|
|
|
|
/**
|
|
Proxy thread is a simple way to avoid all pitfalls of the threads
|
|
implementation in the OS (e.g. LinuxThreads). With such a thread we
|
|
don't have to process SIGCHLD, which is a tricky business if we want
|
|
to do it in a portable way.
|
|
|
|
Instance Monitor Thread forks a child process, execs mysqld and waits for
|
|
the child to die.
|
|
|
|
Instance Monitor assumes that the monitoring instance will not be dropped.
|
|
This is guaranteed by having flag monitoring_thread_active and
|
|
Instance::is_active() operation.
|
|
*/
|
|
|
|
class Instance_monitor: public Thread
|
|
{
|
|
public:
|
|
Instance_monitor(Instance *instance_arg) :instance(instance_arg) {}
|
|
protected:
|
|
virtual void run();
|
|
void start_and_monitor_instance();
|
|
private:
|
|
Instance *instance;
|
|
};
|
|
|
|
|
|
void Instance_monitor::run()
|
|
{
|
|
start_and_monitor_instance();
|
|
delete this;
|
|
}
|
|
|
|
|
|
void Instance_monitor::start_and_monitor_instance()
|
|
{
|
|
Thread_registry *thread_registry= Manager::get_thread_registry();
|
|
Guardian *guardian= Manager::get_guardian();
|
|
|
|
My_process_info mysqld_process_info;
|
|
Thread_info monitor_thread_info;
|
|
|
|
log_info("Instance '%s': Monitor: started.",
|
|
(const char *) instance->get_name()->str);
|
|
|
|
/*
|
|
For guarded instance register the thread in Thread_registry to wait for
|
|
the thread to stop on shutdown (nonguarded instances are not stopped on
|
|
shutdown, so the thread will no finish).
|
|
*/
|
|
|
|
if (instance->is_guarded())
|
|
{
|
|
thread_registry->register_thread(&monitor_thread_info, FALSE);
|
|
}
|
|
|
|
/* Starting mysqld. */
|
|
|
|
log_info("Instance '%s': Monitor: starting mysqld...",
|
|
(const char *) instance->get_name()->str);
|
|
|
|
if (start_process(&instance->options, &mysqld_process_info))
|
|
{
|
|
instance->lock();
|
|
instance->monitoring_thread_active= FALSE;
|
|
instance->unlock();
|
|
|
|
return;
|
|
}
|
|
|
|
/* Waiting for mysqld to die. */
|
|
|
|
log_info("Instance '%s': Monitor: waiting for mysqld to stop...",
|
|
(const char *) instance->get_name()->str);
|
|
|
|
wait_process(&mysqld_process_info); /* Don't check for return value. */
|
|
|
|
log_info("Instance '%s': Monitor: mysqld stopped.",
|
|
(const char *) instance->get_name()->str);
|
|
|
|
/* Update instance status. */
|
|
|
|
instance->lock();
|
|
|
|
if (instance->is_guarded())
|
|
thread_registry->unregister_thread(&monitor_thread_info);
|
|
|
|
instance->crashed= TRUE;
|
|
instance->monitoring_thread_active= FALSE;
|
|
|
|
log_info("Instance '%s': Monitor: finished.",
|
|
(const char *) instance->get_name()->str);
|
|
|
|
instance->unlock();
|
|
|
|
/* Wake up guardian. */
|
|
|
|
guardian->ping();
|
|
}
|
|
|
|
/**************************************************************************
|
|
}}}
|
|
**************************************************************************/
|
|
|
|
|
|
/**************************************************************************
|
|
{{{ Static operations.
|
|
**************************************************************************/
|
|
|
|
/**
|
|
The operation is intended to check whether string is a well-formed
|
|
instance name or not.
|
|
|
|
SYNOPSIS
|
|
is_name_valid()
|
|
name string to check
|
|
|
|
RETURN
|
|
TRUE string is a valid instance name
|
|
FALSE string is not a valid instance name
|
|
|
|
TODO: Move to Instance_name class: Instance_name::is_valid().
|
|
*/
|
|
|
|
bool Instance::is_name_valid(const LEX_STRING *name)
|
|
{
|
|
const char *name_suffix= name->str + DFLT_INSTANCE_NAME.length;
|
|
|
|
if (strncmp(name->str, Instance::DFLT_INSTANCE_NAME.str,
|
|
Instance::DFLT_INSTANCE_NAME.length) != 0)
|
|
return FALSE;
|
|
|
|
return *name_suffix == 0 || my_isdigit(default_charset_info, *name_suffix);
|
|
}
|
|
|
|
|
|
/**
|
|
The operation is intended to check if the given instance name is
|
|
mysqld-compatible or not.
|
|
|
|
SYNOPSIS
|
|
is_mysqld_compatible_name()
|
|
name name to check
|
|
|
|
RETURN
|
|
TRUE name is mysqld-compatible
|
|
FALSE otherwise
|
|
|
|
TODO: Move to Instance_name class: Instance_name::is_mysqld_compatible().
|
|
*/
|
|
|
|
bool Instance::is_mysqld_compatible_name(const LEX_STRING *name)
|
|
{
|
|
return strcmp(name->str, DFLT_INSTANCE_NAME.str) == 0;
|
|
}
|
|
|
|
|
|
/**
|
|
Return client state name. Must not be used outside the class.
|
|
Use Instance::get_state_name() instead.
|
|
*/
|
|
|
|
const char * Instance::get_instance_state_name(enum_instance_state state)
|
|
{
|
|
switch (state) {
|
|
case STOPPED:
|
|
return "offline";
|
|
|
|
case NOT_STARTED:
|
|
return "not started";
|
|
|
|
case STARTING:
|
|
return "starting";
|
|
|
|
case STARTED:
|
|
return "online";
|
|
|
|
case JUST_CRASHED:
|
|
return "failed";
|
|
|
|
case CRASHED:
|
|
return "crashed";
|
|
|
|
case CRASHED_AND_ABANDONED:
|
|
return "abandoned";
|
|
|
|
case STOPPING:
|
|
return "stopping";
|
|
}
|
|
|
|
return NULL; /* just to ignore compiler warning. */
|
|
}
|
|
|
|
/**************************************************************************
|
|
}}}
|
|
**************************************************************************/
|
|
|
|
|
|
/**************************************************************************
|
|
{{{ Initialization & deinitialization.
|
|
**************************************************************************/
|
|
|
|
Instance::Instance()
|
|
:monitoring_thread_active(FALSE),
|
|
crashed(FALSE),
|
|
configured(FALSE),
|
|
/* mysqld_compatible is initialized in init() */
|
|
state(NOT_STARTED),
|
|
restart_counter(0),
|
|
crash_moment(0),
|
|
last_checked(0)
|
|
{
|
|
pthread_mutex_init(&LOCK_instance, 0);
|
|
}
|
|
|
|
|
|
Instance::~Instance()
|
|
{
|
|
log_info("Instance '%s': destroying...", (const char *) get_name()->str);
|
|
|
|
pthread_mutex_destroy(&LOCK_instance);
|
|
}
|
|
|
|
|
|
/**
|
|
Initialize instance options.
|
|
|
|
SYNOPSIS
|
|
init()
|
|
name_arg name of the instance
|
|
|
|
RETURN:
|
|
FALSE - ok
|
|
TRUE - error
|
|
*/
|
|
|
|
bool Instance::init(const LEX_STRING *name_arg)
|
|
{
|
|
mysqld_compatible= is_mysqld_compatible_name(name_arg);
|
|
|
|
return options.init(name_arg);
|
|
}
|
|
|
|
|
|
/**
|
|
@brief Complete instance options initialization.
|
|
|
|
@return Error status.
|
|
@retval FALSE ok
|
|
@retval TRUE error
|
|
*/
|
|
|
|
bool Instance::complete_initialization()
|
|
{
|
|
configured= ! options.complete_initialization();
|
|
return !configured;
|
|
}
|
|
|
|
/**************************************************************************
|
|
}}}
|
|
**************************************************************************/
|
|
|
|
|
|
/**************************************************************************
|
|
{{{ Instance: public interface implementation.
|
|
**************************************************************************/
|
|
|
|
/**
|
|
Determine if there is some activity with the instance.
|
|
|
|
SYNOPSIS
|
|
is_active()
|
|
|
|
DESCRIPTION
|
|
An instance is active if one of the following conditions is true:
|
|
- Instance-monitoring thread is running;
|
|
- Instance is guarded and its state is other than STOPPED;
|
|
- Corresponding mysqld-server accepts connections.
|
|
|
|
MT-NOTE: instance must be locked before calling the operation.
|
|
|
|
RETURN
|
|
TRUE - instance is active
|
|
FALSE - otherwise.
|
|
*/
|
|
|
|
bool Instance::is_active()
|
|
{
|
|
if (monitoring_thread_active)
|
|
return TRUE;
|
|
|
|
if (is_guarded() && get_state() != STOPPED)
|
|
return TRUE;
|
|
|
|
return is_mysqld_running();
|
|
}
|
|
|
|
|
|
/**
|
|
Determine if mysqld is accepting connections.
|
|
|
|
SYNOPSIS
|
|
is_mysqld_running()
|
|
|
|
DESCRIPTION
|
|
Try to connect to mysqld with fake login/password to check whether it is
|
|
accepting connections or not.
|
|
|
|
MT-NOTE: instance must be locked before calling the operation.
|
|
|
|
RETURN
|
|
TRUE - mysqld is alive and accept connections
|
|
FALSE - otherwise.
|
|
*/
|
|
|
|
bool Instance::is_mysqld_running()
|
|
{
|
|
MYSQL mysql;
|
|
uint port= options.get_mysqld_port(); /* 0 if not specified. */
|
|
const char *socket= NULL;
|
|
static const char *password= "check_connection";
|
|
static const char *username= "MySQL_Instance_Manager";
|
|
static const char *access_denied_message= "Access denied for user";
|
|
bool return_val;
|
|
|
|
if (options.mysqld_socket)
|
|
socket= options.mysqld_socket;
|
|
|
|
/* no port was specified => instance falled back to default value */
|
|
if (!port && !options.mysqld_socket)
|
|
port= SERVER_DEFAULT_PORT;
|
|
|
|
mysql_init(&mysql);
|
|
/* try to connect to a server with a fake username/password pair */
|
|
if (mysql_real_connect(&mysql, LOCAL_HOST, username,
|
|
password,
|
|
NullS, port,
|
|
socket, 0))
|
|
{
|
|
/*
|
|
We have successfully connected to the server using fake
|
|
username/password. Write a warning to the logfile.
|
|
*/
|
|
log_error("Instance '%s': was able to log into mysqld.",
|
|
(const char *) get_name()->str);
|
|
return_val= TRUE; /* server is alive */
|
|
}
|
|
else
|
|
return_val= test(!strncmp(access_denied_message, mysql_error(&mysql),
|
|
sizeof(access_denied_message) - 1));
|
|
|
|
mysql_close(&mysql);
|
|
|
|
return return_val;
|
|
}
|
|
|
|
|
|
/**
|
|
@brief Start mysqld.
|
|
|
|
Reset flags and start Instance Monitor thread, which will start mysqld.
|
|
|
|
@note Instance must be locked before calling the operation.
|
|
|
|
@return Error status code
|
|
@retval FALSE Ok
|
|
@retval TRUE Could not start instance
|
|
*/
|
|
|
|
bool Instance::start_mysqld()
|
|
{
|
|
Instance_monitor *instance_monitor;
|
|
|
|
if (!configured)
|
|
return TRUE;
|
|
|
|
/*
|
|
Prepare instance to start Instance Monitor thread.
|
|
|
|
NOTE: It's important to set these actions here in order to avoid
|
|
race conditions -- these actions must be done under acquired lock on
|
|
Instance.
|
|
*/
|
|
|
|
crashed= FALSE;
|
|
monitoring_thread_active= TRUE;
|
|
|
|
remove_pid();
|
|
|
|
/* Create and start the Instance Monitor thread. */
|
|
|
|
instance_monitor= new Instance_monitor(this);
|
|
|
|
if (instance_monitor == NULL || instance_monitor->start(Thread::DETACHED))
|
|
{
|
|
delete instance_monitor;
|
|
monitoring_thread_active= FALSE;
|
|
|
|
log_error("Instance '%s': can not create instance monitor thread.",
|
|
(const char *) get_name()->str);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
++restart_counter;
|
|
|
|
/* The Instance Monitor thread will delete itself when it's finished. */
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/**
|
|
Stop mysqld.
|
|
|
|
SYNOPSIS
|
|
stop_mysqld()
|
|
|
|
DESCRIPTION
|
|
Try to stop mysqld gracefully. Otherwise kill it with SIGKILL.
|
|
|
|
MT-NOTE: instance must be locked before calling the operation.
|
|
|
|
RETURN
|
|
FALSE - ok
|
|
TRUE - could not stop the instance
|
|
*/
|
|
|
|
bool Instance::stop_mysqld()
|
|
{
|
|
log_info("Instance '%s': stopping mysqld...",
|
|
(const char *) get_name()->str);
|
|
|
|
kill_mysqld(SIGTERM);
|
|
|
|
if (!wait_for_stop())
|
|
{
|
|
log_info("Instance '%s': mysqld stopped gracefully.",
|
|
(const char *) get_name()->str);
|
|
return FALSE;
|
|
}
|
|
|
|
log_info("Instance '%s': mysqld failed to stop gracefully within %d seconds.",
|
|
(const char *) get_name()->str,
|
|
(int) options.get_shutdown_delay());
|
|
|
|
log_info("Instance'%s': killing mysqld...",
|
|
(const char *) get_name()->str);
|
|
|
|
kill_mysqld(SIGKILL);
|
|
|
|
if (!wait_for_stop())
|
|
{
|
|
log_info("Instance '%s': mysqld has been killed.",
|
|
(const char *) get_name()->str);
|
|
return FALSE;
|
|
}
|
|
|
|
log_info("Instance '%s': can not kill mysqld within %d seconds.",
|
|
(const char *) get_name()->str,
|
|
(int) options.get_shutdown_delay());
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/**
|
|
Send signal to mysqld.
|
|
|
|
SYNOPSIS
|
|
kill_mysqld()
|
|
|
|
DESCRIPTION
|
|
Load pid from the pid file and send the given signal to that process.
|
|
If the signal is SIGKILL, remove the pid file after sending the signal.
|
|
|
|
MT-NOTE: instance must be locked before calling the operation.
|
|
|
|
TODO
|
|
This too low-level and OS-specific operation for public interface.
|
|
Also, it has some implicit behaviour for SIGKILL signal. Probably, we
|
|
should have the following public operations instead:
|
|
- start_mysqld() -- as is;
|
|
- stop_mysqld -- request mysqld to shutdown gracefully (send SIGTERM);
|
|
don't wait for complete shutdown;
|
|
- wait_for_stop() (or join_mysqld()) -- wait for mysqld to stop within
|
|
time interval;
|
|
- kill_mysqld() -- request to terminate mysqld; don't wait for
|
|
completion.
|
|
These operations should also be used in Guardian to manage instances.
|
|
*/
|
|
|
|
bool Instance::kill_mysqld(int signum)
|
|
{
|
|
pid_t mysqld_pid= options.load_pid();
|
|
|
|
if (mysqld_pid == 0)
|
|
{
|
|
log_info("Instance '%s': no pid file to send a signal (%d).",
|
|
(const char *) get_name()->str,
|
|
(int) signum);
|
|
return TRUE;
|
|
}
|
|
|
|
log_info("Instance '%s': sending %d to %d...",
|
|
(const char *) get_name()->str,
|
|
(int) signum,
|
|
(int) mysqld_pid);
|
|
|
|
if (kill(mysqld_pid, signum))
|
|
{
|
|
log_info("Instance '%s': kill() failed.",
|
|
(const char *) get_name()->str);
|
|
return TRUE;
|
|
}
|
|
|
|
/* Kill suceeded */
|
|
if (signum == SIGKILL) /* really killed instance with SIGKILL */
|
|
{
|
|
log_error("Instance '%s': killed.",
|
|
(const char *) options.instance_name.str);
|
|
|
|
/* After sucessful hard kill the pidfile need to be removed */
|
|
options.unlink_pidfile();
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/**
|
|
Lock instance.
|
|
*/
|
|
|
|
void Instance::lock()
|
|
{
|
|
pthread_mutex_lock(&LOCK_instance);
|
|
}
|
|
|
|
|
|
/**
|
|
Unlock instance.
|
|
*/
|
|
|
|
void Instance::unlock()
|
|
{
|
|
pthread_mutex_unlock(&LOCK_instance);
|
|
}
|
|
|
|
|
|
/**
|
|
Return instance state name.
|
|
|
|
SYNOPSIS
|
|
get_state_name()
|
|
|
|
DESCRIPTION
|
|
The operation returns user-friendly state name. The operation can be
|
|
used both for guarded and non-guarded instances.
|
|
|
|
MT-NOTE: instance must be locked before calling the operation.
|
|
|
|
TODO: Replace with the static get_state_name(state_code) function.
|
|
*/
|
|
|
|
const char *Instance::get_state_name()
|
|
{
|
|
if (!is_configured())
|
|
return "misconfigured";
|
|
|
|
if (is_guarded())
|
|
{
|
|
/* The instance is managed by Guardian: we can report precise state. */
|
|
|
|
return get_instance_state_name(get_state());
|
|
}
|
|
|
|
/* The instance is not managed by Guardian: we can report status only. */
|
|
|
|
return is_active() ? "online" : "offline";
|
|
}
|
|
|
|
|
|
/**
|
|
Reset statistics.
|
|
|
|
SYNOPSIS
|
|
reset_stat()
|
|
|
|
DESCRIPTION
|
|
The operation resets statistics used for guarding the instance.
|
|
|
|
MT-NOTE: instance must be locked before calling the operation.
|
|
|
|
TODO: Make private.
|
|
*/
|
|
|
|
void Instance::reset_stat()
|
|
{
|
|
restart_counter= 0;
|
|
crash_moment= 0;
|
|
last_checked= 0;
|
|
}
|
|
|
|
/**************************************************************************
|
|
}}}
|
|
**************************************************************************/
|
|
|
|
|
|
/**************************************************************************
|
|
{{{ Instance: implementation of private operations.
|
|
**************************************************************************/
|
|
|
|
/**
|
|
Remove pid file.
|
|
*/
|
|
|
|
void Instance::remove_pid()
|
|
{
|
|
int mysqld_pid= options.load_pid();
|
|
|
|
if (mysqld_pid == 0)
|
|
return;
|
|
|
|
if (options.unlink_pidfile())
|
|
{
|
|
log_error("Instance '%s': can not unlink pid file.",
|
|
(const char *) options.instance_name.str);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
Wait for mysqld to stop within shutdown interval.
|
|
*/
|
|
|
|
bool Instance::wait_for_stop()
|
|
{
|
|
int start_time= (int) time(NULL);
|
|
int finish_time= start_time + options.get_shutdown_delay();
|
|
|
|
log_info("Instance '%s': waiting for mysqld to stop "
|
|
"(timeout: %d seconds)...",
|
|
(const char *) get_name()->str,
|
|
(int) options.get_shutdown_delay());
|
|
|
|
while (true)
|
|
{
|
|
if (options.load_pid() == 0 && !is_mysqld_running())
|
|
return FALSE;
|
|
|
|
if (time(NULL) >= finish_time)
|
|
return TRUE;
|
|
|
|
/* Sleep for 0.3 sec and check again. */
|
|
|
|
my_sleep(300000);
|
|
}
|
|
}
|
|
|
|
/**************************************************************************
|
|
}}}
|
|
**************************************************************************/
|