summaryrefslogtreecommitdiff
path: root/server-tools
diff options
context:
space:
mode:
authorunknown <petr@mysql.com>2005-02-11 14:21:59 +0300
committerunknown <petr@mysql.com>2005-02-11 14:21:59 +0300
commitdce2554f9130920ab18e4e31432df7d6ca165ee0 (patch)
tree5a46c104b5146373b9e754ea5691cfa5ef3d2fcf /server-tools
parent79ba407d64ad4387b7b279f80a7bf95e68414df5 (diff)
downloadmariadb-git-dce2554f9130920ab18e4e31432df7d6ca165ee0.tar.gz
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
Diffstat (limited to 'server-tools')
-rw-r--r--server-tools/instance-manager/Makefile.am2
-rw-r--r--server-tools/instance-manager/buffer.cc16
-rw-r--r--server-tools/instance-manager/buffer.h14
-rw-r--r--server-tools/instance-manager/client_func.c32
-rw-r--r--server-tools/instance-manager/commands.cc12
-rw-r--r--server-tools/instance-manager/guardian.cc317
-rw-r--r--server-tools/instance-manager/guardian.h49
-rw-r--r--server-tools/instance-manager/instance.cc190
-rw-r--r--server-tools/instance-manager/instance.h9
-rw-r--r--server-tools/instance-manager/instance_map.cc20
-rw-r--r--server-tools/instance-manager/instance_map.h8
-rw-r--r--server-tools/instance-manager/instance_options.cc91
-rw-r--r--server-tools/instance-manager/instance_options.h8
-rw-r--r--server-tools/instance-manager/listener.cc4
-rw-r--r--server-tools/instance-manager/manager.cc26
-rw-r--r--server-tools/instance-manager/options.cc37
-rw-r--r--server-tools/instance-manager/parse.cc23
-rw-r--r--server-tools/instance-manager/parse.h30
-rw-r--r--server-tools/instance-manager/parse_output.cc72
-rw-r--r--server-tools/instance-manager/protocol.cc3
-rw-r--r--server-tools/instance-manager/user_map.cc2
21 files changed, 591 insertions, 374 deletions
diff --git a/server-tools/instance-manager/Makefile.am b/server-tools/instance-manager/Makefile.am
index 4b776fecc83..21d11e2f7d6 100644
--- a/server-tools/instance-manager/Makefile.am
+++ b/server-tools/instance-manager/Makefile.am
@@ -74,7 +74,7 @@ mysqlmanager_SOURCES= command.cc command.h mysqlmanager.cc \
buffer.h buffer.cc parse.cc parse.h \
guardian.cc guardian.h \
parse_output.cc parse_output.h \
- mysql_manager_error.h client_func.c
+ mysql_manager_error.h
mysqlmanager_LDADD= liboptions.a \
libnet.a \
diff --git a/server-tools/instance-manager/buffer.cc b/server-tools/instance-manager/buffer.cc
index ca84adbfd10..3a2a818e478 100644
--- a/server-tools/instance-manager/buffer.cc
+++ b/server-tools/instance-manager/buffer.cc
@@ -40,7 +40,7 @@
RETURN
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)
@@ -71,7 +71,7 @@ int Buffer::append(uint position, const char *string, uint len_arg)
RETURN
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)
@@ -92,6 +92,18 @@ int Buffer::reserve(uint position, uint len_arg)
return 0;
err:
+ error= 1;
return 1;
}
+
+int Buffer::get_size()
+{
+ return buffer_size;
+}
+
+
+int Buffer::is_error()
+{
+ return error;
+}
diff --git a/server-tools/instance-manager/buffer.h b/server-tools/instance-manager/buffer.h
index 66860bd67b5..260a9ef92f8 100644
--- a/server-tools/instance-manager/buffer.h
+++ b/server-tools/instance-manager/buffer.h
@@ -36,11 +36,17 @@ private:
/* maximum buffer size is 16Mb */
enum { MAX_BUFFER_SIZE= 16777216 };
size_t buffer_size;
+ /* Error flag. Triggered if we get an error of some kind */
+ int error;
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()
@@ -50,6 +56,8 @@ public:
public:
char *buffer;
+ int get_size();
+ int is_error();
int append(uint position, const char *string, uint len_arg);
int reserve(uint position, uint len_arg);
};
diff --git a/server-tools/instance-manager/client_func.c b/server-tools/instance-manager/client_func.c
deleted file mode 100644
index 92c106e5172..00000000000
--- a/server-tools/instance-manager/client_func.c
+++ /dev/null
@@ -1,32 +0,0 @@
-#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));
-}
diff --git a/server-tools/instance-manager/commands.cc b/server-tools/instance-manager/commands.cc
index 70774115429..3f38f21b008 100644
--- a/server-tools/instance-manager/commands.cc
+++ b/server-tools/instance-manager/commands.cc
@@ -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;
}
@@ -270,7 +271,8 @@ int Show_instance_options::do_command(struct st_net *net,
store_to_string(&send_buff,
(char *) instance->options.mysqld_path,
&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;
}
@@ -279,7 +281,8 @@ int Show_instance_options::do_command(struct st_net *net,
position= 0;
store_to_string(&send_buff, (char *) "nonguarded", &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;
}
@@ -296,7 +299,8 @@ int Show_instance_options::do_command(struct st_net *net,
store_to_string(&send_buff, option_value + 1, &position);
/* join name and the value into the same option again */
*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;
}
}
diff --git a/server-tools/instance-manager/guardian.cc b/server-tools/instance-manager/guardian.cc
index bc05fda1a8f..750c3495870 100644
--- a/server-tools/instance-manager/guardian.cc
+++ b/server-tools/instance-manager/guardian.cc
@@ -21,9 +21,32 @@
#include "guardian.h"
#include "instance_map.h"
+#include "instance.h"
#include "mysql_manager_error.h"
#include "log.h"
#include <string.h>
+#include <sys/types.h>
+#include <signal.h>
+
+
+/*
+ The Guardian list node structure. Guardian utilizes it to store
+ guarded instances plus some additional info.
+*/
+
+struct GUARD_NODE
+{
+ Instance *instance;
+ /* state of an instance (i.e. STARTED, CRASHED, etc.) */
+ int state;
+ /* the amount of attemts to restart instance (cleaned up at success) */
+ int restart_counter;
+ /* triggered at a crash */
+ time_t crash_moment;
+ /* General time field. Used to provide timeouts (at shutdown and restart) */
+ time_t last_checked;
+};
+
C_MODE_START
@@ -42,15 +65,13 @@ Guardian_thread::Guardian_thread(Thread_registry &thread_registry_arg,
uint monitoring_interval_arg) :
Guardian_thread_args(thread_registry_arg, instance_map_arg,
monitoring_interval_arg),
- thread_info(pthread_self())
+ thread_info(pthread_self()), guarded_instances(0)
{
pthread_mutex_init(&LOCK_guardian, 0);
pthread_cond_init(&COND_guardian, 0);
- shutdown_guardian= FALSE;
- is_stopped= FALSE;
+ shutdown_requested= FALSE;
+ stopped= FALSE;
init_alloc_root(&alloc, MEM_ROOT_BLOCK_SIZE, 0);
- guarded_instances= NULL;
- starting_instances= NULL;
}
@@ -65,19 +86,107 @@ Guardian_thread::~Guardian_thread()
}
-void Guardian_thread::shutdown()
+void Guardian_thread::request_shutdown(bool stop_instances_arg)
{
pthread_mutex_lock(&LOCK_guardian);
- shutdown_guardian= TRUE;
+ /* stop instances or just clean up Guardian repository */
+ stop_instances(stop_instances_arg);
+ shutdown_requested= TRUE;
pthread_mutex_unlock(&LOCK_guardian);
}
-void Guardian_thread::request_stop_instances()
+void Guardian_thread::process_instance(Instance *instance,
+ GUARD_NODE *current_node,
+ LIST **guarded_instances,
+ LIST *elem)
{
- pthread_mutex_lock(&LOCK_guardian);
- request_stop= TRUE;
- pthread_mutex_unlock(&LOCK_guardian);
+ int waitchild= Instance::DEFAULT_SHUTDOWN_DELAY;
+ /* The amount of times, Guardian attempts to restart an instance */
+ int restart_retry= 100;
+ time_t current_time= time(NULL);
+
+ if (current_node->state == STOPPING)
+ {
+ /* this brach is executed during shutdown */
+ if (instance->options.shutdown_delay != NULL)
+ waitchild= atoi(instance->options.shutdown_delay);
+
+ /* this returns true if and only if an instance was stopped for shure */
+ if (instance->is_crashed())
+ *guarded_instances= list_delete(*guarded_instances, elem);
+ else if (current_time - current_node->last_checked > waitchild)
+ {
+ instance->kill_instance(SIGKILL);
+ /*
+ Later we do elem= elem->next. This is ok, as we are only removing
+ the node from the list. The pointer to the next one is still valid.
+ */
+ *guarded_instances= list_delete(*guarded_instances, elem);
+ }
+
+ return;
+ }
+
+ if (instance->is_running())
+ {
+ /* clear status fields */
+ current_node->restart_counter= 0;
+ current_node->crash_moment= 0;
+ current_node->state= STARTED;
+ }
+ else
+ {
+ switch (current_node->state)
+ {
+ case NOT_STARTED:
+ instance->start();
+ current_node->last_checked= current_time;
+ log_info("guardian: starting instance %s",
+ instance->options.instance_name);
+ current_node->state= STARTING;
+ break;
+ case STARTED: /* fallthrough */
+ case STARTING: /* let the instance start or crash */
+ if (instance->is_crashed())
+ {
+ current_node->crash_moment= current_time;
+ current_node->last_checked= current_time;
+ current_node->state= JUST_CRASHED;
+ /* fallthrough -- restart an instance immediately */
+ }
+ else
+ break;
+ case JUST_CRASHED:
+ if (current_time - current_node->crash_moment <= 2)
+ {
+ instance->start();
+ log_info("guardian: starting instance %s",
+ instance->options.instance_name);
+ }
+ else current_node->state= CRASHED;
+ break;
+ case CRASHED: /* just regular restarts */
+ if (current_time - current_node->last_checked >
+ monitoring_interval)
+ {
+ if ((current_node->restart_counter < restart_retry))
+ {
+ instance->start();
+ current_node->last_checked= current_time;
+ ((GUARD_NODE *) elem->data)->restart_counter++;
+ log_info("guardian: starting instance %s",
+ instance->options.instance_name);
+ }
+ else current_node->state= CRASHED_AND_ABANDONED;
+ }
+ break;
+ case CRASHED_AND_ABANDONED:
+ break; /* do nothing */
+ default:
+ DBUG_ASSERT(0);
+ }
+ }
}
@@ -96,8 +205,7 @@ void Guardian_thread::request_stop_instances()
void Guardian_thread::run()
{
Instance *instance;
- int restart_retry= 100;
- LIST *loop;
+ LIST *elem;
struct timespec timeout;
thread_registry.register_thread(&thread_info);
@@ -105,68 +213,31 @@ void Guardian_thread::run()
my_thread_init();
pthread_mutex_lock(&LOCK_guardian);
-
- while (!shutdown_guardian)
+ /* loop, until all instances were shut down at the end */
+ while (!(shutdown_requested && (guarded_instances == NULL)))
{
- int status= 0;
- loop= guarded_instances;
+ elem= guarded_instances;
- while (loop != NULL)
+ while (elem != NULL)
{
- 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 */
+ struct timespec timeout;
- if (state == 1)
- ((GUARD_NODE *) loop->data)->crash_moment= time(NULL);
+ GUARD_NODE *current_node= (GUARD_NODE *) elem->data;
+ instance= ((GUARD_NODE *) elem->data)->instance;
+ process_instance(instance, current_node, &guarded_instances, elem);
- 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;
+ elem= elem->next;
}
- move_to_list(&starting_instances, &guarded_instances);
timeout.tv_sec= time(NULL) + monitoring_interval;
timeout.tv_nsec= 0;
- status= pthread_cond_timedwait(&COND_guardian, &LOCK_guardian, &timeout);
+ /* check the loop predicate before sleeping */
+ if (!(shutdown_requested && (guarded_instances == NULL)))
+ pthread_cond_timedwait(&COND_guardian, &LOCK_guardian, &timeout);
}
+ stopped= TRUE;
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.unregister_thread(&thread_info);
thread_registry.request_shutdown();
@@ -174,7 +245,29 @@ void Guardian_thread::run()
}
-int Guardian_thread::start()
+int Guardian_thread::is_stopped()
+{
+ int var;
+ pthread_mutex_lock(&LOCK_guardian);
+ var= stopped;
+ pthread_mutex_unlock(&LOCK_guardian);
+ return var;
+}
+
+
+/*
+ Initialize the list of guarded instances: loop through the Instance_map and
+ add all of the instances, which don't have 'nonguarded' option specified.
+
+ SYNOPSYS
+ Guardian_thread::init()
+
+ RETURN
+ 0 - ok
+ 1 - error occured
+*/
+
+int Guardian_thread::init()
{
Instance *instance;
Instance_map::Iterator iterator(instance_map);
@@ -183,7 +276,7 @@ int Guardian_thread::start()
while ((instance= iterator.next()))
{
if ((instance->options.nonguarded == NULL))
- if (add_instance_to_list(instance, &guarded_instances))
+ if (guard(instance))
return 1;
}
instance_map->unlock();
@@ -193,7 +286,7 @@ int Guardian_thread::start()
/*
- Start instance guarding
+ Add instance to the Guardian list
SYNOPSYS
guard()
@@ -201,37 +294,16 @@ int Guardian_thread::start()
DESCRIPTION
- The instance is added to the list of starting instances. Then after one guardian
- loop it is moved to the guarded instances list. Usually guard() is called after we
- start an instance, so we need to give some time to the instance to start.
+ The instance is added to the guarded instances list. Usually guard() is
+ called after we start an instance.
RETURN
0 - ok
1 - error occured
*/
-
int Guardian_thread::guard(Instance *instance)
{
- return add_instance_to_list(instance, &starting_instances);
-}
-
-
-void Guardian_thread::move_to_list(LIST **from, LIST **to)
-{
- LIST *tmp;
-
- while (*from)
- {
- tmp= rest(*from);
- *to= list_add(*to, *from);
- *from= tmp;
- }
-}
-
-
-int Guardian_thread::add_instance_to_list(Instance *instance, LIST **list)
-{
LIST *node;
GUARD_NODE *content;
@@ -244,10 +316,11 @@ int Guardian_thread::add_instance_to_list(Instance *instance, LIST **list)
content->instance= instance;
content->restart_counter= 0;
content->crash_moment= 0;
+ content->state= NOT_STARTED;
node->data= (void *) content;
pthread_mutex_lock(&LOCK_guardian);
- *list= list_add(*list, node);
+ guarded_instances= list_add(guarded_instances, node);
pthread_mutex_unlock(&LOCK_guardian);
return 0;
@@ -256,7 +329,7 @@ int Guardian_thread::add_instance_to_list(Instance *instance, LIST **list)
/*
TODO: perhaps it would make sense to create a pool of the LIST elements
- elements and give them upon request. Now we are loosing a bit of memory when
+ and give them upon request. Now we are loosing a bit of memory when
guarded instance was stopped and then restarted (since we cannot free just
a piece of the MEM_ROOT).
*/
@@ -288,21 +361,61 @@ int Guardian_thread::stop_guard(Instance *instance)
return 0;
}
-int Guardian_thread::stop_instances()
-{
- Instance *instance;
- Instance_map::Iterator iterator(instance_map);
+/*
+ Start Guardian shutdown. Attempt to start instances if requested.
- while ((instance= iterator.next()))
+ SYNOPSYS
+ stop_instances()
+ stop_instances_arg whether we should stop instances at shutdown
+
+ DESCRIPTION
+
+ Loops through the guarded_instances list and prepares them for shutdown.
+ If stop_instances was requested, we need to issue a stop command and change
+ the state accordingly. Otherwise we could simply delete an entry.
+ NOTE: Guardian should be locked by the calling function
+
+ RETURN
+ 0 - ok
+ 1 - error occured
+*/
+
+int Guardian_thread::stop_instances(bool stop_instances_arg)
+{
+ LIST *node;
+ node= guarded_instances;
+ while (node != NULL)
{
- if ((instance->options.nonguarded == NULL))
+ if (!stop_instances_arg)
{
- if (stop_guard(instance))
- return 1;
- /* let us try to stop the server */
- instance->stop();
+ /* just forget about an instance */
+ guarded_instances= list_delete(guarded_instances, node);
+ /*
+ This should still work fine, as we have only removed the
+ node from the list. The pointer to the next one is still valid
+ */
+ node= node->next;
+ }
+ else
+ {
+ GUARD_NODE *current_node= (GUARD_NODE *) node->data;
+ /*
+ If instance is running or was running (and now probably hanging),
+ request stop.
+ */
+ if (current_node->instance->is_running() ||
+ (current_node->state == STARTED))
+ {
+ current_node->state= STOPPING;
+ current_node->last_checked= time(NULL);
+ }
+ else
+ /* otherwise remove it from the list */
+ guarded_instances= list_delete(guarded_instances, node);
+ /* But try to kill it anyway. Just in case */
+ current_node->instance->kill_instance(SIGTERM);
+ node= node->next;
}
}
-
return 0;
}
diff --git a/server-tools/instance-manager/guardian.h b/server-tools/instance-manager/guardian.h
index bf96436a636..0aec00099de 100644
--- a/server-tools/instance-manager/guardian.h
+++ b/server-tools/instance-manager/guardian.h
@@ -19,6 +19,7 @@
#include <my_global.h>
#include <my_sys.h>
#include <my_list.h>
+#include "thread_registry.h"
#ifdef __GNUC__
#pragma interface
@@ -26,9 +27,8 @@
class Instance;
class Instance_map;
-
-#include "thread_registry.h"
-#include "instance.h"
+class Thread_registry;
+struct GUARD_NODE;
C_MODE_START
@@ -36,19 +36,11 @@ 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
{
Thread_registry &thread_registry;
Instance_map *instance_map;
- uint monitoring_interval;
+ int monitoring_interval;
Guardian_thread_args(Thread_registry &thread_registry_arg,
Instance_map *instance_map_arg,
@@ -72,36 +64,41 @@ public:
Instance_map *instance_map_arg,
uint monitoring_interval_arg);
~Guardian_thread();
+ /* Main funtion of the thread */
void run();
- int start();
- void shutdown();
- void request_stop_instances();
+ /* Initialize list of guarded instances */
+ int init();
+ /* Request guardian shutdown. Stop instances if needed */
+ void request_shutdown(bool stop_instances);
+ /* Start instance protection */
int guard(Instance *instance);
+ /* Stop instance protection */
int stop_guard(Instance *instance);
- bool is_stopped;
+ /* Returns true if guardian thread is stopped */
+ int 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);
+ /* Prepares Guardian shutdown. Stops instances is needed */
+ int stop_instances(bool stop_instances_arg);
+ /* check instance state and act accordingly */
+ void process_instance(Instance *instance, GUARD_NODE *current_node,
+ LIST **guarded_instances, LIST *elem);
+ int stopped;
private:
+ /* states of an instance */
+ enum { NOT_STARTED= 1, STARTING, STARTED, JUST_CRASHED, CRASHED,
+ CRASHED_AND_ABANDONED, STOPPING };
pthread_mutex_t LOCK_guardian;
Thread_info thread_info;
LIST *guarded_instances;
- 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;
+ bool shutdown_requested;
};
#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_GUARDIAN_H */
diff --git a/server-tools/instance-manager/instance.cc b/server-tools/instance-manager/instance.cc
index 3ba943c9cd1..e654612de3e 100644
--- a/server-tools/instance-manager/instance.cc
+++ b/server-tools/instance-manager/instance.cc
@@ -27,6 +27,19 @@
#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.
@@ -44,6 +57,12 @@ int Instance::start()
{
pid_t pid;
+ /* clear crash flag */
+ pthread_mutex_lock(&LOCK_instance);
+ crashed= 0;
+ pthread_mutex_unlock(&LOCK_instance);
+
+
if (!is_running())
{
if ((pid= options.get_pid()) != 0) /* check the pidfile */
@@ -52,17 +71,26 @@ int Instance::start()
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:
- execv(options.mysqld_path, options.argv);
- /* exec never returns */
- exit(1);
- case -1:
+ /*
+ 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:
- return 0;
}
+
+ return 0;
}
/* the instance is started already */
@@ -70,9 +98,62 @@ int Instance::start()
}
+void Instance::fork_and_monitor()
+{
+ 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;
}
@@ -95,20 +176,19 @@ bool Instance::is_running()
pthread_mutex_lock(&LOCK_instance);
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,
password,
NullS, port,
socket, 0))
{
/*
- Very strange. We have successfully connected to the server using
- bullshit as username/password. Write a warning to the logfile.
+ 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.");
- mysql_close(&mysql);
pthread_mutex_unlock(&LOCK_instance);
return_val= TRUE; /* server is alive */
}
@@ -151,53 +231,30 @@ int Instance::stop()
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 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);
+ kill_instance(SIGTERM);
+ /* sleep on condition to wait for SIGCHLD */
- return 0;
- }
-
- /* 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;
- timeout.tv_sec= time(NULL) + waitchild;
- timeout.tv_nsec= 0;
- if (pthread_mutex_lock(&instance_map->pid_cond.LOCK_pid))
- goto err; /* perhaps this should be procecced differently */
+ while (options.get_pid() != 0) /* while server isn't stopped */
+ {
+ int status;
- while (options.get_pid() != 0) /* while server isn't stopped */
- {
- int status;
+ status= pthread_cond_timedwait(&COND_instance_restarted,
+ &LOCK_instance,
+ &timeout);
+ if (status == ETIMEDOUT)
+ break;
+ }
- status= pthread_cond_timedwait(&instance_map->pid_cond.COND_pid,
- &instance_map->pid_cond.LOCK_pid,
- &timeout);
- if (status == ETIMEDOUT)
- break;
- }
+ pthread_mutex_unlock(&LOCK_instance);
- pthread_mutex_unlock(&instance_map->pid_cond.LOCK_pid);
+ kill_instance(SIGKILL);
- if (!kill(pid, 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;
err:
@@ -205,6 +262,29 @@ err:
}
+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.
@@ -212,8 +292,6 @@ err:
int Instance::init(const char *name_arg)
{
- pthread_mutex_init(&LOCK_instance, 0);
-
return options.init(name_arg);
}
diff --git a/server-tools/instance-manager/instance.h b/server-tools/instance-manager/instance.h
index 95852542fb4..fbe24e17554 100644
--- a/server-tools/instance-manager/instance.h
+++ b/server-tools/instance-manager/instance.h
@@ -30,14 +30,19 @@ class Instance_map;
class Instance
{
public:
+ Instance();
+
~Instance();
int init(const char *name);
int complete_initialization(Instance_map *instance_map_arg);
- /* check if the instance is running and set up mysql connection if yes */
bool is_running();
int start();
int stop();
+ /* send a signal to the instance */
+ void kill_instance(int signo);
+ int is_crashed();
+ void fork_and_monitor();
public:
enum { DEFAULT_SHUTDOWN_DELAY= 35 };
@@ -49,7 +54,9 @@ private:
double start of the instance. This happens when the instance is starting
and we issue the start command once more.
*/
+ int crashed;
pthread_mutex_t LOCK_instance;
+ pthread_cond_t COND_instance_restarted;
Instance_map *instance_map;
};
diff --git a/server-tools/instance-manager/instance_map.cc b/server-tools/instance-manager/instance_map.cc
index ba373087db4..5044bfb0f43 100644
--- a/server-tools/instance-manager/instance_map.cc
+++ b/server-tools/instance-manager/instance_map.cc
@@ -120,9 +120,6 @@ Instance_map::Instance_map(const char *default_mysqld_path_arg)
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,
get_instance_key, delete_instance, 0))
return 1;
@@ -135,8 +132,6 @@ Instance_map::~Instance_map()
hash_free(&hash);
pthread_mutex_unlock(&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()
}
-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 */
int Instance_map::load()
diff --git a/server-tools/instance-manager/instance_map.h b/server-tools/instance-manager/instance_map.h
index f2121f7141d..b8b5ad0a890 100644
--- a/server-tools/instance-manager/instance_map.h
+++ b/server-tools/instance-manager/instance_map.h
@@ -27,12 +27,6 @@
#include "protocol.h"
#include "guardian.h"
-typedef struct st_instance_cond
-{
- pthread_mutex_t LOCK_pid;
- pthread_cond_t COND_pid;
-} CHILD_COND;
-
class Instance;
extern int load_all_groups(char ***groups, const char *filename);
extern void free_groups(char **groups);
@@ -83,8 +77,6 @@ public:
public:
const char *mysqld_path;
Guardian_thread *guardian;
- /* structure used for syncronization reasons in the stop command */
- CHILD_COND pid_cond;
private:
enum { START_HASH_SIZE = 16 };
diff --git a/server-tools/instance-manager/instance_options.cc b/server-tools/instance-manager/instance_options.cc
index e7e17691330..ab97c86316b 100644
--- a/server-tools/instance-manager/instance_options.cc
+++ b/server-tools/instance-manager/instance_options.cc
@@ -27,25 +27,50 @@
#include <m_string.h>
-/* option_name should be prefixed with "--" */
-int Instance_options::get_default_option(char *result, const char *option_name,
- size_t result_len)
+/*
+ Get compiled-in value of default_option
+
+ 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 rc= 1;
char verbose_option[]= " --no-defaults --verbose --help";
- Buffer cmd;
-
- cmd.append(position, mysqld_path, strlen(mysqld_path));
- position+= strlen(mysqld_path);
- cmd.append(position, verbose_option, sizeof(verbose_option) - 1);
- position+= sizeof(verbose_option) - 1;
- cmd.append(position, "\0", 1);
- /* get the value from "mysqld --help --verbose" */
- if (parse_output_and_get_value(cmd.buffer, option_name + 2,
- result, result_len))
- return 1;
- return 0;
+ Buffer cmd(strlen(mysqld_path)+sizeof(verbose_option)+1);
+ if (cmd.get_size()) /* malloc succeeded */
+ {
+ cmd.append(position, mysqld_path, strlen(mysqld_path));
+ position+= strlen(mysqld_path);
+ cmd.append(position, verbose_option, sizeof(verbose_option) - 1);
+ position+= sizeof(verbose_option) - 1;
+ cmd.append(position, "\0", 1);
+
+ if (cmd.is_error())
+ goto err;
+ /* get the value from "mysqld --help --verbose" */
+ rc= parse_output_and_get_value(cmd.buffer, option_name + 2,
+ result, result_len);
+ }
+
+ return rc;
+err:
+ return 1;
}
@@ -56,51 +81,33 @@ void Instance_options::get_pid_filename(char *result)
if (mysqld_datadir == NULL)
{
- get_default_option(datadir, "--datadir", MAX_PATH_LEN);
+ get_default_option(datadir, sizeof(datadir), "--datadir");
}
else
strxnmov(datadir, MAX_PATH_LEN - 1, strchr(mysqld_datadir, '=') + 1,
"/", NullS);
- /* well, we should never get it */
- if (mysqld_pid_file != NULL)
- pid_file= strchr(pid_file, '=') + 1;
- else
- DBUG_ASSERT(0);
+ DBUG_ASSERT(mysqld_pid_file);
+ pid_file= strchr(pid_file, '=') + 1;
/* get the full path to the pidfile */
my_load_path(result, pid_file, datadir);
-
}
int Instance_options::unlink_pidfile()
{
- char pid_file_path[MAX_PATH_LEN];
-
- /*
- 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);
+ return unlink(pid_file_with_path);
}
pid_t Instance_options::get_pid()
{
- char pid_file_path[MAX_PATH_LEN];
-
- /*
- This works as we know that pid_file_path is of
- MAX_PATH_LEN == FN_REFLEN length
- */
- get_pid_filename((char *)&pid_file_path);
+ FILE *pid_file_stream;
/* get the pid */
- if (FILE *pid_file_stream= my_fopen(pid_file_path,
- O_RDONLY | O_BINARY, MYF(0)))
+ if (pid_file_stream= my_fopen(pid_file_with_path,
+ O_RDONLY | O_BINARY, MYF(0)))
{
pid_t pid;
@@ -140,6 +147,8 @@ int Instance_options::complete_initialization(const char *default_path)
add_option(pidfilename);
}
+ get_pid_filename(pid_file_with_path);
+
/* we need to reserve space for the final zero + possible default options */
if (!(argv= (char**) alloc_root(&alloc, (options_array.elements + 1
+ MAX_NUMBER_OF_DEFAULT_OPTIONS) * sizeof(char*))))
@@ -244,6 +253,8 @@ int Instance_options::add_to_argv(const char* option)
return 0;
}
+
+/* function for debug purposes */
void Instance_options::print_argv()
{
int i;
diff --git a/server-tools/instance-manager/instance_options.h b/server-tools/instance-manager/instance_options.h
index 1ed11fc9afa..f6d4a6d93c6 100644
--- a/server-tools/instance-manager/instance_options.h
+++ b/server-tools/instance-manager/instance_options.h
@@ -39,7 +39,7 @@ public:
Instance_options() :
mysqld_socket(0), mysqld_datadir(0), mysqld_bind_address(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();
/* fills in argv */
@@ -60,6 +60,7 @@ public:
enum { MAX_PATH_LEN= 512 };
enum { MAX_NUMBER_OF_DEFAULT_OPTIONS= 2 };
enum { MEM_ROOT_BLOCK_SIZE= 512 };
+ char pid_file_with_path[MAX_PATH_LEN];
char **argv;
/* We need the some options, so we store them as a separate pointers */
const char *mysqld_socket;
@@ -72,11 +73,12 @@ public:
const char *mysqld_path;
const char *nonguarded;
const char *shutdown_delay;
+ /* this value is computed and cashed here */
DYNAMIC_ARRAY options_array;
private:
int add_to_argv(const char *option);
- int get_default_option(char *result, const char *option_name,
- size_t result_len);
+ int get_default_option(char *result, size_t result_len,
+ const char *option_name);
private:
uint filled_default_options;
MEM_ROOT alloc;
diff --git a/server-tools/instance-manager/listener.cc b/server-tools/instance-manager/listener.cc
index 8266c0dac4c..14970989e92 100644
--- a/server-tools/instance-manager/listener.cc
+++ b/server-tools/instance-manager/listener.cc
@@ -85,6 +85,8 @@ void Listener_thread::run()
thread_registry.register_thread(&thread_info);
+ my_thread_init();
+
/* I. prepare 'listen' sockets */
int ip_socket= socket(AF_INET, SOCK_STREAM, 0);
@@ -263,11 +265,13 @@ void Listener_thread::run()
unlink(unix_socket_address.sun_path);
thread_registry.unregister_thread(&thread_info);
+ my_thread_end();
return;
err:
thread_registry.unregister_thread(&thread_info);
thread_registry.request_shutdown();
+ my_thread_end();
return;
}
diff --git a/server-tools/instance-manager/manager.cc b/server-tools/instance-manager/manager.cc
index b48c020786f..af8dac47dca 100644
--- a/server-tools/instance-manager/manager.cc
+++ b/server-tools/instance-manager/manager.cc
@@ -90,7 +90,6 @@ void manager(const Options &options)
sigemptyset(&mask);
sigaddset(&mask, SIGINT);
sigaddset(&mask, SIGTERM);
- sigaddset(&mask, SIGCHLD);
sigaddset(&mask, SIGPIPE);
sigaddset(&mask, SIGHUP);
/*
@@ -128,7 +127,7 @@ void manager(const Options &options)
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
shutting down the instances, and this is a long operation.
*/
@@ -160,12 +159,8 @@ void manager(const Options &options)
more then 10 alarms at the same time.
*/
init_thr_alarm(10);
- /*
- Now we can init the list of guarded instances. We have to do it after
- 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();
+ /* init list of guarded instances */
+ guardian_thread.init();
/*
After the list of guarded instances have been initialized,
Guardian should start them.
@@ -182,18 +177,12 @@ void manager(const Options &options)
case THR_SERVER_ALARM:
process_alarm(signo);
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:
- if (!guardian_thread.is_stopped)
+ {
+ if (!guardian_thread.is_stopped())
{
- guardian_thread.request_stop_instances();
- guardian_thread.shutdown();
+ bool stop_instances= true;
+ guardian_thread.request_shutdown(stop_instances);
pthread_cond_signal(&guardian_thread.COND_guardian);
}
else
@@ -201,6 +190,7 @@ void manager(const Options &options)
thread_registry.deliver_shutdown();
shutdown_complete= TRUE;
}
+ }
break;
}
}
diff --git a/server-tools/instance-manager/options.cc b/server-tools/instance-manager/options.cc
index bf6ba1e9163..18d98a3d9a6 100644
--- a/server-tools/instance-manager/options.cc
+++ b/server-tools/instance-manager/options.cc
@@ -23,6 +23,8 @@
#include <my_global.h>
#include <my_sys.h>
#include <my_getopt.h>
+#include <m_string.h>
+#include <mysql_com.h>
#include "priv.h"
@@ -77,6 +79,9 @@ static struct my_option my_long_options[] =
(gptr *) &Options::socket_file_name, (gptr *) &Options::socket_file_name,
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.",
(gptr *) &Options::bind_address, (gptr *) &Options::bind_address,
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
@@ -142,6 +147,34 @@ static void usage()
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
static my_bool
@@ -153,7 +186,9 @@ get_one_option(int optid,
case 'V':
version();
exit(0);
- case 'I':
+ case 'P':
+ passwd();
+ exit(0);
case '?':
usage();
exit(0);
diff --git a/server-tools/instance-manager/parse.cc b/server-tools/instance-manager/parse.cc
index d029267f9b8..4c897ddf933 100644
--- a/server-tools/instance-manager/parse.cc
+++ b/server-tools/instance-manager/parse.cc
@@ -50,29 +50,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
TOK_NOT_FOUND
*/
diff --git a/server-tools/instance-manager/parse.h b/server-tools/instance-manager/parse.h
index 236a9bee53a..92519893302 100644
--- a/server-tools/instance-manager/parse.h
+++ b/server-tools/instance-manager/parse.h
@@ -20,4 +20,34 @@
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 */
diff --git a/server-tools/instance-manager/parse_output.cc b/server-tools/instance-manager/parse_output.cc
index 2bc51922e69..4276062caf2 100644
--- a/server-tools/instance-manager/parse_output.cc
+++ b/server-tools/instance-manager/parse_output.cc
@@ -14,43 +14,38 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+#include "parse.h"
+
#include <stdio.h>
#include <my_global.h>
#include <my_sys.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 */
- while (my_isspace(default_charset_info, (char) currchar) &&
- currchar != EOF && size > 1)
- {
- currchar= getc(file);
- }
+ SYNOPSYS
+ parse_output_and_get_value()
- while (!my_isspace(default_charset_info, (char) currchar) &&
- currchar != EOF && size > 1)
- {
- *buf++= (char) currchar;
- currchar= getc(file);
- size--;
- }
+ command the command to execue with popen.
+ word the word to look for (usually an option name)
+ result the buffer to store the next word (option value)
+ result_len self-explanatory
- *buf= '\0';
- return 0;
-}
+ DESCRIPTION
+ 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,
char *result, size_t result_len)
{
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);
@@ -62,19 +57,32 @@ int parse_output_and_get_value(const char *command, const char *word,
*/
setvbuf(output, NULL, _IOFBF, 0);
- get_word(output, result, result_len);
- while (strncmp(word, result, wordlen) && *result != '\0')
+ while (fgets(linebuf, sizeof(linebuf) - 1, output))
{
- 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
+ an option value.
+ */
+ get_word((const char **) &linep, &lineword_len, NONSPACE);
+ DBUG_ASSERT(result_len > lineword_len);
+ strncpy(result, linep, lineword_len);
+ goto pclose;
+ }
}
- /*
- If we have found the word, return the next one. This is usually
- an option value.
- */
- if (*result != '\0')
- get_word(output, result, result_len);
-
+pclose:
if (pclose(output))
return 1;
diff --git a/server-tools/instance-manager/protocol.cc b/server-tools/instance-manager/protocol.cc
index 581157ccd72..60cd0e8714f 100644
--- a/server-tools/instance-manager/protocol.cc
+++ b/server-tools/instance-manager/protocol.cc
@@ -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, field->name, &position); /* column name */
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;
send_buff.buffer[position++]= 12;
int2store(send_buff.buffer + position, 1); /* charsetnr */
diff --git a/server-tools/instance-manager/user_map.cc b/server-tools/instance-manager/user_map.cc
index 21d66912813..7cb2cd67d7f 100644
--- a/server-tools/instance-manager/user_map.cc
+++ b/server-tools/instance-manager/user_map.cc
@@ -69,7 +69,7 @@ int User::init(const char *line)
return 0;
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;
}