diff options
Diffstat (limited to 'server-tools')
-rw-r--r-- | server-tools/instance-manager/commands.cc | 8 | ||||
-rw-r--r-- | server-tools/instance-manager/guardian.cc | 107 | ||||
-rw-r--r-- | server-tools/instance-manager/guardian.h | 19 | ||||
-rw-r--r-- | server-tools/instance-manager/instance.cc | 22 | ||||
-rw-r--r-- | server-tools/instance-manager/instance.h | 4 | ||||
-rw-r--r-- | server-tools/instance-manager/instance_map.cc | 11 | ||||
-rw-r--r-- | server-tools/instance-manager/instance_map.h | 7 | ||||
-rw-r--r-- | server-tools/instance-manager/instance_options.cc | 7 | ||||
-rw-r--r-- | server-tools/instance-manager/instance_options.h | 9 | ||||
-rw-r--r-- | server-tools/instance-manager/manager.cc | 17 | ||||
-rw-r--r-- | server-tools/instance-manager/messages.cc | 4 | ||||
-rw-r--r-- | server-tools/instance-manager/options.cc | 16 | ||||
-rw-r--r-- | server-tools/instance-manager/thread_repository.cc | 185 | ||||
-rw-r--r-- | server-tools/instance-manager/thread_repository.h | 113 |
14 files changed, 160 insertions, 369 deletions
diff --git a/server-tools/instance-manager/commands.cc b/server-tools/instance-manager/commands.cc index 4922aba4a06..70774115429 100644 --- a/server-tools/instance-manager/commands.cc +++ b/server-tools/instance-manager/commands.cc @@ -274,10 +274,10 @@ int Show_instance_options::do_command(struct st_net *net, goto err; } - if (instance->options.is_guarded != NULL) + if (instance->options.nonguarded == NULL) { position= 0; - store_to_string(&send_buff, (char *) "guarded", &position); + store_to_string(&send_buff, (char *) "nonguarded", &position); store_to_string(&send_buff, "", &position); if (my_net_write(net, send_buff.buffer, (uint) position)) goto err; @@ -350,7 +350,7 @@ int Start_instance::execute(struct st_net *net, ulong connection_id) if (err_code= instance->start()) return err_code; - if (instance->options.is_guarded != NULL) + if (instance->options.nonguarded == NULL) instance_map->guardian->guard(instance); net_send_ok(net, connection_id); @@ -381,7 +381,7 @@ int Stop_instance::execute(struct st_net *net, ulong connection_id) } else { - if (instance->options.is_guarded != NULL) + if (instance->options.nonguarded == NULL) instance_map->guardian-> stop_guard(instance); if ((err_code= instance->stop())) diff --git a/server-tools/instance-manager/guardian.cc b/server-tools/instance-manager/guardian.cc index f68ef6575a0..e8f9068dbb9 100644 --- a/server-tools/instance-manager/guardian.cc +++ b/server-tools/instance-manager/guardian.cc @@ -46,6 +46,8 @@ Guardian_thread::Guardian_thread(Thread_registry &thread_registry_arg, { pthread_mutex_init(&LOCK_guardian, 0); pthread_cond_init(&COND_guardian, 0); + shutdown_guardian= FALSE; + is_stopped= FALSE; thread_registry.register_thread(&thread_info); init_alloc_root(&alloc, MEM_ROOT_BLOCK_SIZE, 0); guarded_instances= NULL; @@ -65,6 +67,22 @@ Guardian_thread::~Guardian_thread() } +void Guardian_thread::shutdown() +{ + pthread_mutex_lock(&LOCK_guardian); + shutdown_guardian= TRUE; + pthread_mutex_unlock(&LOCK_guardian); +} + + +void Guardian_thread::request_stop_instances() +{ + pthread_mutex_lock(&LOCK_guardian); + request_stop= TRUE; + pthread_mutex_unlock(&LOCK_guardian); +} + + /* Run guardian thread @@ -80,6 +98,7 @@ Guardian_thread::~Guardian_thread() void Guardian_thread::run() { Instance *instance; + int restart_retry= 100; LIST *loop; struct timespec timeout; @@ -87,26 +106,68 @@ void Guardian_thread::run() pthread_mutex_lock(&LOCK_guardian); - while (!thread_registry.is_shutdown()) + while (!shutdown_guardian) { + int status= 0; loop= guarded_instances; while (loop != NULL) { - instance= (Instance *) loop->data; - /* instance-> start already checks whether the instance is running */ - if (instance->start() != ER_INSTANCE_ALREADY_STARTED) - log_info("guardian attempted to restart instance %s", - instance->options.instance_name); + instance= ((GUARD_NODE *) loop->data)->instance; + if (!instance->is_running()) + { + int state= 0; /* state of guardian */ + + if ((((GUARD_NODE *) loop->data)->crash_moment == 0)) + state= 1; /* an instance just crashed */ + else + if (time(NULL) - ((GUARD_NODE *) loop->data)->crash_moment <= 2) + /* try to restart an instance immediately */ + state= 2; + else + state= 3; /* try to restart it */ + + if (state == 1) + ((GUARD_NODE *) loop->data)->crash_moment= time(NULL); + + if ((state == 1) || (state == 2)) + { + instance->start(); + ((GUARD_NODE *) loop->data)->restart_counter++; + log_info("guardian: starting instance %s", + instance->options.instance_name); + } + else + { + if ((status == ETIMEDOUT) && + (((GUARD_NODE *) loop->data)->restart_counter < restart_retry)) + { + instance->start(); + ((GUARD_NODE *) loop->data)->restart_counter++; + log_info("guardian: starting instance %s", + instance->options.instance_name); + } + } + } + else /* clear status fields */ + { + ((GUARD_NODE *) loop->data)->restart_counter= 0; + ((GUARD_NODE *) loop->data)->crash_moment= 0; + } loop= loop->next; } move_to_list(&starting_instances, &guarded_instances); timeout.tv_sec= time(NULL) + monitoring_interval; timeout.tv_nsec= 0; - pthread_cond_timedwait(&COND_guardian, &LOCK_guardian, &timeout); + status= pthread_cond_timedwait(&COND_guardian, &LOCK_guardian, &timeout); } pthread_mutex_unlock(&LOCK_guardian); + if (request_stop) + stop_instances(); + is_stopped= TRUE; + /* now, when the Guardian is stopped we can stop the IM */ + thread_registry.request_shutdown(); my_thread_end(); } @@ -119,7 +180,7 @@ int Guardian_thread::start() instance_map->lock(); while ((instance= iterator.next())) { - if ((instance->options.is_guarded != NULL) && (instance->is_running())) + if ((instance->options.nonguarded == NULL)) if (guard(instance)) return 1; } @@ -170,12 +231,18 @@ void Guardian_thread::move_to_list(LIST **from, LIST **to) int Guardian_thread::add_instance_to_list(Instance *instance, LIST **list) { LIST *node; + GUARD_NODE *content; node= (LIST *) alloc_root(&alloc, sizeof(LIST)); - if (node == NULL) + content= (GUARD_NODE *) alloc_root(&alloc, sizeof(GUARD_NODE)); + + if ((node == NULL) || (content == NULL)) return 1; /* we store the pointers to instances from the instance_map's MEM_ROOT */ - node->data= (void *) instance; + content->instance= instance; + content->restart_counter= 0; + content->crash_moment= 0; + node->data= (void *) content; pthread_mutex_lock(&LOCK_guardian); *list= list_add(*list, node); @@ -205,7 +272,7 @@ int Guardian_thread::stop_guard(Instance *instance) We compare only pointers, as we always use pointers from the instance_map's MEM_ROOT. */ - if ((Instance *) node->data == instance) + if (((GUARD_NODE *) node->data)->instance == instance) { guarded_instances= list_delete(guarded_instances, node); pthread_mutex_unlock(&LOCK_guardian); @@ -219,3 +286,21 @@ int Guardian_thread::stop_guard(Instance *instance) return 0; } +int Guardian_thread::stop_instances() +{ + Instance *instance; + Instance_map::Iterator iterator(instance_map); + + while ((instance= iterator.next())) + { + if ((instance->options.nonguarded == NULL)) + { + if (stop_guard(instance)) + return 1; + /* let us try to stop the server */ + instance->stop(); + } + } + + return 0; +} diff --git a/server-tools/instance-manager/guardian.h b/server-tools/instance-manager/guardian.h index bcc249ed7d3..d96208247ae 100644 --- a/server-tools/instance-manager/guardian.h +++ b/server-tools/instance-manager/guardian.h @@ -24,6 +24,7 @@ #pragma interface #endif +class Instance; class Instance_map; #include "thread_registry.h" @@ -35,6 +36,13 @@ pthread_handler_decl(guardian, arg); C_MODE_END +typedef struct st_guard_node +{ + Instance *instance; + uint restart_counter; + time_t crash_moment; +} GUARD_NODE; + struct Guardian_thread_args { @@ -67,13 +75,17 @@ public: void run(); int init(); int start(); + void shutdown(); + void request_stop_instances(); int guard(Instance *instance); int stop_guard(Instance *instance); + bool is_stopped; public: pthread_cond_t COND_guardian; private: + int stop_instances(); int add_instance_to_list(Instance *instance, LIST **list); void move_to_list(LIST **from, LIST **to); @@ -84,6 +96,13 @@ private: LIST *starting_instances; MEM_ROOT alloc; enum { MEM_ROOT_BLOCK_SIZE= 512 }; + /* this variable is set to TRUE when we want to stop Guardian thread */ + bool shutdown_guardian; + /* + This var is usually set together with shutdown_guardian. this way we + request guardian to shut down all instances before termination + */ + bool request_stop; }; #endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_GUARDIAN_H */ diff --git a/server-tools/instance-manager/instance.cc b/server-tools/instance-manager/instance.cc index edb9ea61ad3..6c32aa1d815 100644 --- a/server-tools/instance-manager/instance.cc +++ b/server-tools/instance-manager/instance.cc @@ -42,10 +42,16 @@ int Instance::start() { - /* echk for the pidfile and remove it */ + pid_t pid; + if (!is_running()) { - stop(); + 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); + log_info("starting instance %s", options.instance_name); switch (pid= fork()) { case 0: @@ -145,14 +151,17 @@ int Instance::stop() { pid_t pid; struct timespec timeout; - time_t waitchild= 35; /* */ + int waitchild= DEFAULT_SHUTDOWN_DELAY; + + if (options.shutdown_delay != NULL) + waitchild= atoi(options.shutdown_delay); 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 succes as mysqld - is stopped + is probably stopped */ if (kill(pid, SIGTERM)) { @@ -161,9 +170,6 @@ int Instance::stop() since IM lacks permmissions or hasn't found the pidifle", options.instance_name); - log_error("The instance %s has probably crashed or IM lacks permissions \ - to kill it. in either case something seems to be wrong. \ - Check your setup", options.instance_name); return 0; } @@ -174,7 +180,7 @@ int Instance::stop() if (pthread_mutex_lock(&instance_map->pid_cond.LOCK_pid)) goto err; /* perhaps this should be procecced differently */ - while (options.get_pid() != 0) + while (options.get_pid() != 0) /* while server isn't stopped */ { int status; diff --git a/server-tools/instance-manager/instance.h b/server-tools/instance-manager/instance.h index 78b7768c121..29137c749c7 100644 --- a/server-tools/instance-manager/instance.h +++ b/server-tools/instance-manager/instance.h @@ -41,11 +41,9 @@ public: int cleanup(); public: + enum { DEFAULT_SHUTDOWN_DELAY= 35 }; Instance_options options; - /* connection to the instance */ - pid_t pid; - private: /* Mutex protecting the instance. Currently we use it to avoid the diff --git a/server-tools/instance-manager/instance_map.cc b/server-tools/instance-manager/instance_map.cc index 2573729841b..26181ec56e0 100644 --- a/server-tools/instance-manager/instance_map.cc +++ b/server-tools/instance-manager/instance_map.cc @@ -82,7 +82,8 @@ static int process_option(void * ctx, const char *group, const char *option) map = (Instance_map*) ctx; if (strncmp(group, prefix, sizeof prefix) == 0 && - (my_isdigit(default_charset_info, group[sizeof prefix]))) + ((my_isdigit(default_charset_info, group[sizeof prefix])) + || group[sizeof(prefix)] == '\0')) { if ((instance= map->find(group, strlen(group))) == NULL) { @@ -109,13 +110,9 @@ err_new_instance: C_MODE_END -Instance_map::Instance_map(const char *default_mysqld_path_arg, - const char *default_admin_user_arg, - const char *default_admin_password_arg) +Instance_map::Instance_map(const char *default_mysqld_path_arg) { mysqld_path= default_mysqld_path_arg; - user= default_admin_user_arg; - password= default_admin_password_arg; pthread_mutex_init(&LOCK_instance_map, 0); } @@ -195,7 +192,7 @@ void Instance_map::complete_initialization() { instance= (Instance *) hash_element(&hash, i); instance->complete_initialization(this); - instance->options.complete_initialization(mysqld_path, user, password); + instance->options.complete_initialization(mysqld_path); i++; } } diff --git a/server-tools/instance-manager/instance_map.h b/server-tools/instance-manager/instance_map.h index 1f6072f2582..05bc4d94908 100644 --- a/server-tools/instance-manager/instance_map.h +++ b/server-tools/instance-manager/instance_map.h @@ -71,9 +71,7 @@ public: int unlock(); int init(); - Instance_map(const char *default_mysqld_path_arg, - const char *default_admin_user_arg, - const char *default_admin_password_arg); + Instance_map(const char *default_mysqld_path_arg); ~Instance_map(); /* loads options from config files */ @@ -85,9 +83,6 @@ public: public: const char *mysqld_path; - /* user an password to shutdown MySQL */ - const char *user; - const char *password; Guardian_thread *guardian; /* structure used for syncronization reasons in the stop command */ CHILD_COND pid_cond; diff --git a/server-tools/instance-manager/instance_options.cc b/server-tools/instance-manager/instance_options.cc index c29f136955e..0e29dca2422 100644 --- a/server-tools/instance-manager/instance_options.cc +++ b/server-tools/instance-manager/instance_options.cc @@ -113,9 +113,7 @@ pid_t Instance_options::get_pid() } -int Instance_options::complete_initialization(const char *default_path, - const char *default_user, - const char *default_password) +int Instance_options::complete_initialization(const char *default_path) { const char *tmp; @@ -199,7 +197,8 @@ int Instance_options::add_option(const char* option) {"--bind-address=", 15, &mysqld_bind_address, SAVE_WHOLE_AND_ADD}, {"--pid-file=", 11, &mysqld_pid_file, SAVE_WHOLE_AND_ADD}, {"--mysqld-path=", 14, &mysqld_path, SAVE_VALUE}, - {"--guarded", 9, &is_guarded, SAVE_WHOLE}, + {"--nonguarded", 9, &nonguarded, SAVE_WHOLE}, + {"--shutdown_delay", 9, &shutdown_delay, SAVE_VALUE}, {NULL, 0, NULL, 0} }; struct selected_options_st *selected_options; diff --git a/server-tools/instance-manager/instance_options.h b/server-tools/instance-manager/instance_options.h index 26448c0c2b1..eae22f840aa 100644 --- a/server-tools/instance-manager/instance_options.h +++ b/server-tools/instance-manager/instance_options.h @@ -38,14 +38,12 @@ class Instance_options public: Instance_options() : mysqld_socket(0), mysqld_datadir(0), mysqld_bind_address(0), - mysqld_pid_file(0), mysqld_port(0), mysqld_path(0), is_guarded(0), + mysqld_pid_file(0), mysqld_port(0), mysqld_path(0), nonguarded(0), filled_default_options(0) {} ~Instance_options(); /* fills in argv */ - int complete_initialization(const char *default_path, - const char *default_user, - const char *default_password); + int complete_initialization(const char *default_path); int add_option(const char* option); int init(const char *instance_name_arg); @@ -71,7 +69,8 @@ public: uint instance_name_len; const char *instance_name; const char *mysqld_path; - const char *is_guarded; + const char *nonguarded; + const char *shutdown_delay; DYNAMIC_ARRAY options_array; private: int add_to_argv(const char *option); diff --git a/server-tools/instance-manager/manager.cc b/server-tools/instance-manager/manager.cc index a8c6406fb83..6d9ee569d04 100644 --- a/server-tools/instance-manager/manager.cc +++ b/server-tools/instance-manager/manager.cc @@ -67,9 +67,7 @@ void manager(const Options &options) */ User_map user_map; - Instance_map instance_map(options.default_mysqld_path, - options.default_admin_user, - options.default_admin_password); + Instance_map instance_map(options.default_mysqld_path); Guardian_thread guardian_thread(thread_registry, &instance_map, options.monitoring_interval); @@ -181,8 +179,17 @@ void manager(const Options &options) pthread_cond_broadcast(&guardian_thread.COND_guardian); break; default: - thread_registry.deliver_shutdown(); - shutdown_complete= TRUE; + if (!guardian_thread.is_stopped) + { + guardian_thread.request_stop_instances(); + guardian_thread.shutdown(); + pthread_cond_broadcast(&guardian_thread.COND_guardian); + } + else + { + thread_registry.deliver_shutdown(); + shutdown_complete= TRUE; + } break; } } diff --git a/server-tools/instance-manager/messages.cc b/server-tools/instance-manager/messages.cc index cc07352f58a..e3c2423a47e 100644 --- a/server-tools/instance-manager/messages.cc +++ b/server-tools/instance-manager/messages.cc @@ -45,8 +45,8 @@ static const char *mysqld_error_message(unsigned sql_errno) case ER_BAD_INSTANCE_NAME: return "Bad instance name. Check that the instance with such a name exists"; case ER_INSTANCE_IS_NOT_STARTED: - return "Cannot stop instance. Perhaps the instance is not started or you" - " have specified wrong username/password in the config file"; + return "Cannot stop instance. Perhaps the instance is not started, or was started" + "manually, so IM cannot find the pidfile."; case ER_INSTANCE_ALREADY_STARTED: return "The instance is already started"; case ER_CANNOT_START_INSTANCE: diff --git a/server-tools/instance-manager/options.cc b/server-tools/instance-manager/options.cc index 05493e10ad8..828a5d7b4d0 100644 --- a/server-tools/instance-manager/options.cc +++ b/server-tools/instance-manager/options.cc @@ -35,8 +35,6 @@ const char *Options::pid_file_name= QUOTE(DEFAULT_PID_FILE_NAME); const char *Options::socket_file_name= QUOTE(DEFAULT_SOCKET_FILE_NAME); const char *Options::password_file_name= QUOTE(DEFAULT_PASSWORD_FILE_NAME); const char *Options::default_mysqld_path= QUOTE(DEFAULT_MYSQLD_PATH); -const char *Options::default_admin_user= QUOTE(DEFAULT_USER); -const char *Options::default_admin_password= QUOTE(DEFAULT_PASSWORD); const char *Options::bind_address= 0; /* No default value */ uint Options::monitoring_interval= DEFAULT_MONITORING_INTERVAL; uint Options::port_number= DEFAULT_PORT; @@ -55,8 +53,6 @@ enum options { OPT_RUN_AS_SERVICE, OPT_USER, OPT_PASSWORD, - OPT_DEFAULT_ADMIN_USER, - OPT_DEFAULT_ADMIN_PASSWORD, OPT_MONITORING_INTERVAL, OPT_PORT, OPT_BIND_ADDRESS @@ -98,18 +94,6 @@ static struct my_option my_long_options[] = (gptr *) &Options::default_mysqld_path, (gptr *) &Options::default_mysqld_path, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, - { "default-admin-user", OPT_DEFAULT_ADMIN_USER, "Username to shutdown MySQL" - " instances.", - (gptr *) &Options::default_admin_user, - (gptr *) &Options::default_admin_user, - 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, - - { "default-admin-password", OPT_DEFAULT_ADMIN_PASSWORD, "Password to" - "shutdown MySQL instances.", - (gptr *) &Options::default_admin_password, - (gptr *) &Options::default_admin_password, - 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, - { "monitoring-interval", OPT_MONITORING_INTERVAL, "Interval to monitor instances" " in seconds.", (gptr *) &Options::monitoring_interval, diff --git a/server-tools/instance-manager/thread_repository.cc b/server-tools/instance-manager/thread_repository.cc deleted file mode 100644 index d0b302d29fb..00000000000 --- a/server-tools/instance-manager/thread_repository.cc +++ /dev/null @@ -1,185 +0,0 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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; either version 2 of the License, or - (at your option) any later version. - - 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 */ - -#ifdef __GNUC__ -#pragma implementation -#endif - -#include "thread_repository.h" -#include <assert.h> -#include <signal.h> -#include "log.h" - - -/* Kick-off signal handler */ - -enum { THREAD_KICK_OFF_SIGNAL= SIGUSR2 }; - -static void handle_signal(int __attribute__((unused)) sig_no) -{ -} - - -/* - TODO: think about moving signal information (now it's shutdown_in_progress) - to Thread_info. It will reduce contention and allow signal deliverence to - a particular thread, not to the whole worker crew -*/ - -Thread_repository::Thread_repository() : - shutdown_in_progress(false) -{ - pthread_mutex_init(&LOCK_thread_repository, 0); - pthread_cond_init(&COND_thread_repository_is_empty, 0); - - /* head is used by-value to simplify nodes inserting */ - head.next= head.prev= &head; -} - - -Thread_repository::~Thread_repository() -{ - /* Check that no one uses the repository. */ - pthread_mutex_lock(&LOCK_thread_repository); - - /* All threads must unregister */ - DBUG_ASSERT(head.next == &head); - - pthread_mutex_unlock(&LOCK_thread_repository); - pthread_cond_destroy(&COND_thread_repository_is_empty); - pthread_mutex_destroy(&LOCK_thread_repository); -} - - -/* - - Set signal handler for kick-off thread, and insert a thread info to the - repository. New node is appended to the end of the list; head.prev always - points to the last node. -*/ - -void Thread_repository::register_thread(Thread_info *info) -{ - struct sigaction sa; - sa.sa_handler= handle_signal; - sa.sa_flags= 0; - sigemptyset(&sa.sa_mask); - sigaction(THREAD_KICK_OFF_SIGNAL, &sa, 0); - - info->current_cond= 0; - - pthread_mutex_lock(&LOCK_thread_repository); - info->next= &head; - info->prev= head.prev; - head.prev->next= info; - head.prev= info; - pthread_mutex_unlock(&LOCK_thread_repository); -} - - -/* - Unregister a thread from the repository and free Thread_info structure. - Every registered thread must unregister. Unregistering should be the last - thing a thread is doing, otherwise it could have no time to finalize. -*/ - -void Thread_repository::unregister_thread(Thread_info *info) -{ - pthread_mutex_lock(&LOCK_thread_repository); - info->prev->next= info->next; - info->next->prev= info->prev; - if (head.next == &head) - pthread_cond_signal(&COND_thread_repository_is_empty); - pthread_mutex_unlock(&LOCK_thread_repository); -} - - -/* - Check whether shutdown is in progress, and if yes, return immidiately. - Else set info->current_cond and call pthread_cond_wait. When - pthread_cond_wait returns, unregister current cond and check the shutdown - status again. - RETURN VALUE - return value from pthread_cond_wait -*/ - -int Thread_repository::cond_wait(Thread_info *info, pthread_cond_t *cond, - pthread_mutex_t *mutex, bool *is_shutdown) -{ - pthread_mutex_lock(&LOCK_thread_repository); - *is_shutdown= shutdown_in_progress; - if (*is_shutdown) - { - pthread_mutex_unlock(&LOCK_thread_repository); - return 0; - } - info->current_cond= cond; - pthread_mutex_unlock(&LOCK_thread_repository); - /* sic: race condition here, cond can be signaled in deliver_shutdown */ - int rc= pthread_cond_wait(cond, mutex); - pthread_mutex_lock(&LOCK_thread_repository); - info->current_cond= 0; - *is_shutdown= shutdown_in_progress; - pthread_mutex_unlock(&LOCK_thread_repository); - return rc; -} - - -/* - Deliver shutdown message to the workers crew. - As it's impossible to avoid all race conditions, we signal latecomers - again. -*/ - -void Thread_repository::deliver_shutdown() -{ - struct timespec shutdown_time; - set_timespec(shutdown_time, 1); - Thread_info *info; - - pthread_mutex_lock(&LOCK_thread_repository); - shutdown_in_progress= true; - for (info= head.next; info != &head; info= info->next) - { - pthread_kill(info->thread_id, THREAD_KICK_OFF_SIGNAL); - /* - sic: race condition here, the thread may not yet fall into - pthread_cond_wait. - */ - if (info->current_cond) - pthread_cond_signal(info->current_cond); - } - while (pthread_cond_timedwait(&COND_thread_repository_is_empty, - &LOCK_thread_repository, - &shutdown_time) != ETIMEDOUT && - head.next != &head) - ; - /* - If previous signals did not reach some threads, they must be sleeping - in pthread_cond_wait or a blocking syscall. Wake them up: - every thread shall check signal variables after each syscall/cond_wait, - so this time everybody should be informed (presumably each worker can - get CPU during shutdown_time.) - */ - for (info= head.next; info != &head; info= info->next) - { - pthread_kill(info->thread_id, THREAD_KICK_OFF_SIGNAL); - if (info->current_cond) - pthread_cond_signal(info->current_cond); - } - pthread_mutex_unlock(&LOCK_thread_repository); -} - diff --git a/server-tools/instance-manager/thread_repository.h b/server-tools/instance-manager/thread_repository.h deleted file mode 100644 index 7bd21d66e3d..00000000000 --- a/server-tools/instance-manager/thread_repository.h +++ /dev/null @@ -1,113 +0,0 @@ -#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_THREAD_REPOSITORY_HH -#define INCLUDES_MYSQL_INSTANCE_MANAGER_THREAD_REPOSITORY_HH -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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; either version 2 of the License, or - (at your option) any later version. - - 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 */ - -/* - A multi-threaded application shall nicely work with signals. - - This means it shall, first of all, shut down nicely on ``quit'' signals: - stop all running threads, cleanup and exit. - - Note, that a thread can't be shut down nicely if it doesn't want to be. - That's why to perform clean shutdown, all threads consituting a process - must observe certain rules. Here we use the rules, described in Butenhof - book 'Programming with POSIX threads', namely: - - all user signals are handled in 'signal thread' in synchronous manner - (by means of sigwait). To guarantee that the signal thread is the only who - can receive user signals, all threads block them, and signal thread is - the only who calls sigwait() with an apporpriate sigmask. - To propogate a signal to the workers the signal thread sets - a variable, corresponding to the signal. Additionally the signal thread - sends each worker an internal signal (by means of pthread_kill) to kick it - out from possible blocking syscall, and possibly pthread_cond_signal if - some thread is blocked in pthread_cond_[timed]wait. - - a worker handles only internal 'kick' signal (the handler does nothing). - In case when a syscall returns 'EINTR' the worker checks all - signal-related variables and behaves accordingly. - Also these variables shall be checked from time to time in long - CPU-bounded operations, and before/after pthread_cond_wait. (It's supposed - that a worker thread either waits in a syscall/conditional variable, or - computes something.) - - to guarantee signal deliverence, there should be some kind of feedback, - e. g. all workers shall account in the signal thread Thread Repository and - unregister from it on exit. - - Configuration reload (on SIGHUP) and thread timeouts/alarms can be handled - in manner, similar to ``quit'' signals. -*/ - -#ifdef __GNUC__ -#pragma interface -#endif - -#include <my_global.h> -#include <my_pthread.h> - - -/* - Thread_info - repository entry for each worker thread - All entries comprise double-linked list like: - 0 -- entry -- entry -- entry - 0 - Double-linked list is used to unregister threads easy. -*/ - -class Thread_info -{ - pthread_cond_t *current_cond; - Thread_info *prev, *next; - pthread_t thread_id; - Thread_info() {} - friend class Thread_repository; -public: - Thread_info(pthread_t thread_id_arg) : thread_id(thread_id_arg) {} -}; - - -/* - Thread_repository - contains handles for each worker thread to deliver - signal information to workers. -*/ - -class Thread_repository -{ -public: - Thread_repository(); - ~Thread_repository(); - - void register_thread(Thread_info *info); - void unregister_thread(Thread_info *info); - void deliver_shutdown(); - inline bool is_shutdown(); - int cond_wait(Thread_info *info, pthread_cond_t *cond, - pthread_mutex_t *mutex, bool *is_shutdown); -private: - Thread_info head; - bool shutdown_in_progress; - pthread_mutex_t LOCK_thread_repository; - pthread_cond_t COND_thread_repository_is_empty; -}; - - -inline bool Thread_repository::is_shutdown() -{ - pthread_mutex_lock(&LOCK_thread_repository); - bool res= shutdown_in_progress; - pthread_mutex_unlock(&LOCK_thread_repository); - return res; -} - -#endif // INCLUDES_MYSQL_INSTANCE_MANAGER_THREAD_REPOSITORY_HH |