Commit dce2554f authored by unknown's avatar unknown

Post-review fixes + some bugs fixed + several minor features


BitKeeper/deleted/.del-client_func.c~3476a8a85cbd3c29:
  Delete: server-tools/instance-manager/client_func.c
server-tools/instance-manager/Makefile.am:
  clien_func removed
server-tools/instance-manager/buffer.cc:
  several methods added
server-tools/instance-manager/buffer.h:
  Some error-handling fixes.
server-tools/instance-manager/commands.cc:
  check for Buffer errors
server-tools/instance-manager/guardian.cc:
  Guardian rewiriten. Not it works in a finite state machine-way.
server-tools/instance-manager/guardian.h:
  Appropriate (to .cc) changes in the header + some comment added
server-tools/instance-manager/instance.cc:
  added proxy thread to monitor instance. Two kinds of stop() now -- stop() and kill_instance which
  only sends a signal
server-tools/instance-manager/instance.h:
  appropriate changes
server-tools/instance-manager/instance_map.cc:
  cleanup
server-tools/instance-manager/instance_map.h:
  cleanup
server-tools/instance-manager/instance_options.cc:
  Caching of the pid-file-name is added. some comments added
server-tools/instance-manager/instance_options.h:
  cleanup
server-tools/instance-manager/listener.cc:
  listener my_thread_init added (though it doesn't use any mysys functions). Just in case
server-tools/instance-manager/manager.cc:
  SIGCHLD handler removed. now instance monitoring is implemented through proxy threads. This is to work nicely
  with LinuxThreads
server-tools/instance-manager/options.cc:
  added option to create a password file entry (this was implemented by Sergei Vojtovich)
server-tools/instance-manager/parse.cc:
  inline function get_word moved to the header
server-tools/instance-manager/parse.h:
  get_word moved here to use form parse_output
server-tools/instance-manager/parse_output.cc:
  get_word() clone removed. now looking through the output linewise
server-tools/instance-manager/protocol.cc:
  Buffer error chech added
server-tools/instance-manager/user_map.cc:
  typo fixed
parent 79ba407d
...@@ -74,7 +74,7 @@ mysqlmanager_SOURCES= command.cc command.h mysqlmanager.cc \ ...@@ -74,7 +74,7 @@ mysqlmanager_SOURCES= command.cc command.h mysqlmanager.cc \
buffer.h buffer.cc parse.cc parse.h \ buffer.h buffer.cc parse.cc parse.h \
guardian.cc guardian.h \ guardian.cc guardian.h \
parse_output.cc parse_output.h \ parse_output.cc parse_output.h \
mysql_manager_error.h client_func.c mysql_manager_error.h
mysqlmanager_LDADD= liboptions.a \ mysqlmanager_LDADD= liboptions.a \
libnet.a \ libnet.a \
......
...@@ -40,7 +40,7 @@ ...@@ -40,7 +40,7 @@
RETURN RETURN
0 - ok 0 - ok
1 - The buffer came to 16Mb barrier 1 - got an error in reserve()
*/ */
int Buffer::append(uint position, const char *string, uint len_arg) int Buffer::append(uint position, const char *string, uint len_arg)
...@@ -71,7 +71,7 @@ int Buffer::append(uint position, const char *string, uint len_arg) ...@@ -71,7 +71,7 @@ int Buffer::append(uint position, const char *string, uint len_arg)
RETURN RETURN
0 - ok 0 - ok
1 - The buffer came to 16Mb barrier 1 - realloc error or we have come to the 16Mb barrier
*/ */
int Buffer::reserve(uint position, uint len_arg) int Buffer::reserve(uint position, uint len_arg)
...@@ -92,6 +92,18 @@ int Buffer::reserve(uint position, uint len_arg) ...@@ -92,6 +92,18 @@ int Buffer::reserve(uint position, uint len_arg)
return 0; return 0;
err: err:
error= 1;
return 1; return 1;
} }
int Buffer::get_size()
{
return buffer_size;
}
int Buffer::is_error()
{
return error;
}
...@@ -36,11 +36,17 @@ class Buffer ...@@ -36,11 +36,17 @@ class Buffer
/* maximum buffer size is 16Mb */ /* maximum buffer size is 16Mb */
enum { MAX_BUFFER_SIZE= 16777216 }; enum { MAX_BUFFER_SIZE= 16777216 };
size_t buffer_size; size_t buffer_size;
/* Error flag. Triggered if we get an error of some kind */
int error;
public: public:
Buffer() Buffer(size_t buffer_size_arg= BUFFER_INITIAL_SIZE)
:buffer_size(BUFFER_INITIAL_SIZE), error(0)
{ {
buffer=(char *) malloc(BUFFER_INITIAL_SIZE); /*
buffer_size= BUFFER_INITIAL_SIZE; As append() will invokes realloc() anyway, it's ok if malloc returns 0
*/
if (!(buffer= (char*) malloc(buffer_size)))
buffer_size= 0;
} }
~Buffer() ~Buffer()
...@@ -50,6 +56,8 @@ class Buffer ...@@ -50,6 +56,8 @@ class Buffer
public: public:
char *buffer; char *buffer;
int get_size();
int is_error();
int append(uint position, const char *string, uint len_arg); int append(uint position, const char *string, uint len_arg);
int reserve(uint position, uint len_arg); int reserve(uint position, uint len_arg);
}; };
......
#include <my_global.h>
#include <my_sys.h>
#include <mysql.h>
/*
Currently we cannot use libmysqlclient directly because of the linking
issues. Here we provide needed libmysqlclient functions.
TODO: to think how to use libmysqlclient code instead of copy&paste.
The other possible solution is to use simple_command directly.
*/
const char * STDCALL
mysql_get_server_info(MYSQL *mysql)
{
return((char*) mysql->server_version);
}
int STDCALL
mysql_ping(MYSQL *mysql)
{
DBUG_ENTER("mysql_ping");
DBUG_RETURN(simple_command(mysql,COM_PING,0,0,0));
}
int STDCALL
mysql_shutdown(MYSQL *mysql, enum mysql_enum_shutdown_level shutdown_level)
{
uchar level[1];
DBUG_ENTER("mysql_shutdown");
level[0]= (uchar) shutdown_level;
DBUG_RETURN(simple_command(mysql, COM_SHUTDOWN, (char *)level, 1, 0));
}
...@@ -184,7 +184,8 @@ int Show_instance_status::do_command(struct st_net *net, ...@@ -184,7 +184,8 @@ int Show_instance_status::do_command(struct st_net *net,
} }
if (my_net_write(net, send_buff.buffer, (uint) position)) if (my_net_write(net, send_buff.buffer, (uint) position) ||
send_buff.is_error())
goto err; goto err;
} }
...@@ -270,7 +271,8 @@ int Show_instance_options::do_command(struct st_net *net, ...@@ -270,7 +271,8 @@ int Show_instance_options::do_command(struct st_net *net,
store_to_string(&send_buff, store_to_string(&send_buff,
(char *) instance->options.mysqld_path, (char *) instance->options.mysqld_path,
&position); &position);
if (my_net_write(net, send_buff.buffer, (uint) position)) if (my_net_write(net, send_buff.buffer, (uint) position) ||
send_buff.is_error())
goto err; goto err;
} }
...@@ -279,7 +281,8 @@ int Show_instance_options::do_command(struct st_net *net, ...@@ -279,7 +281,8 @@ int Show_instance_options::do_command(struct st_net *net,
position= 0; position= 0;
store_to_string(&send_buff, (char *) "nonguarded", &position); store_to_string(&send_buff, (char *) "nonguarded", &position);
store_to_string(&send_buff, "", &position); store_to_string(&send_buff, "", &position);
if (my_net_write(net, send_buff.buffer, (uint) position)) if (my_net_write(net, send_buff.buffer, (uint) position) ||
send_buff.is_error())
goto err; goto err;
} }
...@@ -296,7 +299,8 @@ int Show_instance_options::do_command(struct st_net *net, ...@@ -296,7 +299,8 @@ int Show_instance_options::do_command(struct st_net *net,
store_to_string(&send_buff, option_value + 1, &position); store_to_string(&send_buff, option_value + 1, &position);
/* join name and the value into the same option again */ /* join name and the value into the same option again */
*option_value= '='; *option_value= '=';
if (my_net_write(net, send_buff.buffer, (uint) position)) if (my_net_write(net, send_buff.buffer, (uint) position) ||
send_buff.is_error())
goto err; goto err;
} }
} }
......
This diff is collapsed.
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <my_global.h> #include <my_global.h>
#include <my_sys.h> #include <my_sys.h>
#include <my_list.h> #include <my_list.h>
#include "thread_registry.h"
#ifdef __GNUC__ #ifdef __GNUC__
#pragma interface #pragma interface
...@@ -26,9 +27,8 @@ ...@@ -26,9 +27,8 @@
class Instance; class Instance;
class Instance_map; class Instance_map;
class Thread_registry;
#include "thread_registry.h" struct GUARD_NODE;
#include "instance.h"
C_MODE_START C_MODE_START
...@@ -36,19 +36,11 @@ pthread_handler_decl(guardian, arg); ...@@ -36,19 +36,11 @@ pthread_handler_decl(guardian, arg);
C_MODE_END C_MODE_END
typedef struct st_guard_node
{
Instance *instance;
uint restart_counter;
time_t crash_moment;
} GUARD_NODE;
struct Guardian_thread_args struct Guardian_thread_args
{ {
Thread_registry &thread_registry; Thread_registry &thread_registry;
Instance_map *instance_map; Instance_map *instance_map;
uint monitoring_interval; int monitoring_interval;
Guardian_thread_args(Thread_registry &thread_registry_arg, Guardian_thread_args(Thread_registry &thread_registry_arg,
Instance_map *instance_map_arg, Instance_map *instance_map_arg,
...@@ -72,36 +64,41 @@ class Guardian_thread: public Guardian_thread_args ...@@ -72,36 +64,41 @@ class Guardian_thread: public Guardian_thread_args
Instance_map *instance_map_arg, Instance_map *instance_map_arg,
uint monitoring_interval_arg); uint monitoring_interval_arg);
~Guardian_thread(); ~Guardian_thread();
/* Main funtion of the thread */
void run(); void run();
int start(); /* Initialize list of guarded instances */
void shutdown(); int init();
void request_stop_instances(); /* Request guardian shutdown. Stop instances if needed */
void request_shutdown(bool stop_instances);
/* Start instance protection */
int guard(Instance *instance); int guard(Instance *instance);
/* Stop instance protection */
int stop_guard(Instance *instance); int stop_guard(Instance *instance);
bool is_stopped; /* Returns true if guardian thread is stopped */
int is_stopped();
public: public:
pthread_cond_t COND_guardian; pthread_cond_t COND_guardian;
private: private:
int stop_instances(); /* Prepares Guardian shutdown. Stops instances is needed */
int add_instance_to_list(Instance *instance, LIST **list); int stop_instances(bool stop_instances_arg);
void move_to_list(LIST **from, LIST **to); /* check instance state and act accordingly */
void process_instance(Instance *instance, GUARD_NODE *current_node,
LIST **guarded_instances, LIST *elem);
int stopped;
private: private:
/* states of an instance */
enum { NOT_STARTED= 1, STARTING, STARTED, JUST_CRASHED, CRASHED,
CRASHED_AND_ABANDONED, STOPPING };
pthread_mutex_t LOCK_guardian; pthread_mutex_t LOCK_guardian;
Thread_info thread_info; Thread_info thread_info;
LIST *guarded_instances; LIST *guarded_instances;
LIST *starting_instances;
MEM_ROOT alloc; MEM_ROOT alloc;
enum { MEM_ROOT_BLOCK_SIZE= 512 }; enum { MEM_ROOT_BLOCK_SIZE= 512 };
/* this variable is set to TRUE when we want to stop Guardian thread */ /* this variable is set to TRUE when we want to stop Guardian thread */
bool shutdown_guardian; bool shutdown_requested;
/*
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 */ #endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_GUARDIAN_H */
...@@ -27,6 +27,19 @@ ...@@ -27,6 +27,19 @@
#include <m_string.h> #include <m_string.h>
#include <sys/wait.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. The method starts an instance.
...@@ -44,6 +57,12 @@ int Instance::start() ...@@ -44,6 +57,12 @@ int Instance::start()
{ {
pid_t pid; pid_t pid;
/* clear crash flag */
pthread_mutex_lock(&LOCK_instance);
crashed= 0;
pthread_mutex_unlock(&LOCK_instance);
if (!is_running()) if (!is_running())
{ {
if ((pid= options.get_pid()) != 0) /* check the pidfile */ if ((pid= options.get_pid()) != 0) /* check the pidfile */
...@@ -52,6 +71,36 @@ int Instance::start() ...@@ -52,6 +71,36 @@ int Instance::start()
since IM lacks permmissions or hasn't found the pidifle", since IM lacks permmissions or hasn't found the pidifle",
options.instance_name); 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;
}
return 0;
}
/* the instance is started already */
return ER_INSTANCE_ALREADY_STARTED;
}
void Instance::fork_and_monitor()
{
pid_t pid;
log_info("starting instance %s", options.instance_name); log_info("starting instance %s", options.instance_name);
switch (pid= fork()) { switch (pid= fork()) {
case 0: case 0:
...@@ -59,20 +108,52 @@ int Instance::start() ...@@ -59,20 +108,52 @@ int Instance::start()
/* exec never returns */ /* exec never returns */
exit(1); exit(1);
case -1: case -1:
return ER_CANNOT_START_INSTANCE; log_info("cannot fork() to start instance %s", options.instance_name);
return;
default: default:
return 0; 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);
}
/* the instance is started already */
return ER_INSTANCE_ALREADY_STARTED; Instance::Instance(): crashed(0)
{
pthread_mutex_init(&LOCK_instance, 0);
pthread_cond_init(&COND_instance_restarted, 0);
} }
Instance::~Instance() Instance::~Instance()
{ {
pthread_mutex_destroy(&LOCK_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;
} }
...@@ -95,20 +176,19 @@ bool Instance::is_running() ...@@ -95,20 +176,19 @@ bool Instance::is_running()
pthread_mutex_lock(&LOCK_instance); pthread_mutex_lock(&LOCK_instance);
mysql_init(&mysql); mysql_init(&mysql);
/* try to connect to a server with the fake username/password pair */ /* try to connect to a server with a fake username/password pair */
if (mysql_real_connect(&mysql, LOCAL_HOST, username, if (mysql_real_connect(&mysql, LOCAL_HOST, username,
password, password,
NullS, port, NullS, port,
socket, 0)) socket, 0))
{ {
/* /*
Very strange. We have successfully connected to the server using We have successfully connected to the server using fake
bullshit as username/password. Write a warning to the logfile. username/password. Write a warning to the logfile.
*/ */
log_info("The Instance Manager was able to log into you server \ log_info("The Instance Manager was able to log into you server \
with faked compiled-in password while checking server status. \ with faked compiled-in password while checking server status. \
Looks like something is wrong."); Looks like something is wrong.");
mysql_close(&mysql);
pthread_mutex_unlock(&LOCK_instance); pthread_mutex_unlock(&LOCK_instance);
return_val= TRUE; /* server is alive */ return_val= TRUE; /* server is alive */
} }
...@@ -151,53 +231,30 @@ int Instance::stop() ...@@ -151,53 +231,30 @@ int Instance::stop()
if (options.shutdown_delay != NULL) if (options.shutdown_delay != NULL)
waitchild= atoi(options.shutdown_delay); waitchild= atoi(options.shutdown_delay);
if ((pid= options.get_pid()) != 0) /* get pid from pidfile */ kill_instance(SIGTERM);
{
/*
If we cannot kill mysqld, then it has propably crashed.
Let us try to remove staled pidfile and return succes as mysqld
is probably stopped
*/
if (kill(pid, SIGTERM))
{
if (options.unlink_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);
return 0;
}
/* sleep on condition to wait for SIGCHLD */ /* sleep on condition to wait for SIGCHLD */
timeout.tv_sec= time(NULL) + waitchild; timeout.tv_sec= time(NULL) + waitchild;
timeout.tv_nsec= 0; timeout.tv_nsec= 0;
if (pthread_mutex_lock(&instance_map->pid_cond.LOCK_pid)) if (pthread_mutex_lock(&LOCK_instance))
goto err; /* perhaps this should be procecced differently */ goto err;
while (options.get_pid() != 0) /* while server isn't stopped */ while (options.get_pid() != 0) /* while server isn't stopped */
{ {
int status; int status;
status= pthread_cond_timedwait(&instance_map->pid_cond.COND_pid, status= pthread_cond_timedwait(&COND_instance_restarted,
&instance_map->pid_cond.LOCK_pid, &LOCK_instance,
&timeout); &timeout);
if (status == ETIMEDOUT) if (status == ETIMEDOUT)
break; break;
} }
pthread_mutex_unlock(&instance_map->pid_cond.LOCK_pid); pthread_mutex_unlock(&LOCK_instance);
if (!kill(pid, SIGKILL)) kill_instance(SIGKILL);
{
log_error("The instance %s has been stopped forsibly. Normally \
it should not happed. Probably the instance has been \
hanging. You should also check your IM setup",
options.instance_name);
}
return 0; return 0;
}
return ER_INSTANCE_IS_NOT_STARTED; return ER_INSTANCE_IS_NOT_STARTED;
err: err:
...@@ -205,6 +262,29 @@ int Instance::stop() ...@@ -205,6 +262,29 @@ int Instance::stop()
} }
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. We execute this function to initialize instance parameters.
Return value: 0 - ok. 1 - unable to init DYNAMIC_ARRAY. Return value: 0 - ok. 1 - unable to init DYNAMIC_ARRAY.
...@@ -212,8 +292,6 @@ int Instance::stop() ...@@ -212,8 +292,6 @@ int Instance::stop()
int Instance::init(const char *name_arg) int Instance::init(const char *name_arg)
{ {
pthread_mutex_init(&LOCK_instance, 0);
return options.init(name_arg); return options.init(name_arg);
} }
......
...@@ -30,14 +30,19 @@ class Instance_map; ...@@ -30,14 +30,19 @@ class Instance_map;
class Instance class Instance
{ {
public: public:
Instance();
~Instance(); ~Instance();
int init(const char *name); int init(const char *name);
int complete_initialization(Instance_map *instance_map_arg); int complete_initialization(Instance_map *instance_map_arg);
/* check if the instance is running and set up mysql connection if yes */
bool is_running(); bool is_running();
int start(); int start();
int stop(); int stop();
/* send a signal to the instance */
void kill_instance(int signo);
int is_crashed();
void fork_and_monitor();
public: public:
enum { DEFAULT_SHUTDOWN_DELAY= 35 }; enum { DEFAULT_SHUTDOWN_DELAY= 35 };
...@@ -49,7 +54,9 @@ class Instance ...@@ -49,7 +54,9 @@ class Instance
double start of the instance. This happens when the instance is starting double start of the instance. This happens when the instance is starting
and we issue the start command once more. and we issue the start command once more.
*/ */
int crashed;
pthread_mutex_t LOCK_instance; pthread_mutex_t LOCK_instance;
pthread_cond_t COND_instance_restarted;
Instance_map *instance_map; Instance_map *instance_map;
}; };
......
...@@ -120,9 +120,6 @@ Instance_map::Instance_map(const char *default_mysqld_path_arg) ...@@ -120,9 +120,6 @@ Instance_map::Instance_map(const char *default_mysqld_path_arg)
int Instance_map::init() int Instance_map::init()
{ {
pthread_mutex_init(&pid_cond.LOCK_pid, 0);
pthread_cond_init(&pid_cond.COND_pid, 0);
if (hash_init(&hash, default_charset_info, START_HASH_SIZE, 0, 0, if (hash_init(&hash, default_charset_info, START_HASH_SIZE, 0, 0,
get_instance_key, delete_instance, 0)) get_instance_key, delete_instance, 0))
return 1; return 1;
...@@ -135,8 +132,6 @@ Instance_map::~Instance_map() ...@@ -135,8 +132,6 @@ Instance_map::~Instance_map()
hash_free(&hash); hash_free(&hash);
pthread_mutex_unlock(&LOCK_instance_map); pthread_mutex_unlock(&LOCK_instance_map);
pthread_mutex_destroy(&LOCK_instance_map); pthread_mutex_destroy(&LOCK_instance_map);
pthread_mutex_destroy(&pid_cond.LOCK_pid);
pthread_cond_destroy(&pid_cond.COND_pid);
} }
...@@ -198,21 +193,6 @@ void Instance_map::complete_initialization() ...@@ -198,21 +193,6 @@ void Instance_map::complete_initialization()
} }
Instance *
Instance_map::find(uint instance_number)
{
Instance *instance;
char name[80];
snprintf(name, sizeof(name) - 1, "mysqld%i", instance_number);
name[sizeof(name) - 1]= 0; /* safety */
pthread_mutex_lock(&LOCK_instance_map);
instance= (Instance *) hash_search(&hash, (byte *) name, strlen(name));
pthread_mutex_unlock(&LOCK_instance_map);
return instance;
}
/* load options from config files and create appropriate instance structures */ /* load options from config files and create appropriate instance structures */
int Instance_map::load() int Instance_map::load()
......
...@@ -27,12 +27,6 @@ ...@@ -27,12 +27,6 @@
#include "protocol.h" #include "protocol.h"
#include "guardian.h" #include "guardian.h"
typedef struct st_instance_cond
{
pthread_mutex_t LOCK_pid;
pthread_cond_t COND_pid;
} CHILD_COND;
class Instance; class Instance;
extern int load_all_groups(char ***groups, const char *filename); extern int load_all_groups(char ***groups, const char *filename);
extern void free_groups(char **groups); extern void free_groups(char **groups);
...@@ -83,8 +77,6 @@ class Instance_map ...@@ -83,8 +77,6 @@ class Instance_map
public: public:
const char *mysqld_path; const char *mysqld_path;
Guardian_thread *guardian; Guardian_thread *guardian;
/* structure used for syncronization reasons in the stop command */
CHILD_COND pid_cond;
private: private:
enum { START_HASH_SIZE = 16 }; enum { START_HASH_SIZE = 16 };
......
...@@ -27,25 +27,50 @@ ...@@ -27,25 +27,50 @@
#include <m_string.h> #include <m_string.h>
/* option_name should be prefixed with "--" */ /*
int Instance_options::get_default_option(char *result, const char *option_name, Get compiled-in value of default_option
size_t result_len)
SYNOPSYS
get_default_option()
result buffer to put found value
result_len buffer size
oprion_name the name of the option, prefixed with "--"
DESCRIPTION
Get compile-in value of requested option from server
RETURN
0 - ok
1 - error occured
*/
int Instance_options::get_default_option(char *result, size_t result_len,
const char *option_name)
{ {
int position= 0; int position= 0;
int rc= 1;
char verbose_option[]= " --no-defaults --verbose --help"; char verbose_option[]= " --no-defaults --verbose --help";
Buffer cmd;
Buffer cmd(strlen(mysqld_path)+sizeof(verbose_option)+1);
if (cmd.get_size()) /* malloc succeeded */
{
cmd.append(position, mysqld_path, strlen(mysqld_path)); cmd.append(position, mysqld_path, strlen(mysqld_path));
position+= strlen(mysqld_path); position+= strlen(mysqld_path);
cmd.append(position, verbose_option, sizeof(verbose_option) - 1); cmd.append(position, verbose_option, sizeof(verbose_option) - 1);
position+= sizeof(verbose_option) - 1; position+= sizeof(verbose_option) - 1;
cmd.append(position, "\0", 1); cmd.append(position, "\0", 1);
if (cmd.is_error())
goto err;
/* get the value from "mysqld --help --verbose" */ /* get the value from "mysqld --help --verbose" */
if (parse_output_and_get_value(cmd.buffer, option_name + 2, rc= parse_output_and_get_value(cmd.buffer, option_name + 2,
result, result_len)) result, result_len);
return 1; }
return 0; return rc;
err:
return 1;
} }
...@@ -56,50 +81,32 @@ void Instance_options::get_pid_filename(char *result) ...@@ -56,50 +81,32 @@ void Instance_options::get_pid_filename(char *result)
if (mysqld_datadir == NULL) if (mysqld_datadir == NULL)
{ {
get_default_option(datadir, "--datadir", MAX_PATH_LEN); get_default_option(datadir, sizeof(datadir), "--datadir");
} }
else else
strxnmov(datadir, MAX_PATH_LEN - 1, strchr(mysqld_datadir, '=') + 1, strxnmov(datadir, MAX_PATH_LEN - 1, strchr(mysqld_datadir, '=') + 1,
"/", NullS); "/", NullS);
/* well, we should never get it */ DBUG_ASSERT(mysqld_pid_file);
if (mysqld_pid_file != NULL)
pid_file= strchr(pid_file, '=') + 1; pid_file= strchr(pid_file, '=') + 1;
else
DBUG_ASSERT(0);
/* get the full path to the pidfile */ /* get the full path to the pidfile */
my_load_path(result, pid_file, datadir); my_load_path(result, pid_file, datadir);
} }
int Instance_options::unlink_pidfile() int Instance_options::unlink_pidfile()
{ {
char pid_file_path[MAX_PATH_LEN]; return unlink(pid_file_with_path);
/*
This works as we know that pid_file_path is of
MAX_PATH_LEN == FN_REFLEN length
*/
get_pid_filename((char *)&pid_file_path);
return unlink(pid_file_path);
} }
pid_t Instance_options::get_pid() pid_t Instance_options::get_pid()
{ {
char pid_file_path[MAX_PATH_LEN]; FILE *pid_file_stream;
/*
This works as we know that pid_file_path is of
MAX_PATH_LEN == FN_REFLEN length
*/
get_pid_filename((char *)&pid_file_path);
/* get the pid */ /* get the pid */
if (FILE *pid_file_stream= my_fopen(pid_file_path, if (pid_file_stream= my_fopen(pid_file_with_path,
O_RDONLY | O_BINARY, MYF(0))) O_RDONLY | O_BINARY, MYF(0)))
{ {
pid_t pid; pid_t pid;
...@@ -140,6 +147,8 @@ int Instance_options::complete_initialization(const char *default_path) ...@@ -140,6 +147,8 @@ int Instance_options::complete_initialization(const char *default_path)
add_option(pidfilename); add_option(pidfilename);
} }
get_pid_filename(pid_file_with_path);
/* we need to reserve space for the final zero + possible default options */ /* we need to reserve space for the final zero + possible default options */
if (!(argv= (char**) alloc_root(&alloc, (options_array.elements + 1 if (!(argv= (char**) alloc_root(&alloc, (options_array.elements + 1
+ MAX_NUMBER_OF_DEFAULT_OPTIONS) * sizeof(char*)))) + MAX_NUMBER_OF_DEFAULT_OPTIONS) * sizeof(char*))))
...@@ -244,6 +253,8 @@ int Instance_options::add_to_argv(const char* option) ...@@ -244,6 +253,8 @@ int Instance_options::add_to_argv(const char* option)
return 0; return 0;
} }
/* function for debug purposes */
void Instance_options::print_argv() void Instance_options::print_argv()
{ {
int i; int i;
......
...@@ -39,7 +39,7 @@ class Instance_options ...@@ -39,7 +39,7 @@ class Instance_options
Instance_options() : Instance_options() :
mysqld_socket(0), mysqld_datadir(0), mysqld_bind_address(0), mysqld_socket(0), mysqld_datadir(0), mysqld_bind_address(0),
mysqld_pid_file(0), mysqld_port(0), mysqld_path(0), nonguarded(0), mysqld_pid_file(0), mysqld_port(0), mysqld_path(0), nonguarded(0),
filled_default_options(0) shutdown_delay(0), filled_default_options(0)
{} {}
~Instance_options(); ~Instance_options();
/* fills in argv */ /* fills in argv */
...@@ -60,6 +60,7 @@ class Instance_options ...@@ -60,6 +60,7 @@ class Instance_options
enum { MAX_PATH_LEN= 512 }; enum { MAX_PATH_LEN= 512 };
enum { MAX_NUMBER_OF_DEFAULT_OPTIONS= 2 }; enum { MAX_NUMBER_OF_DEFAULT_OPTIONS= 2 };
enum { MEM_ROOT_BLOCK_SIZE= 512 }; enum { MEM_ROOT_BLOCK_SIZE= 512 };
char pid_file_with_path[MAX_PATH_LEN];
char **argv; char **argv;
/* We need the some options, so we store them as a separate pointers */ /* We need the some options, so we store them as a separate pointers */
const char *mysqld_socket; const char *mysqld_socket;
...@@ -72,11 +73,12 @@ class Instance_options ...@@ -72,11 +73,12 @@ class Instance_options
const char *mysqld_path; const char *mysqld_path;
const char *nonguarded; const char *nonguarded;
const char *shutdown_delay; const char *shutdown_delay;
/* this value is computed and cashed here */
DYNAMIC_ARRAY options_array; DYNAMIC_ARRAY options_array;
private: private:
int add_to_argv(const char *option); int add_to_argv(const char *option);
int get_default_option(char *result, const char *option_name, int get_default_option(char *result, size_t result_len,
size_t result_len); const char *option_name);
private: private:
uint filled_default_options; uint filled_default_options;
MEM_ROOT alloc; MEM_ROOT alloc;
......
...@@ -85,6 +85,8 @@ void Listener_thread::run() ...@@ -85,6 +85,8 @@ void Listener_thread::run()
thread_registry.register_thread(&thread_info); thread_registry.register_thread(&thread_info);
my_thread_init();
/* I. prepare 'listen' sockets */ /* I. prepare 'listen' sockets */
int ip_socket= socket(AF_INET, SOCK_STREAM, 0); int ip_socket= socket(AF_INET, SOCK_STREAM, 0);
...@@ -263,11 +265,13 @@ void Listener_thread::run() ...@@ -263,11 +265,13 @@ void Listener_thread::run()
unlink(unix_socket_address.sun_path); unlink(unix_socket_address.sun_path);
thread_registry.unregister_thread(&thread_info); thread_registry.unregister_thread(&thread_info);
my_thread_end();
return; return;
err: err:
thread_registry.unregister_thread(&thread_info); thread_registry.unregister_thread(&thread_info);
thread_registry.request_shutdown(); thread_registry.request_shutdown();
my_thread_end();
return; return;
} }
......
...@@ -90,7 +90,6 @@ void manager(const Options &options) ...@@ -90,7 +90,6 @@ void manager(const Options &options)
sigemptyset(&mask); sigemptyset(&mask);
sigaddset(&mask, SIGINT); sigaddset(&mask, SIGINT);
sigaddset(&mask, SIGTERM); sigaddset(&mask, SIGTERM);
sigaddset(&mask, SIGCHLD);
sigaddset(&mask, SIGPIPE); sigaddset(&mask, SIGPIPE);
sigaddset(&mask, SIGHUP); sigaddset(&mask, SIGHUP);
/* /*
...@@ -128,7 +127,7 @@ void manager(const Options &options) ...@@ -128,7 +127,7 @@ void manager(const Options &options)
int rc; int rc;
/* /*
NOTE: Guardian should be shutdowned first. Only then all other threads NOTE: Guardian should be shutdown first. Only then all other threads
need to be stopped. This should be done, as guardian is responsible for need to be stopped. This should be done, as guardian is responsible for
shutting down the instances, and this is a long operation. shutting down the instances, and this is a long operation.
*/ */
...@@ -160,12 +159,8 @@ void manager(const Options &options) ...@@ -160,12 +159,8 @@ void manager(const Options &options)
more then 10 alarms at the same time. more then 10 alarms at the same time.
*/ */
init_thr_alarm(10); init_thr_alarm(10);
/* /* init list of guarded instances */
Now we can init the list of guarded instances. We have to do it after guardian_thread.init();
alarm structures initialization as we have to use net_* functions while
making the list. And they in their turn need alarms for timeout suppport.
*/
guardian_thread.start();
/* /*
After the list of guarded instances have been initialized, After the list of guarded instances have been initialized,
Guardian should start them. Guardian should start them.
...@@ -182,18 +177,12 @@ void manager(const Options &options) ...@@ -182,18 +177,12 @@ void manager(const Options &options)
case THR_SERVER_ALARM: case THR_SERVER_ALARM:
process_alarm(signo); process_alarm(signo);
break; break;
case SIGCHLD:
wait(NULL);
/* wake threads waiting for an instance to shutdown */
pthread_cond_broadcast(&instance_map.pid_cond.COND_pid);
/* wake guardian */
pthread_cond_signal(&guardian_thread.COND_guardian);
break;
default: default:
if (!guardian_thread.is_stopped)
{ {
guardian_thread.request_stop_instances(); if (!guardian_thread.is_stopped())
guardian_thread.shutdown(); {
bool stop_instances= true;
guardian_thread.request_shutdown(stop_instances);
pthread_cond_signal(&guardian_thread.COND_guardian); pthread_cond_signal(&guardian_thread.COND_guardian);
} }
else else
...@@ -201,6 +190,7 @@ void manager(const Options &options) ...@@ -201,6 +190,7 @@ void manager(const Options &options)
thread_registry.deliver_shutdown(); thread_registry.deliver_shutdown();
shutdown_complete= TRUE; shutdown_complete= TRUE;
} }
}
break; break;
} }
} }
......
...@@ -23,6 +23,8 @@ ...@@ -23,6 +23,8 @@
#include <my_global.h> #include <my_global.h>
#include <my_sys.h> #include <my_sys.h>
#include <my_getopt.h> #include <my_getopt.h>
#include <m_string.h>
#include <mysql_com.h>
#include "priv.h" #include "priv.h"
...@@ -77,6 +79,9 @@ static struct my_option my_long_options[] = ...@@ -77,6 +79,9 @@ static struct my_option my_long_options[] =
(gptr *) &Options::socket_file_name, (gptr *) &Options::socket_file_name, (gptr *) &Options::socket_file_name, (gptr *) &Options::socket_file_name,
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
{ "passwd", 'P', "Prepare entry for passwd file and exit.", 0, 0, 0,
GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 },
{ "bind-address", OPT_BIND_ADDRESS, "Bind address to use for connection.", { "bind-address", OPT_BIND_ADDRESS, "Bind address to use for connection.",
(gptr *) &Options::bind_address, (gptr *) &Options::bind_address, (gptr *) &Options::bind_address, (gptr *) &Options::bind_address,
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
...@@ -142,6 +147,34 @@ static void usage() ...@@ -142,6 +147,34 @@ static void usage()
my_print_variables(my_long_options); my_print_variables(my_long_options);
} }
static void passwd()
{
char user[1024], pw[1024], *p;
char crypted_pw[SCRAMBLED_PASSWORD_CHAR_LENGTH + 1];
fprintf(stderr, "Creating record for new user.\n");
fprintf(stderr, "Enter user name: ");
if (!fgets(user, sizeof(user), stdin))
{
fprintf(stderr, "Unable to read user.\n");
return;
}
if ((p= strchr(user, '\n'))) *p= 0;
fprintf(stderr, "Enter password: ");
if (! fgets(pw, sizeof(pw), stdin))
{
fprintf(stderr, "Unable to read password.\n");
return;
}
if ((p= strchr(pw, '\n'))) *p= 0;
make_scrambled_password(crypted_pw, pw);
printf("%s:%s\n", user, crypted_pw);
}
C_MODE_START C_MODE_START
static my_bool static my_bool
...@@ -153,7 +186,9 @@ get_one_option(int optid, ...@@ -153,7 +186,9 @@ get_one_option(int optid,
case 'V': case 'V':
version(); version();
exit(0); exit(0);
case 'I': case 'P':
passwd();
exit(0);
case '?': case '?':
usage(); usage();
exit(0); exit(0);
......
...@@ -49,29 +49,6 @@ static struct tokens_st tokens[]= { ...@@ -49,29 +49,6 @@ static struct tokens_st tokens[]= {
}; };
/*
tries to find next word in the text
if found, returns the beginning and puts word length to word_len argument.
if not found returns pointer to first non-space or to '\0', word_len == 0
*/
inline void get_word(const char **text, uint *word_len)
{
const char *word_end;
/* skip space */
while (my_isspace(default_charset_info, **text))
++(*text);
word_end= *text;
while (my_isalnum(default_charset_info, *word_end))
++word_end;
*word_len= word_end - *text;
}
/* /*
Returns token no if word corresponds to some token, otherwise returns Returns token no if word corresponds to some token, otherwise returns
TOK_NOT_FOUND TOK_NOT_FOUND
......
...@@ -20,4 +20,34 @@ ...@@ -20,4 +20,34 @@
Command *parse_command(Command_factory *factory, const char *text); Command *parse_command(Command_factory *factory, const char *text);
/* define kinds of the word seek method */
enum { ALPHANUM= 1, NONSPACE };
/*
tries to find next word in the text
if found, returns the beginning and puts word length to word_len argument.
if not found returns pointer to first non-space or to '\0', word_len == 0
*/
inline void get_word(const char **text, uint *word_len,
int seek_method= ALPHANUM)
{
const char *word_end;
/* skip space */
while (my_isspace(default_charset_info, **text))
++(*text);
word_end= *text;
if (seek_method == ALPHANUM)
while (my_isalnum(default_charset_info, *word_end))
++word_end;
else
while (!my_isspace(default_charset_info, *word_end))
++word_end;
*word_len= word_end - *text;
}
#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_PARSE_H */ #endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_PARSE_H */
...@@ -14,43 +14,38 @@ ...@@ -14,43 +14,38 @@
along with this program; if not, write to the Free Software along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include "parse.h"
#include <stdio.h> #include <stdio.h>
#include <my_global.h> #include <my_global.h>
#include <my_sys.h> #include <my_sys.h>
#include <string.h> #include <string.h>
/* buf should be of appropriate size. Otherwise the word will be truncated */
static int get_word(FILE *file, char *buf, size_t size)
{
int currchar;
currchar= getc(file); /*
Parse output of the given command
/* skip space */ SYNOPSYS
while (my_isspace(default_charset_info, (char) currchar) && parse_output_and_get_value()
currchar != EOF && size > 1)
{
currchar= getc(file);
}
while (!my_isspace(default_charset_info, (char) currchar) && command the command to execue with popen.
currchar != EOF && size > 1) word the word to look for (usually an option name)
{ result the buffer to store the next word (option value)
*buf++= (char) currchar; result_len self-explanatory
currchar= getc(file);
size--;
}
*buf= '\0'; DESCRIPTION
return 0;
}
Parse output of the "command". Find the "word" and return the next one
*/
int parse_output_and_get_value(const char *command, const char *word, int parse_output_and_get_value(const char *command, const char *word,
char *result, size_t result_len) char *result, size_t result_len)
{ {
FILE *output; FILE *output;
int wordlen; uint wordlen;
/* should be enought to store the string from the output */
enum { MAX_LINE_LEN= 512 };
char linebuf[MAX_LINE_LEN];
wordlen= strlen(word); wordlen= strlen(word);
...@@ -62,19 +57,32 @@ int parse_output_and_get_value(const char *command, const char *word, ...@@ -62,19 +57,32 @@ int parse_output_and_get_value(const char *command, const char *word,
*/ */
setvbuf(output, NULL, _IOFBF, 0); setvbuf(output, NULL, _IOFBF, 0);
get_word(output, result, result_len); while (fgets(linebuf, sizeof(linebuf) - 1, output))
while (strncmp(word, result, wordlen) && *result != '\0')
{ {
get_word(output, result, result_len); uint lineword_len= 0;
} char *linep= linebuf;
linebuf[sizeof(linebuf) - 1]= '\0'; /* safety */
/*
Get the word, which might contain non-alphanumeric characters. (Usually
these are '/', '-' and '.' in the path expressions and filenames)
*/
get_word((const char **) &linep, &lineword_len, NONSPACE);
if (!strncmp(word, linep, wordlen) && *result != '\0')
{
/* /*
If we have found the word, return the next one. This is usually If we have found the word, return the next one. This is usually
an option value. an option value.
*/ */
if (*result != '\0') get_word((const char **) &linep, &lineword_len, NONSPACE);
get_word(output, result, result_len); DBUG_ASSERT(result_len > lineword_len);
strncpy(result, linep, lineword_len);
goto pclose;
}
}
pclose:
if (pclose(output)) if (pclose(output))
return 1; return 1;
......
...@@ -154,7 +154,8 @@ int send_fields(struct st_net *net, LIST *fields) ...@@ -154,7 +154,8 @@ int send_fields(struct st_net *net, LIST *fields)
store_to_string(&send_buff, (char *) "", &position); /* table name alias */ store_to_string(&send_buff, (char *) "", &position); /* table name alias */
store_to_string(&send_buff, field->name, &position); /* column name */ store_to_string(&send_buff, field->name, &position); /* column name */
store_to_string(&send_buff, field->name, &position); /* column name alias */ store_to_string(&send_buff, field->name, &position); /* column name alias */
if (send_buff.reserve(position, 12)) send_buff.reserve(position, 12);
if (send_buff.is_error())
goto err; goto err;
send_buff.buffer[position++]= 12; send_buff.buffer[position++]= 12;
int2store(send_buff.buffer + position, 1); /* charsetnr */ int2store(send_buff.buffer + position, 1); /* charsetnr */
......
...@@ -69,7 +69,7 @@ int User::init(const char *line) ...@@ -69,7 +69,7 @@ int User::init(const char *line)
return 0; return 0;
err: err:
log_error("error parsing user and password at line %d", line); log_error("error parsing user and password at line %s", line);
return 1; return 1;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment