summaryrefslogtreecommitdiff
path: root/server-tools/instance-manager/instance.cc
diff options
context:
space:
mode:
Diffstat (limited to 'server-tools/instance-manager/instance.cc')
-rw-r--r--server-tools/instance-manager/instance.cc234
1 files changed, 185 insertions, 49 deletions
diff --git a/server-tools/instance-manager/instance.cc b/server-tools/instance-manager/instance.cc
index 58bc5b85dd8..f2140ee7200 100644
--- a/server-tools/instance-manager/instance.cc
+++ b/server-tools/instance-manager/instance.cc
@@ -21,11 +21,25 @@
#include "instance.h"
#include "mysql_manager_error.h"
#include "log.h"
+#include "instance_map.h"
#include <my_sys.h>
#include <signal.h>
#include <m_string.h>
#include <sys/wait.h>
+
+C_MODE_START
+
+pthread_handler_decl(proxy, arg)
+{
+ Instance *instance= (Instance *) arg;
+ instance->fork_and_monitor();
+ return 0;
+}
+
+C_MODE_END
+
+
/*
The method starts an instance.
@@ -43,53 +57,115 @@ int Instance::start()
{
pid_t pid;
+ /* clear crash flag */
+ pthread_mutex_lock(&LOCK_instance);
+ crashed= 0;
+ pthread_mutex_unlock(&LOCK_instance);
+
+
if (!is_running())
{
- log_info("trying to start instance %s", options.instance_name);
- switch (pid= fork()) {
- case 0:
- if (fork()) /* zombie protection */
- exit(0); /* parent goes bye-bye */
- else
- {
- execv(options.mysqld_path, options.argv);
- exit(1);
- }
- case -1:
+ if ((pid= options.get_pid()) != 0) /* check the pidfile */
+ if (options.unlink_pidfile()) /* remove stalled pidfile */
+ log_error("cannot remove pidfile for instance %i, this might be \
+ since IM lacks permmissions or hasn't found the pidifle",
+ options.instance_name);
+
+ /*
+ No need to monitor this thread in the Thread_registry, as all
+ instances are to be stopped during shutdown.
+ */
+ pthread_t proxy_thd_id;
+ pthread_attr_t proxy_thd_attr;
+ int rc;
+
+ pthread_attr_init(&proxy_thd_attr);
+ pthread_attr_setdetachstate(&proxy_thd_attr, PTHREAD_CREATE_DETACHED);
+ rc= pthread_create(&proxy_thd_id, &proxy_thd_attr, proxy,
+ this);
+ pthread_attr_destroy(&proxy_thd_attr);
+ if (rc)
+ {
+ log_error("Instance::start(): pthread_create(proxy) failed");
return ER_CANNOT_START_INSTANCE;
- default:
- waitpid(pid, NULL, 0);
- return 0;
}
+
+ return 0;
}
/* the instance is started already */
return ER_INSTANCE_ALREADY_STARTED;
}
-int Instance::cleanup()
+
+void Instance::fork_and_monitor()
{
- /*
- We cannot close connection in destructor, as mysql_close needs alarm
- services which are definitely unavailaible at the time of destructor
- call.
- */
- if (is_connected)
- mysql_close(&mysql);
- return 0;
+ pid_t pid;
+ log_info("starting instance %s", options.instance_name);
+ switch (pid= fork()) {
+ case 0:
+ execv(options.mysqld_path, options.argv);
+ /* exec never returns */
+ exit(1);
+ case -1:
+ log_info("cannot fork() to start instance %s", options.instance_name);
+ return;
+ default:
+ wait(NULL);
+ /* set instance state to crashed */
+ pthread_mutex_lock(&LOCK_instance);
+ crashed= 1;
+ pthread_mutex_unlock(&LOCK_instance);
+
+ /*
+ Wake connection threads waiting for an instance to stop. This
+ is needed if a user issued command to stop an instance via
+ mysql connection. This is not the case if Guardian stop the thread.
+ */
+ pthread_cond_signal(&COND_instance_restarted);
+ /* wake guardian */
+ pthread_cond_signal(&instance_map->guardian->COND_guardian);
+ /* thread exits */
+ return;
+ }
+ /* we should never end up here */
+ DBUG_ASSERT(0);
+}
+
+
+Instance::Instance(): crashed(0)
+{
+ pthread_mutex_init(&LOCK_instance, 0);
+ pthread_cond_init(&COND_instance_restarted, 0);
}
Instance::~Instance()
{
pthread_mutex_destroy(&LOCK_instance);
+ pthread_cond_destroy(&COND_instance_restarted);
+}
+
+
+int Instance::is_crashed()
+{
+ int val;
+ pthread_mutex_lock(&LOCK_instance);
+ val= crashed;
+ pthread_mutex_unlock(&LOCK_instance);
+ return val;
}
bool Instance::is_running()
{
+ MYSQL mysql;
uint port= 0;
const char *socket= NULL;
+ const char *password= "321rarepassword213";
+ const char *username= "645rareusername945";
+ const char *access_denied_message= "Access denied for user";
+ bool return_val;
if (options.mysqld_port)
port= atoi(strchr(options.mysqld_port, '=') + 1);
@@ -98,30 +174,39 @@ bool Instance::is_running()
socket= strchr(options.mysqld_socket, '=') + 1;
pthread_mutex_lock(&LOCK_instance);
- if (!is_connected)
+
+ 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))
{
- mysql_init(&mysql);
- if (mysql_real_connect(&mysql, LOCAL_HOST, options.mysqld_user,
- options.mysqld_password,
- NullS, port,
- socket, 0))
- {
- mysql.reconnect= 1;
- is_connected= TRUE;
- pthread_mutex_unlock(&LOCK_instance);
- return TRUE;
- }
- mysql_close(&mysql);
+ /*
+ We have successfully connected to the server using fake
+ username/password. Write a warning to the logfile.
+ */
+ log_info("The Instance Manager was able to log into you server \
+ with faked compiled-in password while checking server status. \
+ Looks like something is wrong.");
pthread_mutex_unlock(&LOCK_instance);
- return FALSE;
+ return_val= TRUE; /* server is alive */
}
- else if (!mysql_ping(&mysql))
+ else
{
- pthread_mutex_unlock(&LOCK_instance);
- return TRUE;
+ if (!strncmp(access_denied_message, mysql_error(&mysql),
+ sizeof(access_denied_message)-1))
+ {
+ return_val= TRUE;
+ }
+ else
+ return_val= FALSE;
}
+
+ mysql_close(&mysql);
pthread_mutex_unlock(&LOCK_instance);
- return FALSE;
+
+ return return_val;
}
@@ -139,22 +224,67 @@ bool Instance::is_running()
int Instance::stop()
{
- if (is_running())
+ pid_t pid;
+ struct timespec timeout;
+ int waitchild= DEFAULT_SHUTDOWN_DELAY;
+
+ if (options.shutdown_delay != NULL)
+ waitchild= atoi(options.shutdown_delay);
+
+ kill_instance(SIGTERM);
+ /* sleep on condition to wait for SIGCHLD */
+
+ timeout.tv_sec= time(NULL) + waitchild;
+ timeout.tv_nsec= 0;
+ if (pthread_mutex_lock(&LOCK_instance))
+ goto err;
+
+ while (options.get_pid() != 0) /* while server isn't stopped */
{
- if (mysql_shutdown(&mysql, SHUTDOWN_DEFAULT))
- goto err;
+ int status;
- mysql_close(&mysql);
- is_connected= FALSE;
- return 0;
+ status= pthread_cond_timedwait(&COND_instance_restarted,
+ &LOCK_instance,
+ &timeout);
+ if (status == ETIMEDOUT)
+ break;
}
+ pthread_mutex_unlock(&LOCK_instance);
+
+ kill_instance(SIGKILL);
+
+ return 0;
+
return ER_INSTANCE_IS_NOT_STARTED;
err:
return ER_STOP_INSTANCE;
}
+void Instance::kill_instance(int signum)
+{
+ pid_t pid;
+ /* if there are no pid, everything seems to be fine */
+ if ((pid= options.get_pid()) != 0) /* get pid from pidfile */
+ {
+ /*
+ If we cannot kill mysqld, then it has propably crashed.
+ Let us try to remove staled pidfile and return successfully
+ as mysqld is probably stopped.
+ */
+ if (!kill(pid, signum))
+ options.unlink_pidfile();
+ else
+ if (signum == SIGKILL) /* really killed instance with SIGKILL */
+ log_error("The instance %s is being stopped forsibly. Normally \
+ it should not happed. Probably the instance has been \
+ hanging. You should also check your IM setup",
+ options.instance_name);
+ }
+ return;
+}
+
/*
We execute this function to initialize instance parameters.
Return value: 0 - ok. 1 - unable to init DYNAMIC_ARRAY.
@@ -162,7 +292,13 @@ err:
int Instance::init(const char *name_arg)
{
- pthread_mutex_init(&LOCK_instance, 0);
-
return options.init(name_arg);
}
+
+
+int Instance::complete_initialization(Instance_map *instance_map_arg,
+ const char *mysqld_path)
+{
+ instance_map= instance_map_arg;
+ return options.complete_initialization(mysqld_path);
+}