diff options
author | pappa@c-4a09e253.1238-1-64736c10.cust.bredbandsbolaget.se <> | 2005-08-25 13:11:38 -0400 |
---|---|---|
committer | pappa@c-4a09e253.1238-1-64736c10.cust.bredbandsbolaget.se <> | 2005-08-25 13:11:38 -0400 |
commit | 02056f8e3ae729c06875ab63eef8680574b3d91e (patch) | |
tree | 86faf87634c19937967b360a0dd1413fc9eb2879 /server-tools | |
parent | 1c9a78438e789a70c6ee3f227c164739c4bd25e2 (diff) | |
parent | 0c859d6651277c2ee3664cb14bb34a23d048731f (diff) | |
download | mariadb-git-02056f8e3ae729c06875ab63eef8680574b3d91e.tar.gz |
Merge mronstrom@bk-internal.mysql.com:/home/bk/mysql-5.0
into c-4a09e253.1238-1-64736c10.cust.bredbandsbolaget.se:/home/pappa/mysql-5.1
Diffstat (limited to 'server-tools')
-rw-r--r-- | server-tools/instance-manager/IMService.cpp | 18 | ||||
-rw-r--r-- | server-tools/instance-manager/instance.cc | 336 | ||||
-rw-r--r-- | server-tools/instance-manager/instance.h | 4 | ||||
-rw-r--r-- | server-tools/instance-manager/instance_options.cc | 2 | ||||
-rw-r--r-- | server-tools/instance-manager/mysqlmanager.cc | 15 | ||||
-rw-r--r-- | server-tools/instance-manager/options.cc | 83 | ||||
-rw-r--r-- | server-tools/instance-manager/options.h | 2 | ||||
-rw-r--r-- | server-tools/instance-manager/protocol.cc | 2 | ||||
-rw-r--r-- | server-tools/instance-manager/user_map.cc | 17 |
9 files changed, 299 insertions, 180 deletions
diff --git a/server-tools/instance-manager/IMService.cpp b/server-tools/instance-manager/IMService.cpp index b6195d15603..e040a5da8c2 100644 --- a/server-tools/instance-manager/IMService.cpp +++ b/server-tools/instance-manager/IMService.cpp @@ -44,28 +44,28 @@ int HandleServiceOptions(Options options) if (options.install_as_service) { if (winService.IsInstalled()) - log_info("Service is already installed\n"); + log_info("Service is already installed"); else if (winService.Install()) - log_info("Service installed successfully\n"); + log_info("Service installed successfully"); else { - log_info("Service failed to install\n"); - ret_val= -1; + log_info("Service failed to install"); + ret_val= 1; } } else if (options.remove_service) { if (! winService.IsInstalled()) - log_info("Service is not installed\n"); + log_info("Service is not installed"); else if (winService.Remove()) - log_info("Service removed successfully\n"); + log_info("Service removed successfully"); else { - log_info("Service failed to remove\n"); - ret_val= -1; + log_info("Service failed to remove"); + ret_val= 1; } } else - return (int)winService.Init(); + ret_val= !winService.Init(); return ret_val; } diff --git a/server-tools/instance-manager/instance.cc b/server-tools/instance-manager/instance.cc index dee3c2d4e38..0a373429d01 100644 --- a/server-tools/instance-manager/instance.cc +++ b/server-tools/instance-manager/instance.cc @@ -36,6 +36,16 @@ #include <m_string.h> #include <mysql.h> + +static void start_and_monitor_instance(Instance_options *old_instance_options, + Instance_map *instance_map); + +#ifndef _WIN_ +typedef pid_t My_process_info; +#else +typedef PROCESS_INFORMATION My_process_info; +#endif + C_MODE_START /* @@ -48,13 +58,224 @@ C_MODE_START pthread_handler_decl(proxy, arg) { Instance *instance= (Instance *) arg; - instance->fork_and_monitor(); + start_and_monitor_instance(&instance->options, + instance->get_map()); return 0; } C_MODE_END +/* + Wait for an instance + + SYNOPSYS + 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 (linuxthreads) + 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 + + SYNOPSYS + start_process() + instance_options Pointer to the options of the instance to be + launched. + pi Pointer to the process information structure + (platform-dependent). + + RETURN + 0 - Success + 1 - Cannot create an instance +*/ + +#ifndef __WIN__ +static int start_process(Instance_options *instance_options, + My_process_info *pi) +{ + *pi= fork(); + + switch (*pi) { + case 0: + execv(instance_options->mysqld_path, instance_options->argv); + /* exec never returns */ + exit(1); + case 1: + log_info("cannot fork() to start instance %s", + instance_options->instance_name); + return 1; + } + return 0; +} +#else +static int 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= 1; instance_options->argv[i] != 0; i++) + cmdlen+= strlen(instance_options->argv[i]) + 1; + cmdlen++; /* we have to add a single space for CreateProcess (see docs) */ + + char *cmdline= NULL; + if (cmdlen > 0) + { + cmdline= new char[cmdlen]; + cmdline[0]= 0; + for (int i= 1; instance_options->argv[i] != 0; i++) + { + strcat(cmdline, " "); + strcat(cmdline, instance_options->argv[i]); + } + } + + /* Start the child process */ + BOOL result= + CreateProcess(instance_options->mysqld_path, /* File to execute */ + 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 + +/* + Fork child, exec an instance and monitor it. + + SYNOPSYS + start_and_monitor_instance() + old_instance_options Pointer to the options of the instance to be + launched. This info is likely to become obsolete + when function returns from wait_process() + instance_map Pointer to the instance_map. We use it to protect + the instance from deletion, while we are working + with it. + + DESCRIPTION + Fork a child, then exec and monitor it. When the child is dead, + find appropriate instance (for this purpose we save its name), + set appropriate flags and wake all threads waiting for instance + to stop. + + RETURN + Function returns no value +*/ + +static void start_and_monitor_instance(Instance_options *old_instance_options, + Instance_map *instance_map) +{ + enum { MAX_INSTANCE_NAME_LEN= 512 }; + char instance_name_buff[MAX_INSTANCE_NAME_LEN]; + uint instance_name_len; + Instance *current_instance; + My_process_info process_info; + + /* + Lock instance map to guarantee that no instances are deleted during + strmake() and execv() calls. + */ + instance_map->lock(); + + /* + Save the instance name in the case if Instance object we + are using is destroyed. (E.g. by "FLUSH INSTANCES") + */ + strmake(instance_name_buff, old_instance_options->instance_name, + MAX_INSTANCE_NAME_LEN - 1); + instance_name_len= old_instance_options->instance_name_len; + + log_info("starting instance %s", instance_name_buff); + + if (start_process(old_instance_options, &process_info)) + return; /* error is logged */ + + /* allow users to delete instances */ + instance_map->unlock(); + + /* don't check for return value */ + wait_process(&process_info); + + current_instance= instance_map->find(instance_name_buff, instance_name_len); + + if (current_instance) + current_instance->set_crash_flag_n_wake_all(); + + return; +} + + +Instance_map *Instance::get_map() +{ + return instance_map; +} + + void Instance::remove_pid() { int pid; @@ -65,6 +286,7 @@ void Instance::remove_pid() options.instance_name); } + /* The method starts an instance. @@ -116,107 +338,24 @@ int Instance::start() return ER_INSTANCE_ALREADY_STARTED; } -#ifndef __WIN__ -int Instance::launch_and_wait() -{ - pid_t pid= fork(); - - switch (pid) { - 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 -1; - default: - /* - 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 (linuxthreads) - wait(NULL); /* LinuxThreads were detected */ - else - waitpid(pid, NULL, 0); - } - return 0; -} -#else -int Instance::launch_and_wait() -{ - STARTUPINFO si; - PROCESS_INFORMATION pi; - - ZeroMemory(&si, sizeof(si)); - si.cb= sizeof(si); - ZeroMemory(&pi, sizeof(pi)); - - int cmdlen= 0; - for (int i= 1; options.argv[i] != 0; i++) - cmdlen+= strlen(options.argv[i]) + 1; - cmdlen++; // we have to add a single space for CreateProcess (read the docs) - - char *cmdline= NULL; - if (cmdlen > 0) - { - cmdline= new char[cmdlen]; - cmdline[0]= 0; - for (int i= 1; options.argv[i] != 0; i++) - { - strcat(cmdline, " "); - strcat(cmdline, options.argv[i]); - } - } - - // Start the child process. - BOOL result= CreateProcess(options.mysqld_path, // file to execute - 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; - if (! result) - return -1; - - // Wait until child process exits. - WaitForSingleObject(pi.hProcess, INFINITE); - - DWORD exitcode; - ::GetExitCodeProcess(pi.hProcess, &exitcode); +/* + The method sets the crash flag and wakes all waiters on + COND_instance_stopped and COND_guardian - // Close process and thread handles. - CloseHandle(pi.hProcess); - CloseHandle(pi.hThread); + SYNOPSYS + set_crash_flag_n_wake_all() - return exitcode; -} -#endif + DESCRIPTION + The method is called when an instance is crashed or terminated. + In the former case it might indicate that guardian probably should + restart it. + RETURN + Function returns no value +*/ -void Instance::fork_and_monitor() +void Instance::set_crash_flag_n_wake_all() { - log_info("starting instance %s", options.instance_name); - - if (launch_and_wait()) - return; /* error is logged */ - /* set instance state to crashed */ pthread_mutex_lock(&LOCK_instance); crashed= 1; @@ -230,11 +369,10 @@ void Instance::fork_and_monitor() pthread_cond_signal(&COND_instance_stopped); /* wake guardian */ pthread_cond_signal(&instance_map->guardian->COND_guardian); - /* thread exits */ - return; } + Instance::Instance(): crashed(0) { pthread_mutex_init(&LOCK_instance, 0); diff --git a/server-tools/instance-manager/instance.h b/server-tools/instance-manager/instance.h index 0ff5ecc179e..cbcfee0c7ef 100644 --- a/server-tools/instance-manager/instance.h +++ b/server-tools/instance-manager/instance.h @@ -41,7 +41,8 @@ public: /* send a signal to the instance */ void kill_instance(int signo); int is_crashed(); - void fork_and_monitor(); + void set_crash_flag_n_wake_all(); + Instance_map *get_map(); public: enum { DEFAULT_SHUTDOWN_DELAY= 35 }; @@ -63,7 +64,6 @@ private: Instance_map *instance_map; void remove_pid(); - int launch_and_wait(); }; #endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_INSTANCE_H */ diff --git a/server-tools/instance-manager/instance_options.cc b/server-tools/instance-manager/instance_options.cc index 0ae364e5b2d..998bf470c8d 100644 --- a/server-tools/instance-manager/instance_options.cc +++ b/server-tools/instance-manager/instance_options.cc @@ -130,6 +130,8 @@ int Instance_options::fill_instance_version() version_option, sizeof(version_option))) goto err; + bzero(result, MAX_VERSION_STRING_LENGTH); + rc= parse_output_and_get_value(cmd.buffer, mysqld_path, result, MAX_VERSION_STRING_LENGTH, GET_LINE); diff --git a/server-tools/instance-manager/mysqlmanager.cc b/server-tools/instance-manager/mysqlmanager.cc index de80878e283..a1420a639cb 100644 --- a/server-tools/instance-manager/mysqlmanager.cc +++ b/server-tools/instance-manager/mysqlmanager.cc @@ -79,6 +79,7 @@ int HandleServiceOptions(Options options); int main(int argc, char *argv[]) { + int return_value= 1; init_environment(argv[0]); Options options; struct passwd *user_info; @@ -90,10 +91,7 @@ int main(int argc, char *argv[]) if ((user_info= check_user(options.user))) { if (set_user(options.user, user_info)) - { - options.cleanup(); goto err; - } } if (options.run_as_service) @@ -105,17 +103,18 @@ int main(int argc, char *argv[]) } #else #ifdef NDEBUG - return HandleServiceOptions(options); + return_value= HandleServiceOptions(options); + goto err; /* this is not always an error but we reuse the label */ #endif #endif manager(options); - options.cleanup(); - my_end(0); - return 0; + return_value= 0; + err: + options.cleanup(); my_end(0); - return 1; + return return_value; } /******************* Auxilary functions implementation **********************/ diff --git a/server-tools/instance-manager/options.cc b/server-tools/instance-manager/options.cc index a9d31457d98..6fd11471fc6 100644 --- a/server-tools/instance-manager/options.cc +++ b/server-tools/instance-manager/options.cc @@ -30,18 +30,20 @@ #define QUOTE2(x) #x #define QUOTE(x) QUOTE2(x) -const char *default_password_file_name= QUOTE(DEFAULT_PASSWORD_FILE_NAME); -const char *default_log_file_name= QUOTE(DEFAULT_LOG_FILE_NAME); #ifdef __WIN__ -char windows_config_file[FN_REFLEN]; - char Options::install_as_service; char Options::remove_service; +char windows_config_file[FN_REFLEN]; +char default_password_file_name[FN_REFLEN]; +char default_log_file_name[FN_REFLEN]; +const char *Options::config_file= windows_config_file; #else char Options::run_as_service; const char *Options::user= 0; /* No default value */ -#endif +const char *default_password_file_name= QUOTE(DEFAULT_PASSWORD_FILE_NAME); +const char *default_log_file_name= QUOTE(DEFAULT_LOG_FILE_NAME); const char *Options::config_file= QUOTE(DEFAULT_CONFIG_FILE); +#endif const char *Options::log_file_name= default_log_file_name; const char *Options::pid_file_name= QUOTE(DEFAULT_PID_FILE_NAME); const char *Options::socket_file_name= QUOTE(DEFAULT_SOCKET_FILE_NAME); @@ -51,7 +53,7 @@ const char *Options::bind_address= 0; /* No default value */ uint Options::monitoring_interval= DEFAULT_MONITORING_INTERVAL; uint Options::port_number= DEFAULT_PORT; /* just to declare */ -char **Options::saved_argv; +char **Options::saved_argv= NULL; /* List of options, accepted by the instance manager. @@ -262,30 +264,8 @@ int Options::load(int argc, char **argv) } #ifdef __WIN__ - setup_windows_defaults(*argv); - - /* - On Windows, there are two possibilities. Either we are given - a defaults file on the command line or we use the my.ini file - that is in our app dir - */ - if (Options::config_file == NULL) - { - char *filename; - static const char default_win_config_file_name[]= "\\my.ini"; - - if (!GetModuleFileName(NULL, windows_config_file, - sizeof(windows_config_file))) - goto err; - - filename= strrchr(windows_config_file, "\\"); - /* - Don't check for the overflow as strlen("\\my.ini") is less - then strlen("mysqlmanager") (the binary name) - */ - strcpy(filename, default_win_config_file_name); - Options::config_file= windows_config_file; - } + if (setup_windows_defaults()) + goto err; #endif /* config-file options are prepended to command-line ones */ @@ -305,33 +285,32 @@ err: void Options::cleanup() { /* free_defaults returns nothing */ - free_defaults(Options::saved_argv); -#ifdef __WIN__ - free((char*)default_password_file_name); -#endif + if (Options::saved_argv != NULL) + free_defaults(Options::saved_argv); } #ifdef __WIN__ -char* change_extension(const char *src, const char *newext) +int Options::setup_windows_defaults() { - char *dot= (char*)strrchr(src, '.'); - if (!dot) return (char*)src; - - int newlen= dot-src+strlen(newext)+1; - char *temp= (char*)malloc(newlen); - bzero(temp, newlen); - strncpy(temp, src, dot-src+1); - strcat(temp, newext); - return temp; -} - -void Options::setup_windows_defaults(const char *progname) -{ - Options::password_file_name= default_password_file_name= - change_extension(progname, "passwd"); - Options::log_file_name= default_log_file_name= - change_extension(progname, "log"); + if (!GetModuleFileName(NULL, default_password_file_name, + sizeof(default_password_file_name))) + return 1; + char *filename= strstr(default_password_file_name, ".exe"); + strcpy(filename, ".passwd"); + + if (!GetModuleFileName(NULL, default_log_file_name, + sizeof(default_log_file_name))) + return 1; + filename= strstr(default_log_file_name, ".exe"); + strcpy(filename, ".log"); + + if (!GetModuleFileName(NULL, windows_config_file, + sizeof(windows_config_file))) + return 1; + char *slash= strrchr(windows_config_file, '\\'); + strcpy(slash, "\\my.ini"); + return 0; } #endif diff --git a/server-tools/instance-manager/options.h b/server-tools/instance-manager/options.h index 537316fedfc..5cc14e7ee7f 100644 --- a/server-tools/instance-manager/options.h +++ b/server-tools/instance-manager/options.h @@ -52,7 +52,7 @@ struct Options int load(int argc, char **argv); void cleanup(); #ifdef __WIN__ - void setup_windows_defaults(const char *progname); + int setup_windows_defaults(const char *progname); #endif }; diff --git a/server-tools/instance-manager/protocol.cc b/server-tools/instance-manager/protocol.cc index 4b46d091c3f..cd1be805b6b 100644 --- a/server-tools/instance-manager/protocol.cc +++ b/server-tools/instance-manager/protocol.cc @@ -203,7 +203,7 @@ int send_fields(struct st_net *net, LIST *fields) position+= 12; if (my_net_write(net, send_buff.buffer, (uint) position+1)) goto err; - tmp= rest(tmp); + tmp= list_rest(tmp); } if (my_net_write(net, eof_buff, 1)) diff --git a/server-tools/instance-manager/user_map.cc b/server-tools/instance-manager/user_map.cc index 1498f2fa947..4e47127bba1 100644 --- a/server-tools/instance-manager/user_map.cc +++ b/server-tools/instance-manager/user_map.cc @@ -25,12 +25,6 @@ #include "log.h" -#ifdef __WIN__ -#define NEWLINE_LEN 2 -#else -#define NEWLINE_LEN 1 -#endif - struct User { char user[USERNAME_LENGTH + 1]; @@ -43,6 +37,7 @@ struct User int User::init(const char *line) { const char *name_begin, *name_end, *password; + int line_ending_len= 1; if (line[0] == '\'' || line[0] == '"') { @@ -64,8 +59,14 @@ int User::init(const char *line) if (user_length > USERNAME_LENGTH) goto err; - /* assume that newline characater is present */ - if (strlen(password) != SCRAMBLED_PASSWORD_CHAR_LENGTH + NEWLINE_LEN) + /* + assume that newline characater is present + we support reading password files that end in \n or \r\n on + either platform. + */ + if (password[strlen(password)-2] == '\r') + line_ending_len= 2; + if (strlen(password) != SCRAMBLED_PASSWORD_CHAR_LENGTH + line_ending_len) goto err; memcpy(user, name_begin, user_length); |