diff options
Diffstat (limited to 'server-tools/instance-manager/instance.cc')
-rw-r--r-- | server-tools/instance-manager/instance.cc | 234 |
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); +} |