MySQL Lists are EOL. Please join:

List:Commits« Previous MessageNext Message »
From:Alexander Nozdrin Date:October 27 2006 11:30am
Subject:bk commit into 5.1 tree (anozdrin:1.2326) BUG#23215
View as plain text  
Below is the list of changes that have just been committed into a local
5.1 repository of alik. When alik does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html

ChangeSet@stripped, 2006-10-27 15:30:40+04:00, anozdrin@alik. +28 -0
  Fix for the following bugs:
    - BUG#22306: STOP INSTANCE can not be applied for instances in Crashed,
      Failed and Abandoned;
    - BUG#23476: DROP INSTANCE does not work
    - BUG#23215: STOP INSTANCE takes too much time
  
  The problems were as follows:
    - BUG#22306: STOP INSTANCE checked that mysqld is up and running.
      If it was not so, STOP INSTANCE reported an error.
    - BUG#23476: the problem was that DROP INSTANCE tried to stop
      inactive instance;
    - BUG#23215: the problem was that locks were not acquired properly,
      so the instance-monitoring thread could not acquire the mutex,
      holded by the query-processing thread.
  
  The general idea of the fix is to re-implement locking scheme. 

  mysql-test/t/im_options.imtest@stripped, 2006-10-27 15:30:37+04:00, anozdrin@alik. +1 -27
    Update test for new framework.

  server-tools/instance-manager/IMService.cpp@stripped, 2006-10-27 15:30:37+04:00, anozdrin@alik. +1 -1
    Use Manager class instead of manager().

  server-tools/instance-manager/Makefile.am@stripped, 2006-10-27 15:30:37+04:00, anozdrin@alik. +2 -0
    Treat warnings as errors.

  server-tools/instance-manager/command.cc@stripped, 2006-10-27 15:30:37+04:00, anozdrin@alik. +7 -2
    Store references to Guardian_thread and Instance_map in Command attributes.

  server-tools/instance-manager/command.h@stripped, 2006-10-27 15:30:37+04:00, anozdrin@alik. +4 -2
    Store references to Guardian_thread and Instance_map in Command attributes.

  server-tools/instance-manager/commands.cc@stripped, 2006-10-27 15:30:37+04:00, anozdrin@alik. +146 -105
    Ensure that the following locking schema is used:
      1. Acquire LOCK_instance_map;
      2. Acquire LOCK_instance
    
    LOCK_guardian is not needed since Guardian_thread does not
    contain Instance-list anymore.

  server-tools/instance-manager/commands.h@stripped, 2006-10-27 15:30:37+04:00, anozdrin@alik. +39 -45
    1. Remove Instance_map argument from command constructors;
    2. Introduce a new class -- Instance_cmd, which contains
      an attribute for instance name and provide related functionality

  server-tools/instance-manager/guardian.cc@stripped, 2006-10-27 15:30:37+04:00, anozdrin@alik. +303 -335
    1. Remove list of instances from Guardian_thread. LOCK_guardian protects
    now only internal attributes of Guardian_thread.
    2. Introduce start_detached();
    3. Be more verbose.

  server-tools/instance-manager/guardian.h@stripped, 2006-10-27 15:30:37+04:00, anozdrin@alik. +49 -92
    1. Eliminate Guardian_thread_args
    2. Remove list of instances from Guardian_thread. LOCK_guardian protects
    now only internal attributes of Guardian_thread.

  server-tools/instance-manager/instance.cc@stripped, 2006-10-27 15:30:37+04:00, anozdrin@alik. +504 -318
    1. Move Guardian-specific attributes to Instance;
    2. Introduce new state STOPPED to mark that guarded instance
    is stopped and should not be restarted by Guardian.

  server-tools/instance-manager/instance.h@stripped, 2006-10-27 15:30:37+04:00, anozdrin@alik. +108 -25
    1. Move Guardian-specific attributes to Instance;
    2. Introduce new state STOPPED to mark that guarded instance
    is stopped and should not be restarted by Guardian.

  server-tools/instance-manager/instance_map.cc@stripped, 2006-10-27 15:30:37+04:00, anozdrin@alik. +55 -101
    1. Polishing;
    2. Added synchronization on shutdown.

  server-tools/instance-manager/instance_map.h@stripped, 2006-10-27 15:30:37+04:00, anozdrin@alik. +9 -29
    Polishing.

  server-tools/instance-manager/instance_options.cc@stripped, 2006-10-27 15:30:37+04:00, anozdrin@alik. +26 -24
    Polishing.

  server-tools/instance-manager/instance_options.h@stripped, 2006-10-27 15:30:37+04:00, anozdrin@alik. +36 -7
    Polishing.

  server-tools/instance-manager/listener.cc@stripped, 2006-10-27 15:30:37+04:00, anozdrin@alik. +49 -57
    1. Remove Listener_thread_args
    2. Polishing

  server-tools/instance-manager/listener.h@stripped, 2006-10-27 15:30:37+04:00, anozdrin@alik. +26 -17
    1. Remove Listener_thread_args
    2. Polishing

  server-tools/instance-manager/manager.cc@stripped, 2006-10-27 15:30:37+04:00, anozdrin@alik. +196 -138
    Transfer manager() function into Manager class (singleton).

  server-tools/instance-manager/manager.h@stripped, 2006-10-27 15:30:37+04:00, anozdrin@alik. +82 -2
    Transfer manager() function into Manager class (singleton).

  server-tools/instance-manager/mysql_connection.cc@stripped, 2006-10-27 15:30:37+04:00, anozdrin@alik. +8 -14
    Polishing.

  server-tools/instance-manager/mysql_connection.h@stripped, 2006-10-27 15:30:37+04:00, anozdrin@alik. +1 -10
    Polishing.

  server-tools/instance-manager/mysqlmanager.cc@stripped, 2006-10-27 15:30:37+04:00, anozdrin@alik. +5 -4
    Use Manager class instead of manager() function.

  server-tools/instance-manager/parse.cc@stripped, 2006-10-27 15:30:37+04:00, anozdrin@alik. +17 -14
    Remove Instance_map reference.

  server-tools/instance-manager/parse.h@stripped, 2006-10-27 15:30:37+04:00, anozdrin@alik. +1 -2
    Remove Instance_map reference.

  server-tools/instance-manager/priv.cc@stripped, 2006-10-27 15:30:37+04:00, anozdrin@alik. +34 -3
    Move create_pid_file() out of manager.cc.

  server-tools/instance-manager/priv.h@stripped, 2006-10-27 15:30:37+04:00, anozdrin@alik. +2 -3
    Move create_pid_file() out of manager.cc.

  server-tools/instance-manager/thread_registry.h@stripped, 2006-10-27 15:30:37+04:00, anozdrin@alik. +5 -0
    Prevent copying.

  server-tools/instance-manager/user_map.cc@stripped, 2006-10-27 15:30:37+04:00, anozdrin@alik. +5 -5
    Fix typo.

# This is a BitKeeper patch.  What follows are the unified diffs for the
# set of deltas contained in the patch.  The rest of the patch, the part
# that BitKeeper cares about, is below these diffs.
# User:	anozdrin
# Host:	alik.
# Root:	/mnt/raid/alik/MySQL/devel/5.1-rt-bug23215

--- 1.4/mysql-test/t/im_options.imtest	2006-10-27 15:30:46 +04:00
+++ 1.5/mysql-test/t/im_options.imtest	2006-10-27 15:30:46 +04:00
@@ -32,33 +32,7 @@
 #
 ###########################################################################
 
---source include/im_check_os.inc
-
-###########################################################################
-#
-# Check starting conditions.
-#
-###########################################################################
-
-# - check the configuration file;
-
---echo --------------------------------------------------------------------
---exec grep '^server_id[^a-zA-Z0-9_-]' $MYSQLTEST_VARDIR/im.cnf ;
---echo --------------------------------------------------------------------
-
-# - check the running instances.
-
---connect (mysql1_con,localhost,root,,mysql,$IM_MYSQLD1_PORT,$IM_MYSQLD1_SOCK)
-
---connection mysql1_con
-
-SHOW VARIABLES LIKE 'server_id';
-
---connection default
-
-# - check the internal cache.
-
-SHOW INSTANCES;
+--source include/im_check_env.inc
 
 ###########################################################################
 #

--- 1.40/server-tools/instance-manager/Makefile.am	2006-10-27 15:30:46 +04:00
+++ 1.41/server-tools/instance-manager/Makefile.am	2006-10-27 15:30:46 +04:00
@@ -61,6 +61,8 @@ client_settings.h:
 
 libexec_PROGRAMS= mysqlmanager
 
+mysqlmanager_CXXFLAGS=  -Werror
+
 mysqlmanager_SOURCES=	command.cc command.h mysqlmanager.cc \
 			manager.h manager.cc log.h log.cc \
 			thread_registry.h thread_registry.cc \

--- 1.31/server-tools/instance-manager/listener.cc	2006-10-27 15:30:46 +04:00
+++ 1.32/server-tools/instance-manager/listener.cc	2006-10-27 15:30:46 +04:00
@@ -29,7 +29,7 @@
 #include <sys/un.h>
 #endif
 
-#include "instance_map.h"
+#include "manager.h"
 #include "log.h"
 #include "mysql_connection.h"
 #include "options.h"
@@ -59,36 +59,17 @@ static void set_no_inherit(int socket)
 }
 
 
-/*
-  Listener_thread - incapsulates listening functionality
-*/
-
-class Listener_thread: public Listener_thread_args
+void *Listener_thread::listener_thread_func(void *listener)
 {
-public:
-  Listener_thread(const Listener_thread_args &args);
-  ~Listener_thread();
-  void run();
-private:
-  static const int LISTEN_BACK_LOG_SIZE= 5;     /* standard backlog size */
-  ulong total_connection_count;
-  Thread_info thread_info;
-
-  int     sockets[2];
-  int     num_sockets;
-  fd_set  read_fds;
-private:
-  void handle_new_mysql_connection(Vio *vio);
-  int   create_tcp_socket();
-  int   create_unix_socket(struct sockaddr_un &unix_socket_address);
-};
-
-
-Listener_thread::Listener_thread(const Listener_thread_args &args) :
-  Listener_thread_args(args.thread_registry, args.user_map, args.instance_map)
-  ,total_connection_count(0)
-  ,thread_info(pthread_self(), TRUE)
-  ,num_sockets(0)
+  ((Listener_thread *) listener)->run();
+
+  return NULL;
+}
+
+
+Listener_thread::Listener_thread():
+  total_connection_count(0),
+  num_sockets(0)
 {
 }
 
@@ -98,6 +79,22 @@ Listener_thread::~Listener_thread()
 }
 
 
+bool Listener_thread::start_detached()
+{
+  pthread_t thd_id;
+  pthread_attr_t attr;
+  int rc;
+
+  pthread_attr_init(&attr);
+  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+  rc= set_stacksize_n_create_thread(&thd_id, &attr,
+                                    listener_thread_func, this);
+  pthread_attr_destroy(&attr);
+
+  return rc != 0;
+}
+
+
 /*
   Listener_thread::run() - listen all supported sockets and spawn a thread
   to handle incoming connection.
@@ -111,18 +108,27 @@ Listener_thread::~Listener_thread()
 void Listener_thread::run()
 {
   int i, n= 0;
+  Thread_info thread_info(pthread_self(), TRUE);
+  Thread_registry &thread_registry=
+    Manager::get_instance().get_thread_registry();
 
   log_info("Listener_thread: started.");
 
 #ifndef __WIN__
+  struct sockaddr_un unix_socket_address;
+
   /* we use this var to check whether we are running on LinuxThreads */
-  pid_t thread_pid;
+  pid_t thread_pid= getpid();
 
-  thread_pid= getpid();
+  /*
+    Set global variable.
 
-  struct sockaddr_un unix_socket_address;
-  /* set global variable */
-  linuxthreads= (thread_pid != manager_pid);
+    NOTE: Actually, there is race condition, because there is no
+    synchronization between setting and using linuxthreads. In other words, we
+    assume that Listener thread starts and initializes linuxthreads variable
+    before Instance-monitoring threads will use it.
+  */
+  linuxthreads= (thread_pid != Manager::get_instance().get_manager_pid());
 #endif
 
   thread_registry.register_thread(&thread_info);
@@ -183,10 +189,12 @@ void Listener_thread::run()
         {
           set_no_inherit(client_fd);
 
-          Vio *vio= vio_new(client_fd, socket_index == 0 ?
-                            VIO_TYPE_SOCKET : VIO_TYPE_TCPIP,
-                            socket_index == 0 ? 1 : 0);
-          if (vio != 0)
+          struct st_vio *vio=
+            vio_new(client_fd,
+                    socket_index == 0 ?  VIO_TYPE_SOCKET : VIO_TYPE_TCPIP,
+                    socket_index == 0 ? 1 : 0);
+
+          if (vio != NULL)
             handle_new_mysql_connection(vio);
           else
           {
@@ -357,12 +365,10 @@ create_unix_socket(struct sockaddr_un &u
     handle_new_mysql_connection()
 */
 
-void Listener_thread::handle_new_mysql_connection(Vio *vio)
+void Listener_thread::handle_new_mysql_connection(struct st_vio *vio)
 {
   if (Mysql_connection_thread_args *mysql_thread_args=
-      new Mysql_connection_thread_args(vio, thread_registry, user_map,
-                                       ++total_connection_count,
-                                       instance_map)
+      new Mysql_connection_thread_args(vio, ++total_connection_count)
       )
   {
     /*
@@ -386,17 +392,3 @@ void Listener_thread::handle_new_mysql_c
   else
     vio_delete(vio);
 }
-
-
-pthread_handler_t listener(void *arg)
-{
-  Listener_thread_args *args= (Listener_thread_args *) arg;
-  Listener_thread listener(*args);
-  listener.run();
-  /*
-    args is a stack variable because listener thread lives as long as the
-    manager process itself
-  */
-  return 0;
-}
-

--- 1.7/server-tools/instance-manager/listener.h	2006-10-27 15:30:46 +04:00
+++ 1.8/server-tools/instance-manager/listener.h	2006-10-27 15:30:46 +04:00
@@ -23,26 +23,35 @@
 #pragma interface
 #endif
 
+/*
+  Listener_thread - incapsulates listening functionality
+*/
 
-pthread_handler_t listener(void *arg);
+class Listener_thread
+{
+public:
+  Listener_thread();
+  ~Listener_thread();
 
-class Thread_registry;
-class User_map;
-class Instance_map;
+  bool start_detached();
 
-struct Listener_thread_args
-{
-  Thread_registry &thread_registry;
-  const User_map &user_map;
-  Instance_map &instance_map;
-
-  Listener_thread_args(Thread_registry &thread_registry_arg,
-                       const User_map &user_map_arg,
-                       Instance_map &instance_map_arg) :
-    thread_registry(thread_registry_arg)
-    ,user_map(user_map_arg)
-    ,instance_map(instance_map_arg)
-  {}
+private:
+  static const int LISTEN_BACK_LOG_SIZE= 5;     /* standard backlog size */
+  ulong total_connection_count;
+
+  int     sockets[2];
+  int     num_sockets;
+  fd_set  read_fds;
+
+private:
+  static void *listener_thread_func(void *listener);
+
+private:
+  void run();
+
+  void handle_new_mysql_connection(struct st_vio *vio);
+  int   create_tcp_socket();
+  int   create_unix_socket(struct sockaddr_un &unix_socket_address);
 };
 
 #endif // INCLUDES_MYSQL_INSTANCE_MANAGER_LISTENER_H

--- 1.37/server-tools/instance-manager/manager.cc	2006-10-27 15:30:46 +04:00
+++ 1.38/server-tools/instance-manager/manager.cc	2006-10-27 15:30:46 +04:00
@@ -36,34 +36,7 @@
 #include "thread_registry.h"
 #include "user_map.h"
 
-
-int create_pid_file(const char *pid_file_name, int pid)
-{
-  FILE *pid_file;
-
-  if (!(pid_file= my_fopen(pid_file_name, O_WRONLY | O_CREAT | O_BINARY,
-                           MYF(0))))
-  {
-    log_error("Error: can not create pid file '%s': %s (errno: %d)",
-              (const char *) pid_file_name,
-              (const char *) strerror(errno),
-              (int) errno);
-    return 1;
-  }
-
-  if (fprintf(pid_file, "%d\n", (int) pid) <= 0)
-  {
-    log_error("Error: can not write to pid file '%s': %s (errno: %d)",
-              (const char *) pid_file_name,
-              (const char *) strerror(errno),
-              (int) errno);
-    return 1;
-  }
-
-  my_fclose(pid_file, MYF(0));
-
-  return 0;
-}
+/* {{{ Platform-specific implementation. */
 
 #ifndef __WIN__
 void set_signals(sigset_t *mask)
@@ -119,57 +92,176 @@ int my_sigwait(const sigset_t *set, int 
 
 #endif
 
+/* }}} */
+
+/* {{{ Static-operations implementation. */
+
+Manager *Manager::manager_instance;
+
+
+Manager &Manager::get_instance()
+{
+  DBUG_ASSERT(manager_instance);
+  return *manager_instance;
+}
+
+
+int Manager::exec()
+{
+  Manager manager;
+
+  Manager::manager_instance= &manager;
+  manager.main();
+  Manager::manager_instance= NULL;
+
+  return 0;
+}
+
+/* }}} */
+
+/* {{{ Constructor & destructor. */
+
+Manager::Manager() :
+  manager_pid(0),
+
+  thread_registry(new Thread_registry()),
+  /*
+    All objects created in the Manager object live as long as thread_registry
+    lives, and thread_registry is alive until there are working threads.
+
+    There are two main purposes of the Thread Registry:
+      1. Interrupt blocking I/O and signal condition variables in case of
+         shutdown;
+      2. Wait for detached threads before shutting down the main thread.
+
+    NOTE:
+      1. Handling shutdown can be done in more elegant manner by introducing
+         Event (or Condition) object with support of logical operations.
+      2. Using Thread Registry to wait for detached threads is definitely not
+         the best way, because when Thread Registry unregisters an thread, the
+         thread is still alive. Accurate way to wait for threads to stop is
+         not using detached threads and join all threads before shutdown.
+  */
+
+  user_map(new User_map()),
+  instances(new Instance_map()),
+  guardian(new Guardian_thread(*instances)),
+  listener(new Listener_thread())
+{
+}
+
+
+Manager::~Manager()
+{
+  delete listener;
+  delete guardian;
+  delete instances;
+  delete user_map;
+
+  delete thread_registry;
+}
+
+/* }}} */
 
-void stop_all(Guardian_thread *guardian, Thread_registry *registry)
+/**************************************************************************
+  Re-read instance configuration file.
+
+  SYNOPSIS
+    flush_instances()
+
+  DESCRIPTION
+    This function will:
+     - clear the current list of instances. This removes both
+       running and stopped instances.
+     - load a new instance configuration from the file.
+     - pass on the new map to the guardian thread: it will start
+       all instances that are marked `guarded' and not yet started.
+    Note, as the check whether an instance is started is currently
+    very simple (returns TRUE if there is a MySQL server running
+    at the given port), this function has some peculiar
+    side-effects:
+     * if the port number of a running instance was changed, the
+       old instance is forgotten, even if it was running. The new
+       instance will be started at the new port.
+     * if the configuration was changed in a way that two
+       instances swapped their port numbers, the guardian thread
+       will not notice that and simply report that both instances
+       are configured successfully and running.
+    In order to avoid such side effects one should never call
+    FLUSH INSTANCES without prior stop of all running instances.
+
+  NOTE: The operation should be invoked with the following locks acquired:
+    - Guardian_thread;
+    - Instance_map;
+**************************************************************************/
+
+bool Manager::flush_instances()
+{
+  /*
+    Guardian thread relies on the instance map repository for guarding
+    instances. This is why refreshing instance map, we need (1) to stop
+    guardian (2) reload the instance map (3) reinitialize the guardian
+    with new instances.
+  */
+
+  if (instances->reset())
+    return TRUE;
+
+  if (instances->load())
+    return TRUE; /* Don't init guardian if we failed to load instances. */
+
+  guardian->init(); /* TODO: check error status. */
+  guardian->ping();
+
+  return FALSE;
+}
+
+/**************************************************************************
+  Request shutdown of guardian and threads registered in Thread_registry.
+
+  SYNOPSYS
+    stop_all_threads()
+**************************************************************************/
+
+void Manager::stop_all_threads()
 {
   /*
     Let guardian thread know that it should break it's processing cycle,
     once it wakes up.
   */
   guardian->request_shutdown();
-  /* wake guardian */
-  pthread_cond_signal(&guardian->COND_guardian);
-  /* stop all threads */
-  registry->deliver_shutdown();
+
+  /* Stop all threads from the thread registry. */
+  thread_registry->deliver_shutdown();
 }
 
-/*
-  manager - entry point to the main instance manager process: start
-  listener thread, write pid file and enter into signal handling.
-  See also comments in mysqlmanager.cc to picture general Instance Manager
-  architecture.
 
-  TODO: how about returning error status.
-*/
+/**************************************************************************
+  Main manager function.
 
-void manager()
+  SYNOPSYS
+    main()
+
+  DESCRIPTION
+    manager - entry point to the main instance manager process: start
+    listener thread, write pid file and enter into signal handling.
+    See also comments in mysqlmanager.cc to picture general Instance Manager
+    architecture.
+
+    TODO: how about returning error status.
+**************************************************************************/
+
+void Manager::main()
 {
   int err_code;
   const char *err_msg;
   bool shutdown_complete= FALSE;
 
-  Thread_registry thread_registry;
-  /*
-    All objects created in the manager() function live as long as
-    thread_registry lives, and thread_registry is alive until there are
-    working threads.
-  */
-
-  User_map user_map;
-  Instance_map instance_map(Options::Main::default_mysqld_path,
-                            thread_registry);
-  Guardian_thread guardian_thread(thread_registry,
-                                  &instance_map,
-                                  Options::Main::monitoring_interval);
-
-  Listener_thread_args listener_args(thread_registry, user_map, instance_map);
-
   manager_pid= getpid();
-  instance_map.guardian= &guardian_thread;
 
   /* Initialize instance map. */
 
-  if (instance_map.init())
+  if (instances->init())
   {
     log_error("Error: can not initialize instance list: out of memory.");
     return;
@@ -177,13 +269,13 @@ void manager()
 
   /* Initialize user map and load password file. */
 
-  if (user_map.init())
+  if (user_map->init())
   {
     log_error("Error: can not initialize user list: out of memory.");
     return;
   }
 
-  if ((err_code= user_map.load(Options::Main::password_file_name, &err_msg)))
+  if ((err_code= user_map->load(Options::Main::password_file_name, &err_msg)))
   {
     if (err_code == ERR_PASSWORD_FILE_DOES_NOT_EXIST &&
         Options::Main::mysqld_safe_compatible)
@@ -203,7 +295,7 @@ void manager()
     }
   }
 
-  /* write Instance Manager pid file */
+  /* Write Instance Manager pid file. */
 
   log_info("IM pid file: '%s'; PID: %d.",
            (const char *) Options::Main::pid_file_name,
@@ -218,98 +310,65 @@ void manager()
     NOTE: To work nicely with LinuxThreads, the signal thread is the first
     thread in the process.
 
-    NOTE:
-      After init_thr_alarm() call it's possible to call thr_alarm() (from
-      different threads), that results in sending ALARM signal to the alarm
-      thread (which can be the main thread). That signal can interrupt
-      blocking calls.
-
-      In other words, a blocking call can be interrupted in the main thread
-      after init_thr_alarm().
+    NOTE: After init_thr_alarm() call it's possible to call thr_alarm()
+    (from different threads), that results in sending ALARM signal to the
+    alarm thread (which can be the main thread). That signal can interrupt
+    blocking calls. In other words, a blocking call can be interrupted in
+    the main thread after init_thr_alarm().
   */
 
   sigset_t mask;
   set_signals(&mask);
 
-  /* create guardian thread */
-  {
-    pthread_t guardian_thd_id;
-    pthread_attr_t guardian_thd_attr;
-    int rc;
-
-    /*
-      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.
-
-      NOTE: Guardian uses thr_alarm() when detects current state of
-      instances (is_running()), but it is not interfere with
-      flush_instances() later in the code, because until flush_instances()
-      complete in the main thread, Guardian thread is not permitted to
-      process instances. And before flush_instances() there is no instances
-      to proceed.
-    */
+  /*
+    Initialize the Guardian.
 
-    pthread_attr_init(&guardian_thd_attr);
-    pthread_attr_setdetachstate(&guardian_thd_attr, PTHREAD_CREATE_DETACHED);
-    rc= set_stacksize_n_create_thread(&guardian_thd_id, &guardian_thd_attr,
-                                      guardian, &guardian_thread);
-    pthread_attr_destroy(&guardian_thd_attr);
-    if (rc)
-    {
-      log_error("manager(): set_stacksize_n_create_thread(guardian) failed");
-      goto err;
-    }
+    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.
+
+    NOTE: Guardian uses thr_alarm() when detects current state of instances
+    (is_running()), but it is not interfere with flush_instances() later in
+    the code, because until flush_instances() complete in the main thread,
+    Guardian thread is not permitted to process instances. And before
+    flush_instances() there is no instances to proceed.
+  */
 
+  if (guardian->start_detached())
+  {
+    log_error("Error: can not start Guardian thread.");
+    goto err;
   }
 
   /* Load instances. */
 
   {
-    instance_map.guardian->lock();
-    instance_map.lock();
+    instances->lock();
 
-    int flush_instances_status= instance_map.flush_instances();
+    int flush_instances_status= flush_instances();
 
-    instance_map.unlock();
-    instance_map.guardian->unlock();
+    instances->unlock();
 
     if (flush_instances_status)
     {
-      log_error("Cannot init instances repository. This might be caused by "
-        "the wrong config file options. For instance, missing mysqld "
-        "binary. Aborting.");
-      stop_all(&guardian_thread, &thread_registry);
+      log_error("Error: can not init instances repository.");
+      stop_all_threads();
       goto err;
     }
   }
 
-  /* create the listener */
+  /* Initialize the Listener. */
+
+  if (listener->start_detached())
   {
-    pthread_t listener_thd_id;
-    pthread_attr_t listener_thd_attr;
-    int rc;
-
-    pthread_attr_init(&listener_thd_attr);
-    pthread_attr_setdetachstate(&listener_thd_attr, PTHREAD_CREATE_DETACHED);
-    rc= set_stacksize_n_create_thread(&listener_thd_id, &listener_thd_attr,
-                                      listener, &listener_args);
-    pthread_attr_destroy(&listener_thd_attr);
-    if (rc)
-    {
-      log_error("manager(): set_stacksize_n_create_thread(listener) failed");
-      stop_all(&guardian_thread, &thread_registry);
-      goto err;
-    }
+    log_error("Error: can not start Listener thread.");
+    stop_all_threads();
+    goto err;
   }
 
-  /*
-    After the list of guarded instances have been initialized,
-    Guardian should start them.
-  */
-  pthread_cond_signal(&guardian_thread.COND_guardian);
+  /* Main loop. */
 
-  log_info("Main loop: started.");
+  log_info("Manager: started.");
 
   while (!shutdown_complete)
   {
@@ -318,8 +377,8 @@ void manager()
 
     if ((status= my_sigwait(&mask, &signo)) != 0)
     {
-      log_error("sigwait() failed");
-      stop_all(&guardian_thread, &thread_registry);
+      log_error("Error: sigwait() failed");
+      stop_all_threads();
       goto err;
     }
 
@@ -345,7 +404,7 @@ void manager()
   Bug #14164 IM tests fail on MacOS X (powermacg5)
 */
 #ifdef IGNORE_SIGHUP_SIGQUIT
-    if ( SIGHUP == signo )
+    if (SIGHUP == signo)
       continue;
 #endif
     if (THR_SERVER_ALARM == signo)
@@ -353,22 +412,21 @@ void manager()
     else
 #endif
     {
-      log_info("Main loop: got shutdown signal.");
+      log_info("Manager: got shutdown signal.");
 
-      if (!guardian_thread.is_stopped())
+      if (!guardian->is_stopped())
       {
-        guardian_thread.request_shutdown();
-        pthread_cond_signal(&guardian_thread.COND_guardian);
+        guardian->request_shutdown();
       }
       else
       {
-        thread_registry.deliver_shutdown();
+        thread_registry->deliver_shutdown();
         shutdown_complete= TRUE;
       }
     }
   }
 
-  log_info("Main loop: finished.");
+  log_info("Manager: finished.");
 
 err:
   /* delete the pid file */

--- 1.6/server-tools/instance-manager/manager.h	2006-10-27 15:30:46 +04:00
+++ 1.7/server-tools/instance-manager/manager.h	2006-10-27 15:30:46 +04:00
@@ -16,8 +16,88 @@
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 
-void manager();
+#if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE)
+#pragma interface
+#endif
 
-int create_pid_file(const char *pid_file_name, int pid);
+class Guardian_thread;
+class Instance;
+class Instance_map;
+class Listener_thread;
+class Thread_registry;
+class User_map;
+
+class Manager
+{
+public:
+  static Manager &get_instance();
+
+  static int exec();
+
+public:
+  inline Thread_registry &get_thread_registry();
+  inline User_map &get_user_map();
+  inline Instance_map &get_instances();
+  inline Guardian_thread &get_guardian();
+
+  inline int get_manager_pid() const;
+
+public:
+  /* Clear the configuration cache and reload the configuration file. */
+  bool flush_instances();
+
+private:
+  Manager();
+  ~Manager();
+
+  Manager(const Manager &);
+  Manager &operator =(const Manager &);
+
+private:
+  void stop_all_threads();
+  void main();
+
+private:
+  static Manager *manager_instance;
+
+private:
+  int manager_pid;
+
+  Thread_registry *thread_registry;
+
+  User_map *user_map;
+  Instance_map *instances;
+  Guardian_thread *guardian;
+  Listener_thread *listener;
+};
+
+/**************************************************************************
+  Manager inline impl
+**************************************************************************/
+
+inline Thread_registry &Manager::get_thread_registry()
+{
+  return *thread_registry;
+}
+
+inline User_map &Manager::get_user_map()
+{
+  return *user_map;
+}
+
+inline Instance_map &Manager::get_instances()
+{
+  return *instances;
+}
+
+inline Guardian_thread &Manager::get_guardian()
+{
+  return *guardian;
+}
+
+inline int Manager::get_manager_pid() const
+{
+  return manager_pid;
+}
 
 #endif // INCLUDES_MYSQL_INSTANCE_MANAGER_MANAGER_H

--- 1.19/server-tools/instance-manager/mysqlmanager.cc	2006-10-27 15:30:46 +04:00
+++ 1.20/server-tools/instance-manager/mysqlmanager.cc	2006-10-27 15:30:46 +04:00
@@ -31,6 +31,7 @@
 #include "log.h"
 #include "manager.h"
 #include "options.h"
+#include "priv.h"
 #include "user_management_commands.h"
 
 #ifdef __WIN__
@@ -117,7 +118,7 @@ int main(int argc, char *argv[])
     angel();
   }
 
-  manager();
+  Manager::exec();
 
 #else
 
@@ -131,7 +132,7 @@ int main(int argc, char *argv[])
   }
   else
   {
-    manager();
+    Manager::exec();
   }
 
 #endif
@@ -384,8 +385,8 @@ spawn:
     }
     /*
       mysqlmanager successfully exited, let's silently evaporate
-      If we return to main we fall into the manager() function, so let's
-      simply exit().
+      If we return to main we will fall into the manager functionality,
+      so let's simply exit().
     */
     exit(0);
   }

--- 1.6/server-tools/instance-manager/command.cc	2006-10-27 15:30:46 +04:00
+++ 1.7/server-tools/instance-manager/command.cc	2006-10-27 15:30:46 +04:00
@@ -20,9 +20,14 @@
 
 #include "command.h"
 
+#include "guardian.h"
+#include "instance_map.h"
+#include "manager.h"
 
-Command::Command(Instance_map *instance_map_arg)
-  :instance_map(instance_map_arg)
+
+Command::Command():
+  guardian(Manager::get_instance().get_guardian()),
+  instances(Manager::get_instance().get_instances())
 {}
 
 Command::~Command()

--- 1.6/server-tools/instance-manager/command.h	2006-10-27 15:30:46 +04:00
+++ 1.7/server-tools/instance-manager/command.h	2006-10-27 15:30:46 +04:00
@@ -24,6 +24,7 @@
 
 /* Class responsible for allocation of IM commands. */
 
+class Guardian_thread;
 class Instance_map;
 
 struct st_net;
@@ -36,7 +37,7 @@ struct st_net;
 class Command
 {
 public:
-  Command(Instance_map *instance_map_arg= 0);
+  Command();
   virtual ~Command();
 
   /*
@@ -53,7 +54,8 @@ public:
   virtual int execute(st_net *net, ulong connection_id) = 0;
 
 protected:
-  Instance_map *instance_map;
+  Guardian_thread &guardian;
+  Instance_map &instances;
 };
 
 #endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_COMMAND_H */

--- 1.36/server-tools/instance-manager/commands.cc	2006-10-27 15:30:46 +04:00
+++ 1.37/server-tools/instance-manager/commands.cc	2006-10-27 15:30:46 +04:00
@@ -171,30 +171,34 @@ int Show_instances::write_data(st_net *n
   my_bool err_status= FALSE;
 
   Instance *instance;
-  Instance_map::Iterator iterator(instance_map);
+  Instance_map::Iterator iterator(&instances);
 
-  instance_map->guardian->lock();
-  instance_map->lock();
+  instances.lock();
 
   while ((instance= iterator.next()))
   {
     Buffer send_buf;  /* buffer for packets */
     uint pos= 0;
 
+    instance->lock();
+
     const char *instance_name= instance->options.instance_name.str;
-    const char *state_name= instance_map->get_instance_state_name(instance);
+    const char *state_name= instance->get_state_name();
 
     if (store_to_protocol_packet(&send_buf, instance_name, &pos) ||
         store_to_protocol_packet(&send_buf, state_name, &pos) ||
         my_net_write(net, send_buf.buffer, pos))
     {
       err_status= TRUE;
-      break;
     }
+
+    instance->unlock();
+
+    if (err_status)
+      break;
   }
 
-  instance_map->unlock();
-  instance_map->guardian->unlock();
+  instances.unlock();
 
   return err_status ? ER_OUT_OF_RESOURCES : 0;
 }
@@ -214,38 +218,47 @@ int Show_instances::write_data(st_net *n
 
 int Flush_instances::execute(st_net *net, ulong connection_id)
 {
-  instance_map->guardian->lock();
-  instance_map->lock();
+  instances.lock();
 
-  if (instance_map->is_there_active_instance())
+  if (instances.is_there_active_instance())
   {
-    instance_map->unlock();
-    instance_map->guardian->unlock();
+    instances.unlock();
     return ER_THERE_IS_ACTIVE_INSTACE;
   }
 
-  if (instance_map->flush_instances())
+  if (Manager::get_instance().flush_instances())
   {
-    instance_map->unlock();
-    instance_map->guardian->unlock();
+    instances.unlock();
     return ER_OUT_OF_RESOURCES;
   }
 
-  instance_map->unlock();
-  instance_map->guardian->unlock();
+  instances.unlock();
 
   return net_send_ok(net, connection_id, NULL) ? ER_OUT_OF_RESOURCES : 0;
 }
 
 
 /**************************************************************************
+ Implementation of Instance_cmd.
+**************************************************************************/
+
+Instance_cmd::Instance_cmd(const LEX_STRING *instance_name_arg):
+   instance_name(instance_name_arg)
+{
+  /*
+    MT-NOTE: we can not make a search for Instance object here,
+    because it can dissappear after releasing the lock.
+  */
+}
+
+
+/**************************************************************************
  Implementation of Abstract_instance_cmd.
 **************************************************************************/
 
 Abstract_instance_cmd::Abstract_instance_cmd(
-  Instance_map *instance_map_arg, const LEX_STRING *instance_name_arg)
-  :Command(instance_map_arg),
-  instance_name(instance_name_arg)
+  const LEX_STRING *instance_name_arg)
+  :Instance_cmd(instance_name_arg)
 {
   /*
     MT-NOTE: we can not make a search for Instance object here,
@@ -257,22 +270,24 @@ Abstract_instance_cmd::Abstract_instance
 int Abstract_instance_cmd::execute(st_net *net, ulong connection_id)
 {
   int err_code;
+  Instance *instance;
+
+  instances.lock();
 
-  instance_map->lock();
+  instance= instances.find(get_instance_name());
 
+  if (!instance)
   {
-    Instance *instance= instance_map->find(get_instance_name());
+    instances.unlock();
+    return ER_BAD_INSTANCE_NAME;
+  }
 
-    if (!instance)
-    {
-      instance_map->unlock();
-      return ER_BAD_INSTANCE_NAME;
-    }
+  instance->lock();
+  instances.unlock();
 
-    err_code= execute_impl(net, instance);
-  }
+  err_code= execute_impl(net, instance);
 
-  instance_map->unlock();
+  instance->unlock();
 
   if (!err_code)
     err_code= send_ok_response(net, connection_id);
@@ -285,9 +300,8 @@ int Abstract_instance_cmd::execute(st_ne
  Implementation of Show_instance_status.
 **************************************************************************/
 
-Show_instance_status::Show_instance_status(Instance_map *instance_map_arg,
-                                           const LEX_STRING *instance_name_arg)
-  :Abstract_instance_cmd(instance_map_arg, instance_name_arg)
+Show_instance_status::Show_instance_status(const LEX_STRING *instance_name_arg)
+  :Abstract_instance_cmd(instance_name_arg)
 {
 }
 
@@ -371,10 +385,8 @@ int Show_instance_status::write_data(st_
   const char *version_num= "unknown";
   const char *mysqld_compatible_status;
 
-  instance_map->guardian->lock();
-  state_name= instance_map->get_instance_state_name(instance);
+  state_name= instance->get_state_name();
   mysqld_compatible_status= instance->is_mysqld_compatible() ? "yes" : "no";
-  instance_map->guardian->unlock();
 
   if (instance->options.mysqld_version)
   {
@@ -406,8 +418,8 @@ int Show_instance_status::write_data(st_
 **************************************************************************/
 
 Show_instance_options::Show_instance_options(
-  Instance_map *instance_map_arg, const LEX_STRING *instance_name_arg)
-  :Abstract_instance_cmd(instance_map_arg, instance_name_arg)
+  const LEX_STRING *instance_name_arg)
+  :Abstract_instance_cmd(instance_name_arg)
 {
 }
 
@@ -501,9 +513,8 @@ int Show_instance_options::write_data(st
  Implementation of Start_instance.
 **************************************************************************/
 
-Start_instance::Start_instance(Instance_map *instance_map_arg,
-                               const LEX_STRING *instance_name_arg)
-  :Abstract_instance_cmd(instance_map_arg, instance_name_arg)
+Start_instance::Start_instance(const LEX_STRING *instance_name_arg)
+  :Abstract_instance_cmd(instance_name_arg)
 {
 }
 
@@ -513,18 +524,21 @@ Start_instance::Start_instance(Instance_
 
   Possible error codes:
     ER_BAD_INSTANCE_NAME        The instance with the given name does not exist
-    ER_OUT_OF_RESOURCES         Not enough resources to complete the operation
+    ER_INSTANCE_MISCONFIGURED   The instance configuration is invalid
+    ER_INSTANCE_ALREADY_STARTED The instance is already started
+    ER_CANNOT_START_INSTANCE    The instance could not have been started
 */
 
 int Start_instance::execute_impl(st_net *net, Instance *instance)
 {
-  int err_code;
+  if (!instance->is_configured())
+    return ER_INSTANCE_MISCONFIGURED;
 
-  if ((err_code= instance->start()))
-    return err_code;
+  if (instance->is_active())
+    return ER_INSTANCE_ALREADY_STARTED;
 
-  if (!(instance->options.nonguarded))
-    instance_map->guardian->guard(instance);
+  if (instance->start_cmd())
+    return ER_CANNOT_START_INSTANCE;
 
   return 0;
 }
@@ -543,9 +557,8 @@ int Start_instance::send_ok_response(st_
  Implementation of Stop_instance.
 **************************************************************************/
 
-Stop_instance::Stop_instance(Instance_map *instance_map_arg,
-                             const LEX_STRING *instance_name_arg)
-  :Abstract_instance_cmd(instance_map_arg, instance_name_arg)
+Stop_instance::Stop_instance(const LEX_STRING *instance_name_arg)
+  :Abstract_instance_cmd(instance_name_arg)
 {
 }
 
@@ -555,18 +568,17 @@ Stop_instance::Stop_instance(Instance_ma
 
   Possible error codes:
     ER_BAD_INSTANCE_NAME        The instance with the given name does not exist
-    ER_OUT_OF_RESOURCES         Not enough resources to complete the operation
+    ER_STOP_INSTANCE            The instance can not be stopped
+    ER_INSTANCE_IS_NOT_STARTED  The instance has not been started yet
 */
 
 int Stop_instance::execute_impl(st_net *net, Instance *instance)
 {
-  int err_code;
+  if (!instance->is_active())
+    return ER_INSTANCE_IS_NOT_STARTED;
 
-  if (!(instance->options.nonguarded))
-    instance_map->guardian->stop_guard(instance);
-
-  if ((err_code= instance->stop()))
-    return err_code;
+  if (instance->stop_cmd())
+    return ER_STOP_INSTANCE;
 
   return 0;
 }
@@ -585,10 +597,8 @@ int Stop_instance::send_ok_response(st_n
  Implementation for Create_instance.
 **************************************************************************/
 
-Create_instance::Create_instance(Instance_map *instance_map_arg,
-                                 const LEX_STRING *instance_name_arg)
-  :Command(instance_map_arg),
-  instance_name(instance_name_arg)
+Create_instance::Create_instance(const LEX_STRING *instance_name_arg)
+  :Instance_cmd(instance_name_arg)
 {
 }
 
@@ -753,34 +763,34 @@ int Create_instance::execute(st_net *net
     on under acquired lock.
   */
 
-  instance_map->lock();
+  instances.lock();
 
-  if (instance_map->find(get_instance_name()))
+  if (instances.find(get_instance_name()))
   {
-    instance_map->unlock();
+    instances.unlock();
     return ER_CREATE_EXISTING_INSTANCE;
   }
 
-  if ((err_code= instance_map->create_instance(get_instance_name(), &options)))
+  if ((err_code= instances.create_instance(get_instance_name(), &options)))
   {
-    instance_map->unlock();
+    instances.unlock();
     return err_code;
   }
 
   if ((err_code= create_instance_in_file(get_instance_name(), &options)))
   {
-    Instance *instance= instance_map->find(get_instance_name());
+    Instance *instance= instances.find(get_instance_name());
 
     if (instance)
-      instance_map->remove_instance(instance); /* instance is deleted here. */
+      instances.remove_instance(instance); /* instance is deleted here. */
 
-    instance_map->unlock();
+    instances.unlock();
     return err_code;
   }
 
   /* That's all. */
 
-  instance_map->unlock();
+  instances.unlock();
 
   /* Send the result. */
 
@@ -795,9 +805,8 @@ int Create_instance::execute(st_net *net
  Implementation for Drop_instance.
 **************************************************************************/
 
-Drop_instance::Drop_instance(Instance_map *instance_map_arg,
-                             const LEX_STRING *instance_name_arg)
-  :Abstract_instance_cmd(instance_map_arg, instance_name_arg)
+Drop_instance::Drop_instance(const LEX_STRING *instance_name_arg)
+  :Instance_cmd(instance_name_arg)
 {
 }
 
@@ -811,14 +820,38 @@ Drop_instance::Drop_instance(Instance_ma
     ER_OUT_OF_RESOURCES         Not enough resources to complete the operation
 */
 
-int Drop_instance::execute_impl(st_net *net, Instance *instance)
+int Drop_instance::execute(st_net *net, ulong connection_id)
 {
   int err_code;
+  Instance *instance;
+
+  /* Lock Guardian, then Instance_map. */
+
+  instances.lock();
+
+  /* Find an instance. */
+
+  instance= instances.find(get_instance_name());
+
+  if (!instance)
+  {
+    instances.unlock();
+    return ER_BAD_INSTANCE_NAME;
+  }
+
+  instance->lock();
 
   /* Check that the instance is offline. */
 
-  if (instance_map->guardian->is_active(instance))
+  if (instance->is_active())
+  {
+    instance->unlock();
+    instances.unlock();
+
     return ER_DROP_ACTIVE_INSTANCE;
+  }
+
+  /* Try to remove instance from the file. */
 
   err_code= modify_defaults_file(Options::Main::config_file, NULL, NULL,
                                  get_instance_name()->str, MY_REMOVE_SECTION);
@@ -831,27 +864,30 @@ int Drop_instance::execute_impl(st_net *
               (const char *) get_instance_name()->str,
               (const char *) Options::Main::config_file,
               (int) err_code);
-  }
 
-  if (err_code)
+    instance->unlock();
+    instances.unlock();
+
     return modify_defaults_to_im_error[err_code];
+  }
 
-  /* Remove instance from the instance map hash and Guardian's list. */
+  /* Unlock the instance before destroy. */
 
-  if (!instance->options.nonguarded)
-    instance_map->guardian->stop_guard(instance);
+  instance->unlock();
 
-  if ((err_code= instance->stop()))
-    return err_code;
+  /*
+    Remove instance from the instance map
+    (the instance will be also destroyed here).
+  */
 
-  instance_map->remove_instance(instance);
+  instances.remove_instance(instance);
 
-  return 0;
-}
+  /* Unlock the collection. */
 
+  instances.unlock();
+
+  /* That's all: send ok. */
 
-int Drop_instance::send_ok_response(st_net *net, ulong connection_id)
-{
   if (net_send_ok(net, connection_id, "Instance dropped"))
     return ER_OUT_OF_RESOURCES;
 
@@ -863,11 +899,10 @@ int Drop_instance::send_ok_response(st_n
  Implementation for Show_instance_log.
 **************************************************************************/
 
-Show_instance_log::Show_instance_log(Instance_map *instance_map_arg,
-                                     const LEX_STRING *instance_name_arg,
+Show_instance_log::Show_instance_log(const LEX_STRING *instance_name_arg,
                                      Log_type log_type_arg,
                                      uint size_arg, uint offset_arg)
-  :Abstract_instance_cmd(instance_map_arg, instance_name_arg),
+  :Abstract_instance_cmd(instance_name_arg),
   log_type(log_type_arg),
   size(size_arg),
   offset(offset_arg)
@@ -1013,9 +1048,8 @@ int Show_instance_log::write_data(st_net
 **************************************************************************/
 
 Show_instance_log_files::Show_instance_log_files
-              (Instance_map *instance_map_arg,
-               const LEX_STRING *instance_name_arg)
-  :Abstract_instance_cmd(instance_map_arg, instance_name_arg)
+              (const LEX_STRING *instance_name_arg)
+  :Abstract_instance_cmd(instance_name_arg)
 {
 }
 
@@ -1214,9 +1248,8 @@ C_MODE_END
 
 /**************************************************************************/
 
-Abstract_option_cmd::Abstract_option_cmd(Instance_map *instance_map_arg)
-  :Command(instance_map_arg),
-  initialized(FALSE)
+Abstract_option_cmd::Abstract_option_cmd()
+  :initialized(FALSE)
 {
 }
 
@@ -1313,11 +1346,11 @@ int Abstract_option_cmd::execute(st_net 
 {
   int err_code;
 
-  instance_map->lock();
+  instances.lock();
 
   err_code= execute_impl(net, connection_id);
 
-  instance_map->unlock();
+  instances.unlock();
 
   return err_code;
 }
@@ -1351,7 +1384,7 @@ Abstract_option_cmd::get_instance_option
 
 int Abstract_option_cmd::execute_impl(st_net *net, ulong connection_id)
 {
-  int err_code;
+  int err_code= 0;
 
   /* Check that all the specified instances exist and are offline. */
 
@@ -1360,12 +1393,18 @@ int Abstract_option_cmd::execute_impl(st
     Instance_options_list *lst=
       (Instance_options_list *) hash_element(&instance_options_map, i);
 
-    lst->instance= instance_map->find(lst->get_instance_name());
+    bool instance_is_active;
+
+    lst->instance= instances.find(lst->get_instance_name());
 
     if (!lst->instance)
       return ER_BAD_INSTANCE_NAME;
 
-    if (instance_map->guardian->is_active(lst->instance))
+    lst->instance->lock();
+    instance_is_active= lst->instance->is_active();
+    lst->instance->unlock();
+
+    if (instance_is_active)
       return ER_INSTANCE_IS_ACTIVE;
   }
 
@@ -1376,6 +1415,8 @@ int Abstract_option_cmd::execute_impl(st
     Instance_options_list *lst=
       (Instance_options_list *) hash_element(&instance_options_map, i);
 
+    lst->instance->lock();
+
     for (int j= 0; j < lst->options.get_size(); ++j)
     {
       Named_value option= lst->options.get_element(j);
@@ -1385,6 +1426,8 @@ int Abstract_option_cmd::execute_impl(st
         break;
     }
 
+    lst->instance->unlock();
+
     if (err_code)
       break;
   }
@@ -1400,8 +1443,7 @@ int Abstract_option_cmd::execute_impl(st
  Implementation of Set_option.
 **************************************************************************/
 
-Set_option::Set_option(Instance_map *instance_map_arg)
-  :Abstract_option_cmd(instance_map_arg)
+Set_option::Set_option()
 {
 }
 
@@ -1580,8 +1622,7 @@ int Set_option::process_option(Instance 
  Implementation of Unset_option.
 **************************************************************************/
 
-Unset_option::Unset_option(Instance_map *instance_map_arg)
-  :Abstract_option_cmd(instance_map_arg)
+Unset_option::Unset_option()
 {
 }
 

--- 1.11/server-tools/instance-manager/commands.h	2006-10-27 15:30:46 +04:00
+++ 1.12/server-tools/instance-manager/commands.h	2006-10-27 15:30:46 +04:00
@@ -38,7 +38,7 @@
 class Show_instances : public Command
 {
 public:
-  Show_instances(Instance_map *instance_map_arg): Command(instance_map_arg)
+  Show_instances()
   {}
 
   int execute(st_net *net, ulong connection_id);
@@ -57,7 +57,7 @@ private:
 class Flush_instances : public Command
 {
 public:
-  Flush_instances(Instance_map *instance_map_arg): Command(instance_map_arg)
+  Flush_instances()
   {}
 
   int execute(st_net *net, ulong connection_id);
@@ -65,14 +65,33 @@ public:
 
 
 /*
+  Base class for Instance-specific commands.
+*/
+
+class Instance_cmd : public Command
+{
+public:
+  Instance_cmd(const LEX_STRING *instance_name_arg);
+
+protected:
+  inline const LEX_STRING *get_instance_name() const
+  {
+    return instance_name.get_str();
+  }
+
+private:
+  Instance_name instance_name;
+};
+
+
+/*
   Abstract class for Instance-specific commands.
 */
 
-class Abstract_instance_cmd : public Command
+class Abstract_instance_cmd : public Instance_cmd
 {
 public:
-  Abstract_instance_cmd(Instance_map *instance_map_arg,
-                        const LEX_STRING *instance_name_arg);
+  Abstract_instance_cmd(const LEX_STRING *instance_name_arg);
 
 public:
   virtual int execute(st_net *net, ulong connection_id);
@@ -88,15 +107,6 @@ protected:
     MT-NOTE: this operation is called under released Instance_map's lock.
   */
   virtual int send_ok_response(st_net *net, ulong connection_id) = 0;
-
-protected:
-  inline const LEX_STRING *get_instance_name() const
-  {
-    return instance_name.get_str();
-  }
-
-private:
-  Instance_name instance_name;
 };
 
 
@@ -108,8 +118,7 @@ private:
 class Show_instance_status : public Abstract_instance_cmd
 {
 public:
-  Show_instance_status(Instance_map *instance_map_arg,
-                       const LEX_STRING *instance_name_arg);
+  Show_instance_status(const LEX_STRING *instance_name_arg);
 
 protected:
   virtual int execute_impl(st_net *net, Instance *instance);
@@ -129,8 +138,7 @@ private:
 class Show_instance_options : public Abstract_instance_cmd
 {
 public:
-  Show_instance_options(Instance_map *instance_map_arg,
-                        const LEX_STRING *instance_name_arg);
+  Show_instance_options(const LEX_STRING *instance_name_arg);
 
 protected:
   virtual int execute_impl(st_net *net, Instance *instance);
@@ -150,8 +158,7 @@ private:
 class Start_instance : public Abstract_instance_cmd
 {
 public:
-  Start_instance(Instance_map *instance_map_arg,
-                 const LEX_STRING *instance_name_arg);
+  Start_instance(const LEX_STRING *instance_name_arg);
 
 protected:
   virtual int execute_impl(st_net *net, Instance *instance);
@@ -167,8 +174,7 @@ protected:
 class Stop_instance : public Abstract_instance_cmd
 {
 public:
-  Stop_instance(Instance_map *instance_map_arg,
-                const LEX_STRING *instance_name_arg);
+  Stop_instance(const LEX_STRING *instance_name_arg);
 
 protected:
   virtual int execute_impl(st_net *net, Instance *instance);
@@ -181,11 +187,10 @@ protected:
   Grammar: CREATE INSTANCE <instance_name> [<options>]
 */
 
-class Create_instance : public Command
+class Create_instance : public Instance_cmd
 {
 public:
-  Create_instance(Instance_map *instance_map_arg,
-                  const LEX_STRING *instance_name_arg);
+  Create_instance(const LEX_STRING *instance_name_arg);
 
 public:
   bool init(const char **text);
@@ -193,17 +198,10 @@ public:
 protected:
   virtual int execute(st_net *net, ulong connection_id);
 
-  inline const LEX_STRING *get_instance_name() const
-  {
-    return instance_name.get_str();
-  }
-
 private:
   bool parse_args(const char **text);
 
 private:
-  Instance_name instance_name;
-
   Named_value_arr options;
 };
 
@@ -217,15 +215,13 @@ private:
   is removed from the instance map.
 */
 
-class Drop_instance : public Abstract_instance_cmd
+class Drop_instance : public Instance_cmd
 {
 public:
-  Drop_instance(Instance_map *instance_map_arg,
-                const LEX_STRING *instance_name_arg);
+  Drop_instance(const LEX_STRING *instance_name_arg);
 
 protected:
-  virtual int execute_impl(st_net *net, Instance *instance);
-  virtual int send_ok_response(st_net *net, ulong connection_id);
+  virtual int execute(st_net *net, ulong connection_id);
 };
 
 
@@ -238,8 +234,7 @@ protected:
 class Show_instance_log : public Abstract_instance_cmd
 {
 public:
-  Show_instance_log(Instance_map *instance_map_arg,
-                    const LEX_STRING *instance_name_arg,
+  Show_instance_log(const LEX_STRING *instance_name_arg,
                     Log_type log_type_arg, uint size_arg, uint offset_arg);
 
 protected:
@@ -266,8 +261,7 @@ private:
 class Show_instance_log_files : public Abstract_instance_cmd
 {
 public:
-  Show_instance_log_files(Instance_map *instance_map_arg,
-                          const LEX_STRING *instance_name_arg);
+  Show_instance_log_files(const LEX_STRING *instance_name_arg);
 
 protected:
   virtual int execute_impl(st_net *net, Instance *instance);
@@ -299,7 +293,7 @@ public:
   virtual int execute(st_net *net, ulong connection_id);
 
 protected:
-  Abstract_option_cmd(Instance_map *instance_map_arg);
+  Abstract_option_cmd();
 
   int correct_file(Instance *instance, Named_value *option, bool skip);
 
@@ -327,7 +321,7 @@ private:
 class Set_option : public Abstract_option_cmd
 {
 public:
-  Set_option(Instance_map *instance_map_arg);
+  Set_option();
 
 protected:
   virtual bool parse_args(const char **text);
@@ -343,7 +337,7 @@ protected:
 class Unset_option: public Abstract_option_cmd
 {
 public:
-  Unset_option(Instance_map *instance_map_arg);
+  Unset_option();
 
 protected:
   virtual bool parse_args(const char **text);
@@ -364,7 +358,7 @@ class Syntax_error : public Command
 {
 public:
   /* This is just to avoid compiler warning. */
-  Syntax_error() :Command(NULL)
+  Syntax_error()
   {}
 
 public:

--- 1.28/server-tools/instance-manager/guardian.cc	2006-10-27 15:30:46 +04:00
+++ 1.29/server-tools/instance-manager/guardian.cc	2006-10-27 15:30:46 +04:00
@@ -28,203 +28,312 @@
 #include "instance.h"
 #include "instance_map.h"
 #include "log.h"
+#include "manager.h"
 #include "mysql_manager_error.h"
+#include "options.h"
+#include "thread_registry.h"
 
 
-pthread_handler_t guardian(void *arg)
+/**************************************************************************
+  Entry point of Guardian thread.
+**************************************************************************/
+
+void *Guardian_thread::guardian_thread_func(void *guardian)
+{
+  ((Guardian_thread *) guardian)->run();
+
+  return NULL;
+}
+
+/* {{{ Constructor & destructor. */
+
+Guardian_thread::Guardian_thread(Instance_map &instances_arg):
+  instances(instances_arg),
+  shutdown_requested(FALSE),
+  stopped(TRUE)
 {
-  Guardian_thread *guardian_thread= (Guardian_thread *) arg;
-  guardian_thread->run();
-  return 0;
+  pthread_mutex_init(&LOCK_guardian, 0);
+  pthread_cond_init(&COND_guardian, 0);
 }
 
 
-const char *
-Guardian_thread::get_instance_state_name(enum_instance_state state)
+Guardian_thread::~Guardian_thread()
 {
-  switch (state) {
-  case NOT_STARTED:
-    return "offline";
+  /*
+    NOTE: it's necessary to synchronize here, because Guiardian thread can be
+    still alive an hold the mutex (because it is detached and we have no
+    control over it).
+  */
+  lock();
+  unlock();
+
+  pthread_mutex_destroy(&LOCK_guardian);
+  pthread_cond_destroy(&COND_guardian);
+}
+
+/* }}} */
+
+
+/**************************************************************************
+  Prepare list of instances.
+
+  SYNOPSYS
+    init()
 
-  case STARTING:
-    return "starting";
+  NOTE: The operation should be invoked with acquired LOCK_instance_map.
 
-  case STARTED:
-    return "online";
+  RETURN
+    FALSE - ok
+    TRUE  - error occured
+**************************************************************************/
 
-  case JUST_CRASHED:
-    return "failed";
+bool Guardian_thread::init()
+{
+  Instance *instance;
+  Instance_map::Iterator instances_it(&instances);
 
-  case CRASHED:
-    return "crashed";
+  while ((instance= instances_it.next()))
+  {
+    instance->lock();
 
-  case CRASHED_AND_ABANDONED:
-    return "abandoned";
+    instance->reset_stat();
+    instance->set_state(Instance::NOT_STARTED);
 
-  case STOPPING:
-    return "stopping";
+    instance->unlock();
   }
 
-  return NULL; /* just to ignore compiler warning. */
+  return FALSE;
 }
 
 
-Guardian_thread::Guardian_thread(Thread_registry &thread_registry_arg,
-                                 Instance_map *instance_map_arg,
-                                 uint monitoring_interval_arg) :
-  Guardian_thread_args(thread_registry_arg, instance_map_arg,
-                       monitoring_interval_arg),
-  thread_info(pthread_self(), TRUE), guarded_instances(0)
+/**************************************************************************
+  Lock Guardian_thread.
+**************************************************************************/
+
+void Guardian_thread::lock()
 {
-  pthread_mutex_init(&LOCK_guardian, 0);
-  pthread_cond_init(&COND_guardian, 0);
-  shutdown_requested= FALSE;
-  stopped= FALSE;
-  init_alloc_root(&alloc, MEM_ROOT_BLOCK_SIZE, 0);
+  pthread_mutex_lock(&LOCK_guardian);
 }
 
 
-Guardian_thread::~Guardian_thread()
+/**************************************************************************
+  Unlock Guardian_thread.
+**************************************************************************/
+
+void Guardian_thread::unlock()
 {
-  /* delay guardian destruction to the moment when no one needs it */
-  pthread_mutex_lock(&LOCK_guardian);
-  free_root(&alloc, MYF(0));
   pthread_mutex_unlock(&LOCK_guardian);
-  pthread_mutex_destroy(&LOCK_guardian);
-  pthread_cond_destroy(&COND_guardian);
 }
 
 
+/**************************************************************************
+  Start Guardian_thread.
+**************************************************************************/
+
+bool Guardian_thread::start_detached()
+{
+  pthread_t thd_id;
+  pthread_attr_t attr;
+  int rc;
+
+  lock();
+  if (!stopped)
+  {
+    log_info("Guardian: already started.");
+    return TRUE;
+  }
+  stopped= FALSE;
+  unlock();
+
+  pthread_attr_init(&attr);
+  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+  rc= set_stacksize_n_create_thread(&thd_id, &attr,
+                                    guardian_thread_func, this);
+  pthread_attr_destroy(&attr);
+
+  return rc != 0;
+}
+
+
+/**************************************************************************
+  Send request to stop Guardian_thread.
+**************************************************************************/
+
 void Guardian_thread::request_shutdown()
 {
-  pthread_mutex_lock(&LOCK_guardian);
-  /* stop instances or just clean up Guardian repository */
   stop_instances();
+
+  lock();
   shutdown_requested= TRUE;
-  pthread_mutex_unlock(&LOCK_guardian);
+  ping();
+  unlock();
+}
+
+
+/**************************************************************************
+  Return TRUE is Guardian_thread is stopped.
+**************************************************************************/
+
+bool Guardian_thread::is_stopped()
+{
+  bool var;
+
+  lock();
+  var= stopped;
+  unlock();
+
+  return var;
+}
+
+
+/**************************************************************************
+  Process an instance.
+**************************************************************************/
+
+void Guardian_thread::ping()
+{
+  pthread_cond_signal(&COND_guardian);
 }
 
 
-void Guardian_thread::process_instance(Instance *instance,
-                                       GUARD_NODE *current_node,
-                                       LIST **guarded_instances,
-                                       LIST *node)
+/**************************************************************************
+  Process an instance.
+**************************************************************************/
+
+void Guardian_thread::process_instance(Instance *instance)
 {
-  uint waitchild= (uint) 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)
+  if (instance->get_state() == Instance::STOPPING)
   {
     /* this brach is executed during shutdown */
-    if (instance->options.shutdown_delay)
-    {
-      /*
-        NOTE: it is important to check shutdown_delay here, but use
-        shutdown_delay_val. The idea is that if the option is unset,
-        shutdown_delay will be NULL, but shutdown_delay_val will not be reset.
-      */
-      waitchild= instance->options.shutdown_delay_val;
-    }
 
     /* this returns TRUE if and only if an instance was stopped for sure */
     if (instance->is_crashed())
-      *guarded_instances= list_delete(*guarded_instances, node);
-    else if ( (uint) (current_time - current_node->last_checked) > waitchild)
     {
-      instance->kill_instance(SIGKILL);
-      /*
-        Later we do node= node->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, node);
+      log_info("Guardian: '%s' stopped.",
+               (const char *) instance->get_name()->str);
+
+      instance->set_state(Instance::STOPPED);
+    }
+    else if ((uint) (current_time - instance->last_checked) >=
+             instance->options.get_shutdown_delay())
+    {
+      log_info("Guardian: '%s' hasn't stopped within %d secs.",
+               (const char *) instance->get_name()->str,
+               (int) instance->options.get_shutdown_delay());
+
+      instance->kill_mysqld(SIGKILL);
+
+      log_info("Guardian: pretend that '%s' is killed.",
+               (const char *) instance->get_name()->str);
+
+      instance->set_state(Instance::STOPPED);
+    }
+    else
+    {
+      log_info("Guardian: waiting for '%s' to stop (%d secs left).",
+               (const char *) instance->get_name()->str,
+               (int) (instance->options.get_shutdown_delay() -
+                      current_time + instance->last_checked));
     }
 
     return;
   }
 
-  if (instance->is_running())
+  if (instance->is_mysqld_running())
   {
     /* The instance can be contacted  on it's port */
 
     /* If STARTING also check that pidfile has been created */
-    if (current_node->state == STARTING &&
-        current_node->instance->options.get_pid() == 0)
+    if (instance->get_state() == Instance::STARTING &&
+        instance->options.load_pid() == 0)
     {
       /* Pid file not created yet, don't go to STARTED state yet  */
     }
-    else if (current_node->state != STARTED)
+    else if (instance->get_state() != Instance::STARTED)
     {
       /* clear status fields */
-      log_info("guardian: instance '%s' is running, set state to STARTED.",
+      log_info("Guardian: '%s' is running, set state to STARTED.",
                (const char *) instance->options.instance_name.str);
-      current_node->restart_counter= 0;
-      current_node->crash_moment= 0;
-      current_node->state= STARTED;
+      instance->restart_counter= 0;
+      instance->crash_moment= 0;
+      instance->set_state(Instance::STARTED);
     }
   }
   else
   {
-    switch (current_node->state) {
-    case NOT_STARTED:
-      log_info("guardian: starting instance '%s'...",
+    switch (instance->get_state()) {
+    case Instance::NOT_STARTED:
+      log_info("Guardian: starting '%s'...",
                (const char *) instance->options.instance_name.str);
 
-      /* NOTE, set state to STARTING _before_ start() is called */
-      current_node->state= STARTING;
-      instance->start();
-      current_node->last_checked= current_time;
-      break;
-    case STARTED:     /* fallthrough */
-    case STARTING:    /* let the instance start or crash */
-      if (instance->is_crashed())
+      /* NOTE: set state to STARTING _before_ start() is called. */
+
+      instance->set_state(Instance::STARTING);
+      instance->last_checked= current_time;
+
+      instance->start_mysqld();
+
+      return;
+
+    case Instance::STARTED:     /* fallthrough */
+    case Instance::STARTING:    /* let the instance start or crash */
+      if (!instance->is_crashed())
+        return;
+
+      instance->crash_moment= current_time;
+      instance->last_checked= current_time;
+      instance->set_state(Instance::JUST_CRASHED);
+      /* fallthrough -- restart an instance immediately */
+
+    case Instance::JUST_CRASHED:
+      if (current_time - instance->crash_moment <= 2)
       {
-        current_node->crash_moment= current_time;
-        current_node->last_checked= current_time;
-        current_node->state= JUST_CRASHED;
-        /* fallthrough -- restart an instance immediately */
+        if (instance->is_crashed())
+        {
+          instance->start_mysqld();
+          log_info("Guardian: starting '%s'...",
+                   (const char *) instance->options.instance_name.str);
+        }
       }
       else
-        break;
-    case JUST_CRASHED:
-      if (current_time - current_node->crash_moment <= 2)
+        instance->set_state(Instance::CRASHED);
+
+      return;
+
+    case Instance::CRASHED:    /* just regular restarts */
+      if (current_time - instance->last_checked <=
+          Options::Main::monitoring_interval)
+        return;
+
+      if (instance->restart_counter < restart_retry)
       {
         if (instance->is_crashed())
         {
-          instance->start();
-          log_info("guardian: starting instance '%s'...",
+          instance->start_mysqld();
+          instance->last_checked= current_time;
+          instance->restart_counter++;
+
+          log_info("Guardian: restarting '%s'...",
                    (const char *) instance->options.instance_name.str);
         }
       }
       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))
-        {
-          if (instance->is_crashed())
-          {
-            instance->start();
-            current_node->last_checked= current_time;
-            current_node->restart_counter++;
-            log_info("guardian: restarting instance '%s'...",
-                     (const char *) instance->options.instance_name.str);
-          }
-        }
-        else
-        {
-          log_info("guardian: cannot start instance %s. Abandoning attempts "
-                   "to (re)start it", instance->options.instance_name.str);
-          current_node->state= CRASHED_AND_ABANDONED;
-        }
+        log_info("Guardian: can not start '%s'. "
+                 "Abandoning attempts to (re)start it",
+                 (const char *) instance->options.instance_name.str);
+
+        instance->set_state(Instance::CRASHED_AND_ABANDONED);
       }
-      break;
-    case CRASHED_AND_ABANDONED:
-      break; /* do nothing */
+
+      return;
+
+    case Instance::CRASHED_AND_ABANDONED:
+      return; /* do nothing */
+
     default:
       DBUG_ASSERT(0);
     }
@@ -232,189 +341,88 @@ void Guardian_thread::process_instance(I
 }
 
 
-/*
-  Run guardian thread
+/*************************************************************************
+  Main function of Guardian thread.
 
   SYNOPSYS
     run()
 
   DESCRIPTION
-
     Check for all guarded instances and restart them if needed. If everything
     is fine go and sleep for some time.
-*/
+*************************************************************************/
 
 void Guardian_thread::run()
 {
-  Instance *instance;
-  LIST *node;
   struct timespec timeout;
+  Thread_registry &thread_registry=
+    Manager::get_instance().get_thread_registry();
+  Thread_info thread_info(pthread_self(), TRUE);
 
   log_info("Guardian: started.");
 
   thread_registry.register_thread(&thread_info);
 
   my_thread_init();
-  pthread_mutex_lock(&LOCK_guardian);
 
   /* loop, until all instances were shut down at the end */
-  while (!(shutdown_requested && (guarded_instances == NULL)))
+  while (true)
   {
-    node= guarded_instances;
+    Instance_map::Iterator instances_it(&instances);
+    Instance *instance;
+    bool all_instances_stopped= TRUE;
 
-    while (node != NULL)
-    {
-      GUARD_NODE *current_node= (GUARD_NODE *) node->data;
-      instance= ((GUARD_NODE *) node->data)->instance;
-      process_instance(instance, current_node, &guarded_instances, node);
+    instances.lock();
 
-      node= node->next;
-    }
-    timeout.tv_sec= time(NULL) + monitoring_interval;
-    timeout.tv_nsec= 0;
-
-    /* check the loop predicate before sleeping */
-    if (!(shutdown_requested && (!(guarded_instances))))
-      thread_registry.cond_timedwait(&thread_info, &COND_guardian,
-                                     &LOCK_guardian, &timeout);
-  }
-
-  log_info("Guardian: stopped.");
-
-  stopped= TRUE;
-  pthread_mutex_unlock(&LOCK_guardian);
-  /* now, when the Guardian is stopped we can stop the IM */
-  thread_registry.unregister_thread(&thread_info);
-  thread_registry.request_shutdown();
-  my_thread_end();
-
-  log_info("Guardian: finished.");
-}
-
-
-int Guardian_thread::is_stopped()
-{
-  int var;
-  pthread_mutex_lock(&LOCK_guardian);
-  var= stopped;
-  pthread_mutex_unlock(&LOCK_guardian);
-  return var;
-}
+    while ((instance= instances_it.next()))
+    {
+      instance->lock();
 
+      if (!instance->is_guarded() ||
+          instance->get_state() == Instance::STOPPED)
+      {
+        instance->unlock();
+        continue;
+      }
 
-/*
-  Initialize the list of guarded instances: loop through the Instance_map and
-  add all of the instances, which don't have 'nonguarded' option specified.
+      process_instance(instance);
 
-  SYNOPSYS
-    Guardian_thread::init()
+      if (instance->get_state() != Instance::STOPPED)
+        all_instances_stopped= FALSE;
 
-  NOTE: The operation should be invoked with the following locks acquired:
-    - Guardian_thread;
-    - Instance_map;
+      instance->unlock();
+    }
 
-  RETURN
-    0 - ok
-    1 - error occured
-*/
+    instances.unlock();
 
-int Guardian_thread::init()
-{
-  Instance *instance;
-  Instance_map::Iterator iterator(instance_map);
+    lock();
+    if (shutdown_requested && all_instances_stopped)
+    {
+      log_info("Guardian: all guarded mysqlds stopped.");
 
-  /* clear the list of guarded instances */
-  free_root(&alloc, MYF(0));
-  init_alloc_root(&alloc, MEM_ROOT_BLOCK_SIZE, 0);
-  guarded_instances= NULL;
+      stopped= TRUE;
+      unlock();
+      break;
+    }
 
-  while ((instance= iterator.next()))
-  {
-    if (instance->options.nonguarded)
-      continue;
+    timeout.tv_sec= time(NULL) + Options::Main::monitoring_interval;
+    timeout.tv_nsec= 0;
 
-    if (guard(instance, TRUE))                /* do not lock guardian */
-      return 1;
+    thread_registry.cond_timedwait(&thread_info, &COND_guardian,
+                                   &LOCK_guardian, &timeout);
+    unlock();
   }
 
-  return 0;
-}
-
-
-/*
-  Add instance to the Guardian list
-
-  SYNOPSYS
-    guard()
-    instance           the instance to be guarded
-    nolock             whether we prefer do not lock Guardian here,
-                       but use external locking instead
-
-  DESCRIPTION
-
-    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, bool nolock)
-{
-  LIST *node;
-  GUARD_NODE *content;
-
-  node= (LIST *) alloc_root(&alloc, sizeof(LIST));
-  content= (GUARD_NODE *) alloc_root(&alloc, sizeof(GUARD_NODE));
-
-  if ((!(node)) || (!(content)))
-    return 1;
-  /* we store the pointers to instances from the instance_map's MEM_ROOT */
-  content->instance= instance;
-  content->restart_counter= 0;
-  content->crash_moment= 0;
-  content->state= NOT_STARTED;
-  node->data= (void*) content;
-
-  if (nolock)
-    guarded_instances= list_add(guarded_instances, node);
-  else
-  {
-    pthread_mutex_lock(&LOCK_guardian);
-    guarded_instances= list_add(guarded_instances, node);
-    pthread_mutex_unlock(&LOCK_guardian);
-  }
+  /* now, when the Guardian is stopped we can stop the IM */
+  thread_registry.unregister_thread(&thread_info);
+  thread_registry.request_shutdown();
+  my_thread_end();
 
-  return 0;
+  log_info("Guardian: finished.");
 }
 
 
-/*
-  TODO: perhaps it would make sense to create a pool of the LIST nodeents
-  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).
-*/
-
-int Guardian_thread::stop_guard(Instance *instance)
-{
-  LIST *node;
-
-  pthread_mutex_lock(&LOCK_guardian);
-
-  node= find_instance_node(instance);
-
-  if (node != NULL)
-    guarded_instances= list_delete(guarded_instances, node);
-
-  pthread_mutex_unlock(&LOCK_guardian);
-
-  /* if there is nothing to delete it is also fine */
-  return 0;
-}
-
-/*
+/**************************************************************************
   An internal method which is called at shutdown to unregister instances and
   attempt to stop them if requested.
 
@@ -425,88 +433,48 @@ int Guardian_thread::stop_guard(Instance
     Loops through the guarded_instances list and prepares them for shutdown.
     For each instance we issue a stop command and change the state
     accordingly.
+**************************************************************************/
 
-  NOTE
-    Guardian object should be locked by the calling function.
+void Guardian_thread::stop_instances()
+{
+  Instance_map::Iterator instances_it(&instances);
+  Instance *instance;
 
-  RETURN
-    0 - ok
-    1 - error occured
-*/
-
-int Guardian_thread::stop_instances()
-{
-  LIST *node;
-  node= guarded_instances;
-  while (node != NULL)
+  instances.lock();
+
+  while ((instance= instances_it.next()))
   {
-    GUARD_NODE *current_node= (GUARD_NODE *) node->data;
+    instance->lock();
+
+    if (!instance->is_guarded() ||
+        instance->get_state() == Instance::STOPPED)
+    {
+      instance->unlock();
+      continue;
+    }
+
     /*
       If instance is running or was running (and now probably hanging),
       request stop.
     */
-    if (current_node->instance->is_running() ||
-        (current_node->state == STARTED))
+
+    if (instance->is_mysqld_running() ||
+        instance->get_state() == Instance::STARTED)
     {
-      current_node->state= STOPPING;
-      current_node->last_checked= time(NULL);
+      instance->set_state(Instance::STOPPING);
+      instance->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;
-}
-
-
-void Guardian_thread::lock()
-{
-  pthread_mutex_lock(&LOCK_guardian);
-}
-
-
-void Guardian_thread::unlock()
-{
-  pthread_mutex_unlock(&LOCK_guardian);
-}
-
-
-LIST *Guardian_thread::find_instance_node(Instance *instance)
-{
-  LIST *node= guarded_instances;
+    {
+      /* Otherwise mark it as STOPPED. */
+      instance->set_state(Instance::STOPPED);
+    }
 
-  while (node != NULL)
-  {
-    /*
-      We compare only pointers, as we always use pointers from the
-      instance_map's MEM_ROOT.
-    */
-    if (((GUARD_NODE *) node->data)->instance == instance)
-      return node;
+    /* But try to kill it anyway. Just in case */
+    instance->kill_mysqld(SIGTERM);
 
-    node= node->next;
+    instance->unlock();
   }
 
-  return NULL;
-}
-
-
-bool Guardian_thread::is_active(Instance *instance)
-{
-  bool guarded;
-
-  lock();
-
-  guarded= find_instance_node(instance) != NULL;
-
-  /* is_running() can take a long time, so let's unlock mutex first. */
-  unlock();
-
-  if (guarded)
-    return true;
-
-  return instance->is_running();
+  instances.unlock();
 }

--- 1.14/server-tools/instance-manager/guardian.h	2006-10-27 15:30:46 +04:00
+++ 1.15/server-tools/instance-manager/guardian.h	2006-10-27 15:30:46 +04:00
@@ -20,130 +20,87 @@
 #include <my_sys.h>
 #include <my_list.h>
 
-#include "thread_registry.h"
-
 #if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE)
 #pragma interface
 #endif
 
 class Instance;
 class Instance_map;
-class Thread_registry;
-struct GUARD_NODE;
-
-pthread_handler_t guardian(void *arg);
-
-struct Guardian_thread_args
-{
-  Thread_registry &thread_registry;
-  Instance_map *instance_map;
-  int monitoring_interval;
-
-  Guardian_thread_args(Thread_registry &thread_registry_arg,
-                       Instance_map *instance_map_arg,
-                       uint monitoring_interval_arg) :
-    thread_registry(thread_registry_arg),
-    instance_map(instance_map_arg),
-    monitoring_interval(monitoring_interval_arg)
-  {}
-};
-
 
 /*
   The guardian thread is responsible for monitoring and restarting of guarded
   instances.
 */
 
-class Guardian_thread: public Guardian_thread_args
+class Guardian_thread
 {
 public:
-  /* states of an instance */
-  enum enum_instance_state { NOT_STARTED= 1, STARTING, STARTED, JUST_CRASHED,
-                             CRASHED, CRASHED_AND_ABANDONED, STOPPING };
+  Guardian_thread(Instance_map &instances_arg);
+  ~Guardian_thread();
 
-  /*
-    The Guardian list node structure. Guardian utilizes it to store
-    guarded instances plus some additional info.
-  */
+  bool init();
 
-  struct GUARD_NODE
-  {
-    Instance *instance;
-    /* state of an instance (i.e. STARTED, CRASHED, etc.) */
-    enum_instance_state 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;
-  };
-
-  /* Return client state name. */
-  static const char *get_instance_state_name(enum_instance_state state);
-
-  Guardian_thread(Thread_registry &thread_registry_arg,
-                  Instance_map *instance_map_arg,
-                  uint monitoring_interval_arg);
-  ~Guardian_thread();
-  /* Main funtion of the thread */
-  void run();
-  /* Initialize or refresh the list of guarded instances */
-  int init();
-  /* Request guardian shutdown. Stop instances if needed */
-  void request_shutdown();
-  /* Start instance protection */
-  int guard(Instance *instance, bool nolock= FALSE);
-  /* Stop instance protection */
-  int stop_guard(Instance *instance);
-  /* Returns TRUE if guardian thread is stopped */
-  int is_stopped();
   void lock();
   void unlock();
 
-  /*
-    Return an internal list node for the given instance if the instance is
-    managed by Guardian. Otherwise, return NULL.
+  bool start_detached();
 
-    MT-NOTE: must be called under acquired lock.
-  */
-  LIST *find_instance_node(Instance *instance);
+  /* Request guardian shutdown. Stop instances if needed */
+  void request_shutdown();
 
-  /* The operation is used to check if the instance is active or not. */
-  bool is_active(Instance *instance);
+  /* Returns TRUE if guardian thread is stopped */
+  bool is_stopped();
 
-  /*
-    Return state of the given instance list node. The pointer must specify
-    a valid list node.
-  */
-  inline enum_instance_state get_instance_state(LIST *instance_node);
+  void ping();
 
-public:
-  pthread_cond_t COND_guardian;
+private:
+  static void *guardian_thread_func(void *guardian);
 
 private:
+  void process_instance(Instance *instance);
+
+  /* Main funtion of the thread */
+  void run();
+
   /* Prepares Guardian shutdown. Stops instances is needed */
-  int stop_instances();
-  /* check instance state and act accordingly */
-  void process_instance(Instance *instance, GUARD_NODE *current_node,
-                        LIST **guarded_instances, LIST *elem);
+  void stop_instances();
 
-  int stopped;
+private:
+  Instance_map &instances;
 
 private:
+  /*
+    LOCK_guardian protectes the members in this section:
+      - shutdown_requested;
+      - stopped;
+
+    Also, it is used for COND_guardian.
+  */
   pthread_mutex_t LOCK_guardian;
-  Thread_info thread_info;
-  LIST *guarded_instances;
-  MEM_ROOT alloc;
-  /* this variable is set to TRUE when we want to stop Guardian thread */
+
+  /*
+    Guardian's main loop waits on this condition. So, it should be signalled
+    each time, when instance state has been changed and we want Guardian to
+    wake up.
+
+    TODO: Change this to having data-scoped conditions, i.e. conditions, which
+    indicate that some data has been changed.
+  */
+  pthread_cond_t COND_guardian;
+
+  /*
+    This variable is set to TRUE, when Guardian thread is going to stop.
+  */
   bool shutdown_requested;
-};
 
+  /*
+    This variable is set to TRUE, when Guardian thread is stopped.
+  */
+  bool stopped;
 
-inline Guardian_thread::enum_instance_state
-Guardian_thread::get_instance_state(LIST *instance_node)
-{
-  return ((GUARD_NODE *) instance_node->data)->state;
-}
+private:
+  Guardian_thread(const Guardian_thread &);
+  Guardian_thread &operator =(const Guardian_thread &);
+};
 
 #endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_GUARDIAN_H */

--- 1.41/server-tools/instance-manager/instance.cc	2006-10-27 15:30:46 +04:00
+++ 1.42/server-tools/instance-manager/instance.cc	2006-10-27 15:30:46 +04:00
@@ -29,24 +29,14 @@
 #endif
 
 #include "guardian.h"
-#include "instance_map.h"
+#include "manager.h"
 #include "log.h"
 #include "mysql_manager_error.h"
 #include "portability.h"
 #include "priv.h"
 #include "thread_registry.h"
 
-
-const LEX_STRING
-Instance::DFLT_INSTANCE_NAME= { C_STRING_WITH_LEN("mysqld") };
-
-static const char * const INSTANCE_NAME_PREFIX= Instance::DFLT_INSTANCE_NAME.str;
-static const int INSTANCE_NAME_PREFIX_LEN= Instance::DFLT_INSTANCE_NAME.length;
-
-
-static void start_and_monitor_instance(Instance_options *old_instance_options,
-                                       Instance_map *instance_map,
-                                       Thread_registry *thread_registry);
+/* {{{ Platform-specific functions. */
 
 #ifndef __WIN__
 typedef pid_t My_process_info;
@@ -55,22 +45,6 @@ typedef PROCESS_INFORMATION My_process_i
 #endif
 
 /*
-  Proxy thread is a simple way to avoid all pitfalls of the threads
-  implementation in the OS (e.g. LinuxThreads). With such a thread we
-  don't have to process SIGCHLD, which is a tricky business if we want
-  to do it in a portable way.
-*/
-
-pthread_handler_t proxy(void *arg)
-{
-  Instance *instance= (Instance *) arg;
-  start_and_monitor_instance(&instance->options,
-                             instance->get_map(),
-                             &instance->thread_registry);
-  return 0;
-}
-
-/*
   Wait for an instance
 
   SYNOPSYS
@@ -131,7 +105,6 @@ static int wait_process(My_process_info 
 }
 #endif
 
-
 /*
   Launch an instance
 
@@ -143,12 +116,12 @@ static int wait_process(My_process_info 
                          (platform-dependent).
 
   RETURN
-   0  -  Success
-   1  -  Cannot create an instance
+   FALSE - Success
+   TRUE  - Cannot create an instance
 */
 
 #ifndef __WIN__
-static int start_process(Instance_options *instance_options,
+static bool start_process(Instance_options *instance_options,
                          My_process_info *pi)
 {
 #ifndef __QNX__
@@ -169,14 +142,15 @@ static int start_process(Instance_option
     /* exec never returns */
     exit(1);
   case -1:
-    log_info("cannot create a new process to start instance '%s'.",
+    log_info("Instance '%s': can not start mysqld: fork() failed.",
              (const char *) instance_options->instance_name.str);
-    return 1;
+    return TRUE;
   }
-  return 0;
+
+  return FALSE;
 }
 #else
-static int start_process(Instance_options *instance_options,
+static bool start_process(Instance_options *instance_options,
                          My_process_info *pi)
 {
   STARTUPINFO si;
@@ -192,7 +166,7 @@ static int start_process(Instance_option
 
   char *cmdline= new char[cmdlen];
   if (cmdline == NULL)
-    return 1;
+    return TRUE;
 
   cmdline[0]= 0;
   for (int i= 0; instance_options->argv[i] != 0; i++)
@@ -216,21 +190,89 @@ static int start_process(Instance_option
                   pi);           /* Pointer to PROCESS_INFORMATION structure */
   delete cmdline;
 
-  return (!result);
+  return !result;
 }
 #endif
 
-/*
+#ifdef __WIN__
+
+BOOL SafeTerminateProcess(HANDLE hProcess, UINT uExitCode)
+{
+  DWORD dwTID, dwCode, dwErr= 0;
+  HANDLE hProcessDup= INVALID_HANDLE_VALUE;
+  HANDLE hRT= NULL;
+  HINSTANCE hKernel= GetModuleHandle("Kernel32");
+  BOOL bSuccess= FALSE;
+
+  BOOL bDup= DuplicateHandle(GetCurrentProcess(),
+                             hProcess, GetCurrentProcess(), &hProcessDup,
+                             PROCESS_ALL_ACCESS, FALSE, 0);
+
+  // Detect the special case where the process is
+  // already dead...
+  if (GetExitCodeProcess((bDup) ? hProcessDup : hProcess, &dwCode) &&
+      (dwCode == STILL_ACTIVE))
+  {
+    FARPROC pfnExitProc;
+
+    pfnExitProc= GetProcAddress(hKernel, "ExitProcess");
+
+    hRT= CreateRemoteThread((bDup) ? hProcessDup : hProcess, NULL, 0,
+                            (LPTHREAD_START_ROUTINE)pfnExitProc,
+                            (PVOID)uExitCode, 0, &dwTID);
+
+    if (hRT == NULL)
+      dwErr= GetLastError();
+  }
+  else
+    dwErr= ERROR_PROCESS_ABORTED;
+
+  if (hRT)
+  {
+    // Must wait process to terminate to
+    // guarantee that it has exited...
+    WaitForSingleObject((bDup) ? hProcessDup : hProcess, INFINITE);
+
+    CloseHandle(hRT);
+    bSuccess= TRUE;
+  }
+
+  if (bDup)
+    CloseHandle(hProcessDup);
+
+  if (!bSuccess)
+    SetLastError(dwErr);
+
+  return bSuccess;
+}
+
+int kill(pid_t pid, int signum)
+{
+  HANDLE processhandle= ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
+  if (signum == SIGTERM)
+    ::SafeTerminateProcess(processhandle, 0);
+  else
+    ::TerminateProcess(processhandle, -1);
+  return 0;
+}
+#endif
+
+/* }}} */
+
+/* {{{ Static constants.  */
+
+const LEX_STRING
+Instance::DFLT_INSTANCE_NAME= { C_STRING_WITH_LEN("mysqld") };
+
+/* }}} */
+
+/* {{{ Static operations. */
+
+/*************************************************************************
   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.
+    monitor_thread_func()
 
   DESCRIPTION
     Fork a child, then exec and monitor it. When the child is dead,
@@ -238,23 +280,25 @@ static int start_process(Instance_option
     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,
-                                       Thread_registry *thread_registry)
-{
-  Instance_name instance_name(&old_instance_options->instance_name);
-  Instance *current_instance;
+    NOTE: a separate thread for starting/monitoring instance is a simple way
+    to avoid all pitfalls of the threads implementation in the OS (e.g.
+    LinuxThreads). For one, with such a thread we don't have to process
+    SIGCHLD, which is a tricky business if we want to do it in a portable way.
+*************************************************************************/
+
+void *Instance::monitor_thread_func(void *instance_ptr)
+{
+  Instance *instance= (Instance *) instance_ptr;
+  Guardian_thread &guardian= Manager::get_instance().get_guardian();
+  Thread_registry &thread_registry=
+    Manager::get_instance().get_thread_registry();
   My_process_info process_info;
   Thread_info thread_info(pthread_self(), FALSE);
 
-  log_info("Monitoring thread (instance: '%s'): started.",
-           (const char *) instance_name.get_c_str());
+  log_info("Instance '%s': Monitor: started.",
+           (const char *) instance->get_name()->str);
 
-  if (!old_instance_options->nonguarded)
+  if (instance->is_guarded())
   {
     /*
       Register thread in Thread_registry to wait for it to stop on shutdown
@@ -262,226 +306,255 @@ static void start_and_monitor_instance(I
       finish, because nonguarded instances are not stopped on shutdown.
     */
 
-    thread_registry->register_thread(&thread_info);
+    thread_registry.register_thread(&thread_info);
     my_thread_init();
   }
 
   /*
-    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")
   */
 
-  log_info("starting instance %s...",
-           (const char *) instance_name.get_c_str());
+  log_info("Instance '%s': Monitor: starting mysqld...",
+           (const char *) instance->get_name()->str);
 
-  if (start_process(old_instance_options, &process_info))
+  if (start_process(&instance->options, &process_info))
   {
-    instance_map->unlock();
-    return;                                     /* error is logged */
+    instance->lock();
+    instance->monitoring_thread_active= FALSE;
+    instance->unlock();
+    return NULL;
   }
 
-  /* allow users to delete instances */
-  instance_map->unlock();
+  log_info("Instance '%s': Monitor: waiting for mysqld to stop...",
+           (const char *) instance->get_name()->str);
 
-  /* don't check for return value */
-  wait_process(&process_info);
+  wait_process(&process_info); /* Don't check for return value. */
 
-  instance_map->lock();
+  log_info("Instance '%s': Monitor: mysqld stopped.",
+           (const char *) instance->get_name()->str);
 
-  current_instance= instance_map->find(instance_name.get_str());
+  /* Updated instance status. */
 
-  if (current_instance)
-    current_instance->set_crash_flag_n_wake_all();
+  instance->lock();
 
-  instance_map->unlock();
-
-  if (!old_instance_options->nonguarded)
+  if (instance->is_guarded())
   {
-    thread_registry->unregister_thread(&thread_info);
+    thread_registry.unregister_thread(&thread_info);
     my_thread_end();
   }
 
-  log_info("Monitoring thread (instance: '%s'): finished.",
-           (const char *) instance_name.get_c_str());
+  instance->crashed= TRUE;
+  instance->monitoring_thread_active= FALSE;
+
+  log_info("Instance '%s': Monitor: finished.",
+           (const char *) instance->get_name()->str);
+
+  instance->unlock();
+
+  /* Wake up guardian. */
+
+  guardian.lock();
+  guardian.ping();
+  guardian.unlock();
+
+  return 0;
 }
 
+/*************************************************************************
+  Instance::is_name_valid()
+*************************************************************************/
 
 bool Instance::is_name_valid(const LEX_STRING *name)
 {
-  const char *name_suffix= name->str + INSTANCE_NAME_PREFIX_LEN;
+  const char *name_suffix= name->str + DFLT_INSTANCE_NAME.length;
 
-  if (strncmp(name->str, INSTANCE_NAME_PREFIX, INSTANCE_NAME_PREFIX_LEN) != 0)
+  if (strncmp(name->str, Instance::DFLT_INSTANCE_NAME.str,
+              Instance::DFLT_INSTANCE_NAME.length) != 0)
     return FALSE;
 
   return *name_suffix == 0 || my_isdigit(default_charset_info, *name_suffix);
 }
 
+/*************************************************************************
+  Instance::is_mysqld_compatible_name()
+*************************************************************************/
 
 bool Instance::is_mysqld_compatible_name(const LEX_STRING *name)
 {
-  return strcmp(name->str, INSTANCE_NAME_PREFIX) == 0;
+  return strcmp(name->str, DFLT_INSTANCE_NAME.str) == 0;
 }
 
+/*************************************************************************
+  Instance::is_mysqld_compatible_name()
+*************************************************************************/
 
-Instance_map *Instance::get_map()
+const char * Instance::get_instance_state_name(enum_instance_state state)
 {
-  return instance_map;
-}
+  switch (state) {
+  case STOPPED:
+    return "offline";
 
+  case NOT_STARTED:
+    return "not started";
 
-void Instance::remove_pid()
-{
-  int pid;
-  if ((pid= options.get_pid()) != 0)          /* check the pidfile */
-    if (options.unlink_pidfile())             /* remove stalled pidfile */
-      log_error("cannot remove pidfile for instance '%s', this might be "
-                "since IM lacks permmissions or hasn't found the pidifle",
-                (const char *) options.instance_name.str);
+  case STARTING:
+    return "starting";
+
+  case STARTED:
+    return "online";
+
+  case JUST_CRASHED:
+    return "failed";
+
+  case CRASHED:
+    return "crashed";
+
+  case CRASHED_AND_ABANDONED:
+    return "abandoned";
+
+  case STOPPING:
+    return "stopping";
+  }
+
+  return NULL; /* just to ignore compiler warning. */
 }
 
 
-/*
-  The method starts an instance.
+/* }}} */
 
-  SYNOPSYS
-    start()
+/* {{{ Constructor & destructor */
 
-  RETURN
-    0                             ok
-    ER_CANNOT_START_INSTANCE      Cannot start instance
-    ER_INSTANCE_ALREADY_STARTED   The instance on the specified port/socket
-                                  is already started
-*/
+Instance::Instance():
+  monitoring_thread_active(FALSE),
+  crashed(FALSE),
+  configured(FALSE),
+  /* mysqld_compatible is initialized in init() */
+  state(NOT_STARTED),
+  restart_counter(0),
+  crash_moment(0),
+  last_checked(0)
+{
+  pthread_mutex_init(&LOCK_instance, 0);
+}
 
-int Instance::start()
+Instance::~Instance()
 {
-  /* clear crash flag */
-  pthread_mutex_lock(&LOCK_instance);
-  crashed= FALSE;
-  pthread_mutex_unlock(&LOCK_instance);
+  log_info("Instance '%s': destroying...", (const char *) get_name()->str);
+
+  pthread_mutex_destroy(&LOCK_instance);
+}
 
+/* }}} */
 
-  if (configured && !is_running())
-  {
-    remove_pid();
 
-    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;
-    }
+/**************************************************************************
+  Initialize instance options.
 
-    return 0;
-  }
+  SYNOPSYS
+    init()
+    name_arg      name of the instance
 
-  /* The instance is started already or misconfigured. */
-  return configured ? ER_INSTANCE_ALREADY_STARTED : ER_INSTANCE_MISCONFIGURED;
+  RETURN:
+    FALSE - ok
+    TRUE  - error
+**************************************************************************/
+
+bool Instance::init(const LEX_STRING *name_arg)
+{
+  mysqld_compatible= is_mysqld_compatible_name(name_arg);
+
+  return options.init(name_arg);
 }
 
-/*
-  The method sets the crash flag and wakes all waiters on
-  COND_instance_stopped and COND_guardian
 
-  SYNOPSYS
-    set_crash_flag_n_wake_all()
+/**************************************************************************
+  Complete instance options initialization.
 
-  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.
+  SYNOPSYS
+    complete_initialization()
 
   RETURN
-    Function returns no value
-*/
+    FALSE - ok
+    TRUE  - error
+**************************************************************************/
 
-void Instance::set_crash_flag_n_wake_all()
+bool Instance::complete_initialization()
 {
-  /* set instance state to crashed */
-  pthread_mutex_lock(&LOCK_instance);
-  crashed= TRUE;
-  pthread_mutex_unlock(&LOCK_instance);
-
+  configured= !options.complete_initialization();
+  return FALSE;
   /*
-    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.
+    TODO: return actual status (from
+    Instance_options::complete_initialization()) here.
   */
-  pthread_cond_signal(&COND_instance_stopped);
-  /* wake guardian */
-  pthread_cond_signal(&instance_map->guardian->COND_guardian);
 }
 
 
+/**************************************************************************
+  Determine if there is some activity with the instance.
 
-Instance::Instance(Thread_registry &thread_registry_arg):
-  crashed(FALSE), configured(FALSE), thread_registry(thread_registry_arg)
-{
-  pthread_mutex_init(&LOCK_instance, 0);
-  pthread_cond_init(&COND_instance_stopped, 0);
-}
+  SYNOPSYS
+    is_active()
 
+  DESCRIPTION
+    An instance is active if one of the following conditions is true:
+      - Instance-monitoring thread is running;
+      - Instance is guarded and its state is other than STOPPED;
+      - Corresponding mysqld-server accepts connections.
 
-Instance::~Instance()
-{
-  pthread_cond_destroy(&COND_instance_stopped);
-  pthread_mutex_destroy(&LOCK_instance);
-}
+    MT-NOTE: this operation must be called under acquired LOCK_instance.
 
+  RETURN
+    TRUE  - instance is active
+    FALSE - otherwise.
+**************************************************************************/
 
-bool Instance::is_crashed()
+bool Instance::is_active()
 {
-  bool val;
-  pthread_mutex_lock(&LOCK_instance);
-  val= crashed;
-  pthread_mutex_unlock(&LOCK_instance);
-  return val;
+  if (monitoring_thread_active)
+    return TRUE;
+
+  if (is_guarded() && get_state() != STOPPED)
+    return TRUE;
+
+  return is_mysqld_running();
 }
 
 
-bool Instance::is_running()
+/**************************************************************************
+  Determine if mysqld is accepting connections.
+
+  SYNOPSYS
+    is_mysqld_running()
+
+  DESCRIPTION
+    Try to connect to mysqld with fake login/password to check whether it is
+    accepting connections or not.
+
+    MT-NOTE: this operation must be called under acquired LOCK_instance.
+
+  RETURN
+    TRUE  - mysqld is alive and accept connections
+    FALSE - otherwise.
+**************************************************************************/
+
+bool Instance::is_mysqld_running()
 {
   MYSQL mysql;
-  uint port= 0;
+  uint port= options.get_mysqld_port(); /* 0 if not specified. */
   const char *socket= NULL;
   static const char *password= "check_connection";
   static const char *username= "MySQL_Instance_Manager";
   static const char *access_denied_message= "Access denied for user";
   bool return_val;
 
-  if (options.mysqld_port)
-  {
-    /*
-      NOTE: it is important to check mysqld_port here, but use
-      mysqld_port_val. The idea is that if the option is unset, mysqld_port
-      will be NULL, but mysqld_port_val will not be reset.
-    */
-    port= options.mysqld_port_val;
-  }
-
   if (options.mysqld_socket)
     socket= options.mysqld_socket;
 
   /* no port was specified => instance falled back to default value */
-  if (!options.mysqld_port && !options.mysqld_socket)
+  if (!port && !options.mysqld_socket)
     port= SERVER_DEFAULT_PORT;
 
-  pthread_mutex_lock(&LOCK_instance);
-
   mysql_init(&mysql);
   /* try to connect to a server with a fake username/password pair */
   if (mysql_real_connect(&mysql, LOCAL_HOST, username,
@@ -493,10 +566,8 @@ bool Instance::is_running()
       We have successfully connected to the server using fake
       username/password. Write a warning to the logfile.
     */
-    log_info("The Instance Manager was able to log into you server "
-             "with faked compiled-in password while checking server status. "
-             "Looks like something is wrong.");
-    pthread_mutex_unlock(&LOCK_instance);
+    log_error("Instance '%s': was able to log into mysqld.",
+              (const char *) get_name()->str);
     return_val= TRUE;                           /* server is alive */
   }
   else
@@ -504,184 +575,299 @@ bool Instance::is_running()
                               sizeof(access_denied_message) - 1));
 
   mysql_close(&mysql);
-  pthread_mutex_unlock(&LOCK_instance);
 
   return return_val;
 }
 
 
-/*
-  Stop an instance.
+/**************************************************************************
+  The method handles START INSTANCE request.
 
   SYNOPSYS
-    stop()
+    start_cmd()
 
-  RETURN:
-    0                            ok
-    ER_INSTANCE_IS_NOT_STARTED   Looks like the instance it is not started
-    ER_STOP_INSTANCE             mysql_shutdown reported an error
-*/
+  RETURN
+    FALSE - ok
+    TRUE  - could not start instance
+**************************************************************************/
 
-int Instance::stop()
+bool Instance::start_cmd()
 {
-  struct timespec timeout;
-  uint waitchild= (uint)  DEFAULT_SHUTDOWN_DELAY;
+  if (start_mysqld())
+    return TRUE;
 
-  if (is_running())
-  {
-    if (options.shutdown_delay)
-    {
-      /*
-        NOTE: it is important to check shutdown_delay here, but use
-        shutdown_delay_val. The idea is that if the option is unset,
-        shutdown_delay will be NULL, but shutdown_delay_val will not be reset.
-      */
-      waitchild= options.shutdown_delay_val;
-    }
+  reset_stat();
+  set_state(NOT_STARTED);
+
+  return FALSE;
+}
+
+
+/**************************************************************************
+  The method handles STOP INSTANCE request.
+
+  SYNOPSYS
+    stop_cmd()
+
+  RETURN
+    FALSE - ok
+    TRUE  - could not stop instance
+**************************************************************************/
+
+bool Instance::stop_cmd()
+{
+  set_state(STOPPED);
+
+  return stop_mysqld();
+}
 
-    kill_instance(SIGTERM);
-    /* sleep on condition to wait for SIGCHLD */
 
-    timeout.tv_sec= time(NULL) + waitchild;
-    timeout.tv_nsec= 0;
-    if (pthread_mutex_lock(&LOCK_instance))
-      return ER_STOP_INSTANCE;
+/**************************************************************************
+  The method starts mysqld.
 
-    while (options.get_pid() != 0)              /* while server isn't stopped */
-    {
-      int status;
+  SYNOPSYS
+    start_mysqld()
 
-      status= pthread_cond_timedwait(&COND_instance_stopped,
-                                     &LOCK_instance,
-                                     &timeout);
-      if (status == ETIMEDOUT || status == ETIME)
-        break;
-    }
+  RETURN
+    FALSE - ok
+    TRUE  - could not start instance
+**************************************************************************/
+
+bool Instance::start_mysqld()
+{
+  pthread_t thd_id;
+  pthread_attr_t thd_attr;
+  int rc;
 
-    pthread_mutex_unlock(&LOCK_instance);
+  crashed= FALSE;
+  monitoring_thread_active= TRUE;
 
-    kill_instance(SIGKILL);
+  remove_pid();
 
-    return 0;
+  pthread_attr_init(&thd_attr);
+  pthread_attr_setdetachstate(&thd_attr, PTHREAD_CREATE_DETACHED);
+  rc= pthread_create(&thd_id, &thd_attr, monitor_thread_func, this);
+  pthread_attr_destroy(&thd_attr);
+
+  if (rc)
+  {
+    monitoring_thread_active= FALSE;
+
+    log_error("Instance '%s': can not start monitor thread: "
+              "pthread_create() failed.",
+              (const char *) get_name()->str);
+
+    return TRUE;
   }
 
-  return ER_INSTANCE_IS_NOT_STARTED;
+  return FALSE;
 }
 
-#ifdef __WIN__
 
-BOOL SafeTerminateProcess(HANDLE hProcess, UINT uExitCode)
+/**************************************************************************
+  Stop mysqld.
+
+  SYNOPSYS
+    stop_mysqld()
+
+  RETURN
+    FALSE - ok
+    TRUE  - could not stop the instance
+**************************************************************************/
+
+bool Instance::stop_mysqld()
 {
-  DWORD dwTID, dwCode, dwErr= 0;
-  HANDLE hProcessDup= INVALID_HANDLE_VALUE;
-  HANDLE hRT= NULL;
-  HINSTANCE hKernel= GetModuleHandle("Kernel32");
-  BOOL bSuccess= FALSE;
+  log_info("Instance '%s': stopping mysqld...",
+           (const char *) get_name()->str);
 
-  BOOL bDup= DuplicateHandle(GetCurrentProcess(),
-                             hProcess, GetCurrentProcess(), &hProcessDup,
-                             PROCESS_ALL_ACCESS, FALSE, 0);
+  kill_mysqld(SIGTERM);
 
-  // Detect the special case where the process is
-  // already dead...
-  if (GetExitCodeProcess((bDup) ? hProcessDup : hProcess, &dwCode) &&
-      (dwCode == STILL_ACTIVE))
+  if (!wait_for_stop())
   {
-    FARPROC pfnExitProc;
+    log_info("Instance '%s': mysqld stopped gracefully.",
+             (const char *) get_name()->str);
+    return FALSE;
+  }
 
-    pfnExitProc= GetProcAddress(hKernel, "ExitProcess");
+  log_info("Instance '%s': mysqld failed to stop gracefully within %d seconds.",
+           (const char *) get_name()->str,
+           (int) options.get_shutdown_delay());
 
-    hRT= CreateRemoteThread((bDup) ? hProcessDup : hProcess, NULL, 0,
-                            (LPTHREAD_START_ROUTINE)pfnExitProc,
-                            (PVOID)uExitCode, 0, &dwTID);
+  log_info("Instance'%s': killing mysqld...",
+           (const char *) get_name()->str);
 
-    if (hRT == NULL)
-      dwErr= GetLastError();
+  kill_mysqld(SIGKILL);
+
+  if (!wait_for_stop())
+  {
+    log_info("Instance '%s': mysqld has been killed.",
+             (const char *) get_name()->str);
+    return FALSE;
   }
-  else
-    dwErr= ERROR_PROCESS_ABORTED;
 
-  if (hRT)
+  log_info("Instance '%s': can not kill mysqld within %d seconds.",
+           (const char *) get_name()->str,
+           (int) options.get_shutdown_delay());
+
+  return TRUE;
+}
+
+
+/**************************************************************************
+  Send signal to mysqld.
+
+  SYNOPSYS
+    kill_mysqld()
+**************************************************************************/
+
+void Instance::kill_mysqld(int signum)
+{
+  pid_t mysqld_pid= options.load_pid();
+
+  if (mysqld_pid == 0)
   {
-    // Must wait process to terminate to
-    // guarantee that it has exited...
-    WaitForSingleObject((bDup) ? hProcessDup : hProcess, INFINITE);
+    log_info("Instance '%s': no pid file to send a signal (%d).",
+             (const char *) get_name()->str,
+             (int) signum);
+    return;
+  }
 
-    CloseHandle(hRT);
-    bSuccess= TRUE;
+  log_info("Instance '%s': sending %d to %d...",
+           (const char *) get_name()->str,
+           (int) signum,
+           (int) mysqld_pid);
+
+  if (kill(mysqld_pid, signum))
+  {
+    log_info("Instance '%s': kill() failed.",
+             (const char *) get_name()->str);
+    return;
   }
 
-  if (bDup)
-    CloseHandle(hProcessDup);
+  /* Kill suceeded */
+  if (signum == SIGKILL)      /* really killed instance with SIGKILL */
+  {
+    log_error("The instance '%s' is being stopped forcibly. Normally"
+              "it should not happen. Probably the instance has been"
+              "hanging. You should also check your IM setup",
+              (const char *) options.instance_name.str);
+    /* After sucessful hard kill the pidfile need to be removed */
+    options.unlink_pidfile();
+  }
+}
 
-  if (!bSuccess)
-    SetLastError(dwErr);
+/**************************************************************************
+  Return crashed flag.
 
-  return bSuccess;
+  SYNOPSYS
+    is_crashed()
+
+  RETURN
+    TRUE  - mysqld crashed
+    FALSE - mysqld hasn't crashed yet
+**************************************************************************/
+
+bool Instance::is_crashed()
+{
+  return crashed;
 }
 
-int kill(pid_t pid, int signum)
+
+/**************************************************************************
+  Lock instance.
+**************************************************************************/
+
+void Instance::lock()
 {
-  HANDLE processhandle= ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
-  if (signum == SIGTERM)
-    ::SafeTerminateProcess(processhandle, 0);
-  else
-    ::TerminateProcess(processhandle, -1);
-  return 0;
+  pthread_mutex_lock(&LOCK_instance);
 }
-#endif
 
-void Instance::kill_instance(int signum)
+
+/**************************************************************************
+  Unlock instance.
+**************************************************************************/
+
+void Instance::unlock()
+{
+  pthread_mutex_unlock(&LOCK_instance);
+}
+
+
+/**************************************************************************
+  Return instance state name.
+**************************************************************************/
+
+const char *Instance::get_state_name()
 {
-  pid_t pid;
-  /* if there are no pid, everything seems to be fine */
-  if ((pid= options.get_pid()) != 0)            /* get pid from pidfile */
-  {
-    if (kill(pid, signum) == 0)
-    {
-      /* Kill suceeded */
-      if (signum == SIGKILL)      /* really killed instance with SIGKILL */
-      {
-        log_error("The instance '%s' is being stopped forcibly. Normally"
-                  "it should not happen. Probably the instance has been"
-                  "hanging. You should also check your IM setup",
-                  (const char *) options.instance_name.str);
-        /* After sucessful hard kill the pidfile need to be removed */
-        options.unlink_pidfile();
-      }
-    }
+  if (!is_configured())
+    return "misconfigured";
+
+  if (is_guarded())
+  {
+    /* The instance is managed by Guardian: we can report precise state. */
+
+    return get_instance_state_name(get_state());
   }
-  return;
+
+  /* The instance is not managed by Guardian: we can report status only.  */
+
+  return is_active() ? "online" : "offline";
 }
 
-/*
-  Initialize instance parameters.
 
-  SYNOPSYS
-    Instance::init()
-    name_arg      name of the instance
+/**************************************************************************
+  Reset statistics.
+**************************************************************************/
+
+void Instance::reset_stat()
+{
+  restart_counter= 0;
+  crash_moment= 0;
+  last_checked= 0;
+}
 
-  RETURN:
-    0             ok
-    !0            error
-*/
 
-int Instance::init(const LEX_STRING *name_arg)
+/**************************************************************************
+  Remove pid file.
+**************************************************************************/
+
+void Instance::remove_pid()
 {
-  mysqld_compatible= is_mysqld_compatible_name(name_arg);
+  int mysqld_pid= options.load_pid();
 
-  return options.init(name_arg);
+  if (mysqld_pid == 0)
+    return;
+
+  if (options.unlink_pidfile())
+  {
+    log_error("Instance '%s': can not unlink pid file.",
+              (const char *) options.instance_name.str);
+  }
 }
 
 
-int Instance::complete_initialization(Instance_map *instance_map_arg,
-                                      const char *mysqld_path)
+/**************************************************************************
+  Wait for mysqld to stop within shutdown interval.
+**************************************************************************/
+
+bool Instance::wait_for_stop()
 {
-  instance_map= instance_map_arg;
-  configured= !options.complete_initialization(mysqld_path);
-  return 0;
-  /*
-    TODO: return actual status (from
-    Instance_options::complete_initialization()) here.
-  */
+  int start_time= time(NULL);
+  int finish_time= start_time + options.get_shutdown_delay();
+
+  log_info("Instance '%s': waiting for mysqld to stop "
+           "(timeout: %d seconds)...",
+           (const char *) get_name()->str,
+           (int) options.get_shutdown_delay());
+
+  while (true)
+  {
+    if (options.load_pid() == 0 && !is_mysqld_running())
+      return FALSE;
+
+    if (time(NULL) >= finish_time)
+      return TRUE;
+
+    my_sleep(300000);
+  }
 }

--- 1.17/server-tools/instance-manager/instance.h	2006-10-27 15:30:46 +04:00
+++ 1.18/server-tools/instance-manager/instance.h	2006-10-27 15:30:46 +04:00
@@ -17,6 +17,7 @@
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 
 #include <my_global.h>
+#include <my_pthread.h>
 #include <m_string.h>
 
 #include "instance_options.h"
@@ -26,9 +27,6 @@
 #pragma interface
 #endif
 
-class Instance_map;
-class Thread_registry;
-
 
 /*
   Instance_name -- the class represents instance name -- a string of length
@@ -68,6 +66,20 @@ private:
 class Instance
 {
 public:
+  /* states of an instance */
+  enum enum_instance_state
+  {
+    STOPPED,
+    NOT_STARTED,
+    STARTING,
+    STARTED,
+    JUST_CRASHED,
+    CRASHED,
+    CRASHED_AND_ABANDONED,
+    STOPPING
+  };
+
+public:
   /*
     The following two constants defines name of the default mysqld-instance
     ("mysqld").
@@ -87,22 +99,46 @@ public:
   */
   static bool is_mysqld_compatible_name(const LEX_STRING *name);
 
-public:
-  Instance(Thread_registry &thread_registry_arg);
+  /*
+    Return client state name.
+  */
+  static const char *get_instance_state_name(enum_instance_state state);
 
+public:
+  Instance();
   ~Instance();
-  int init(const LEX_STRING *name_arg);
-  int complete_initialization(Instance_map *instance_map_arg,
-                              const char *mysqld_path);
-
-  bool is_running();
-  int start();
-  int stop();
-  /* send a signal to the instance */
-  void kill_instance(int signo);
+
+  bool init(const LEX_STRING *name_arg);
+  bool complete_initialization();
+
+  /*
+    An instance is active if one of the following conditions is true:
+      - Instance-monitoring thread is running;
+      - Instance is guarded and its state is other than STOPPED;
+      - Corresponding mysqld-server accepts connections.
+
+    MT-NOTE: this operation must be called under acquired LOCK_instance.
+  */
+  bool is_active();
+
+  /*
+    Return TRUE if mysqld is accepting connections.
+
+    MT-NOTE: this operation must be called under acquired LOCK_instance.
+  */
+  bool is_mysqld_running();
+
+  bool start_cmd();
+  bool stop_cmd();
+
+  bool start_mysqld();
+  bool stop_mysqld();
+  void kill_mysqld(int signo);
+
   bool is_crashed();
-  void set_crash_flag_n_wake_all();
-  Instance_map *get_map();
+
+  void lock();
+  void unlock();
 
   /*
     The operation is intended to check if the instance is mysqld-compatible
@@ -116,14 +152,28 @@ public:
   */
   inline bool is_configured() const;
 
+  inline bool is_guarded() const;
+
   inline const LEX_STRING *get_name() const;
 
+  /*
+    Return state of guarded instance.
+
+    NOTE: Now should be used only for guarded instances.
+  */
+  inline enum_instance_state get_state() const;
+  inline void set_state(enum_instance_state new_state);
+
+  const char *get_state_name();
+
+  void reset_stat();
+
 public:
-  enum { DEFAULT_SHUTDOWN_DELAY= 35 };
   Instance_options options;
-  Thread_registry &thread_registry;
 
 private:
+  bool monitoring_thread_active;
+
   /* This attributes is a flag, specifies if the instance has been crashed. */
   bool crashed;
 
@@ -150,14 +200,29 @@ private:
     and we issue the start command once more.
   */
   pthread_mutex_t LOCK_instance;
-  /*
-    This condition variable is used to wake threads waiting for instance to
-    stop in Instance::stop()
-  */
-  pthread_cond_t COND_instance_stopped;
-  Instance_map *instance_map;
 
-  void  remove_pid();
+private:
+  /* Guarded-instance attributes. */
+
+  /* state of an instance (i.e. STARTED, CRASHED, etc.) */
+  enum_instance_state state;
+
+public:
+  /* 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;
+
+private:
+  void remove_pid();
+
+  bool wait_for_stop();
+
+  static void *monitor_thread_func(void *instance_ptr);
 };
 
 
@@ -173,9 +238,27 @@ inline bool Instance::is_configured() co
 }
 
 
+inline bool Instance::is_guarded() const
+{
+  return !options.nonguarded;
+}
+
+
 inline const LEX_STRING *Instance::get_name() const
 {
   return &options.instance_name;
+}
+
+
+inline Instance::enum_instance_state Instance::get_state() const
+{
+  return state;
+}
+
+
+inline void Instance::set_state(enum_instance_state new_state)
+{
+  state= new_state;
 }
 
 #endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_INSTANCE_H */

--- 1.31/server-tools/instance-manager/instance_map.cc	2006-10-27 15:30:46 +04:00
+++ 1.32/server-tools/instance-manager/instance_map.cc	2006-10-27 15:30:46 +04:00
@@ -25,10 +25,8 @@
 #include <mysql_com.h>
 
 #include "buffer.h"
-#include "guardian.h"
 #include "instance.h"
 #include "log.h"
-#include "manager.h"
 #include "mysqld_error.h"
 #include "mysql_manager_error.h"
 #include "options.h"
@@ -169,7 +167,7 @@ int Instance_map::process_one_option(con
   if (!(instance= (Instance *) hash_search(&hash, (byte *) group->str,
                                            group->length)))
   {
-    if (!(instance= new Instance(thread_registry)))
+    if (!(instance= new Instance()))
       return 1;
 
     if (instance->init(group) || add_instance(instance))
@@ -213,113 +211,88 @@ int Instance_map::process_one_option(con
 }
 
 
-Instance_map::Instance_map(const char *default_mysqld_path_arg,
-                           Thread_registry &thread_registry_arg):
-  mysqld_path(default_mysqld_path_arg),
-  thread_registry(thread_registry_arg)
+Instance_map::Instance_map()
 {
   pthread_mutex_init(&LOCK_instance_map, 0);
 }
 
 
-int Instance_map::init()
+bool Instance_map::init()
 {
   return hash_init(&hash, default_charset_info, START_HASH_SIZE, 0, 0,
                    get_instance_key, delete_instance, 0);
 }
 
-Instance_map::~Instance_map()
+bool Instance_map::reset()
 {
-  pthread_mutex_lock(&LOCK_instance_map);
   hash_free(&hash);
-  pthread_mutex_unlock(&LOCK_instance_map);
-  pthread_mutex_destroy(&LOCK_instance_map);
+  return init();
 }
 
-
-void Instance_map::lock()
+bool Instance_map::is_there_active_instance()
 {
-  pthread_mutex_lock(&LOCK_instance_map);
-}
-
+  Instance *instance;
+  Iterator iterator(this);
 
-void Instance_map::unlock()
-{
-  pthread_mutex_unlock(&LOCK_instance_map);
-}
+  while ((instance= iterator.next()))
+  {
+    bool active_instance_found;
 
-/*
-  Re-read instance configuration file.
+    instance->lock();
+    active_instance_found= instance->is_active();
+    instance->unlock();
 
-  SYNOPSIS
-    Instance_map::flush_instances()
+    if (active_instance_found)
+      return TRUE;
+  }
 
-  DESCRIPTION
-    This function will:
-     - clear the current list of instances. This removes both
-       running and stopped instances.
-     - load a new instance configuration from the file.
-     - pass on the new map to the guardian thread: it will start
-       all instances that are marked `guarded' and not yet started.
-    Note, as the check whether an instance is started is currently
-    very simple (returns TRUE if there is a MySQL server running
-    at the given port), this function has some peculiar
-    side-effects:
-     * if the port number of a running instance was changed, the
-       old instance is forgotten, even if it was running. The new
-       instance will be started at the new port.
-     * if the configuration was changed in a way that two
-       instances swapped their port numbers, the guardian thread
-       will not notice that and simply report that both instances
-       are configured successfully and running.
-    In order to avoid such side effects one should never call
-    FLUSH INSTANCES without prior stop of all running instances.
-
-  NOTE: The operation should be invoked with the following locks acquired:
-    - Guardian_thread;
-    - Instance_map;
-*/
+  return FALSE;
+}
 
-int Instance_map::flush_instances()
+Instance_map::~Instance_map()
 {
-  int rc;
+  lock();
 
   /*
-    Guardian thread relies on the instance map repository for guarding
-    instances. This is why refreshing instance map, we need (1) to stop
-    guardian (2) reload the instance map (3) reinitialize the guardian
-    with new instances.
+    NOTE: it's necessary to synchronize on each instance before removal,
+    because Instance-monitoring thread can be still alive an hold the mutex
+    (because it is detached and we have no control over it).
   */
+
+  while (true)
+  {
+    Iterator it(this);
+    Instance *instance= it.next();
+
+    if (!instance)
+      break;
+
+    instance->lock();
+    instance->unlock();
+
+    remove_instance(instance);
+  }
+
   hash_free(&hash);
-  hash_init(&hash, default_charset_info, START_HASH_SIZE, 0, 0,
-            get_instance_key, delete_instance, 0);
+  unlock();
 
-  rc= load();
-  /* don't init guardian if we failed to load instances */
-  if (!rc)
-    guardian->init(); // TODO: check error status.
-  return rc;
+  pthread_mutex_destroy(&LOCK_instance_map);
 }
 
 
-bool Instance_map::is_there_active_instance()
+void Instance_map::lock()
 {
-  Instance *instance;
-  Iterator iterator(this);
+  pthread_mutex_lock(&LOCK_instance_map);
+}
 
-  while ((instance= iterator.next()))
-  {
-    if (guardian->find_instance_node(instance) != NULL ||
-        instance->is_running())
-    {
-      return TRUE;
-    }
-  }
 
-  return FALSE;
+void Instance_map::unlock()
+{
+  pthread_mutex_unlock(&LOCK_instance_map);
 }
 
 
+
 int Instance_map::add_instance(Instance *instance)
 {
   return my_hash_insert(&hash, (byte *) instance);
@@ -335,18 +308,20 @@ int Instance_map::remove_instance(Instan
 int Instance_map::create_instance(const LEX_STRING *instance_name,
                                   const Named_value_arr *options)
 {
-  Instance *instance= new Instance(thread_registry);
+  Instance *instance= new Instance();
 
   if (!instance)
   {
-    log_error("Error: can not initialize (name: '%s').",
+    log_error("Error: can not allocate instance (name: '%s').",
               (const char *) instance_name->str);
     return ER_OUT_OF_RESOURCES;
   }
 
+  instance->set_state(Instance::STOPPED);
+
   if (instance->init(instance_name))
   {
-    log_error("Error: can not initialize (name: '%s').",
+    log_error("Error: can not initialize instance (name: '%s').",
               (const char *) instance_name->str);
     delete instance;
     return ER_OUT_OF_RESOURCES;
@@ -374,7 +349,7 @@ int Instance_map::create_instance(const 
     log_info("Warning: instance name '%s' is mysqld-compatible.",
              (const char *) instance_name->str);
 
-  if (instance->complete_initialization(this, mysqld_path))
+  if (instance->complete_initialization())
   {
     log_error("Error: can not complete initialization of instance (name: '%s').",
               (const char *) instance_name->str);
@@ -411,7 +386,7 @@ bool Instance_map::complete_initializati
   {
     Instance *instance= (Instance *) hash_element(&hash, i);
 
-    if (instance->complete_initialization(this, mysqld_path))
+    if (instance->complete_initialization())
       return TRUE;
   }
 
@@ -523,27 +498,6 @@ Instance *Instance_map::Iterator::next()
     return (Instance *) hash_element(&instance_map->hash, current_instance++);
 
   return NULL;
-}
-
-
-const char *Instance_map::get_instance_state_name(Instance *instance)
-{
-  LIST *instance_node;
-
-  if (!instance->is_configured())
-    return "misconfigured";
-
-  if ((instance_node= guardian->find_instance_node(instance)) != NULL)
-  {
-    /* The instance is managed by Guardian: we can report precise state. */
-
-    return Guardian_thread::get_instance_state_name(
-      guardian->get_instance_state(instance_node));
-  }
-
-  /* The instance is not managed by Guardian: we can report status only.  */
-
-  return instance->is_running() ? "online" : "offline";
 }
 
 

--- 1.21/server-tools/instance-manager/instance_map.h	2006-10-27 15:30:46 +04:00
+++ 1.22/server-tools/instance-manager/instance_map.h	2006-10-27 15:30:46 +04:00
@@ -25,10 +25,8 @@
 #pragma interface
 #endif
 
-class Guardian_thread;
 class Instance;
 class Named_value_arr;
-class Thread_registry;
 
 extern int load_all_groups(char ***groups, const char *filename);
 extern void free_groups(char **groups);
@@ -66,16 +64,17 @@ public:
   */
   Instance *find(const LEX_STRING *name);
 
-  /* Clear the configuration cache and reload the configuration file. */
-  int flush_instances();
-
-  /* The operation is used to check if there is an active instance or not. */
-  bool is_there_active_instance();
-
   void lock();
   void unlock();
 
-  int init();
+  /* loads options from config files */
+  int load();
+
+  bool init();
+  bool reset();
+
+  /* The operation is used to check if there is an active instance or not. */
+  bool is_there_active_instance();
 
   /*
     Process a given option and assign it to appropricate instance. This is
@@ -105,35 +104,16 @@ public:
   int create_instance(const LEX_STRING *instance_name,
                       const Named_value_arr *options);
 
-  Instance_map(const char *default_mysqld_path_arg,
-               Thread_registry &thread_registry_arg);
+  Instance_map();
   ~Instance_map();
 
-  /*
-    Retrieve client state name of the given instance.
-
-    MT-NOTE: the options must be called under acquired locks of the following
-    objects:
-      - Instance_map;
-      - Guardian_thread;
-  */
-  const char *get_instance_state_name(Instance *instance);
-
-public:
-  const char *mysqld_path;
-  Guardian_thread *guardian;
-
 private:
-  /* loads options from config files */
-  int load();
   /* inits instances argv's after all options have been loaded */
   bool complete_initialization();
 private:
   enum { START_HASH_SIZE = 16 };
   pthread_mutex_t LOCK_instance_map;
   HASH hash;
-
-  Thread_registry &thread_registry;
 };
 
 #endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_INSTANCE_MAP_H */

--- 1.37/server-tools/instance-manager/instance_options.cc	2006-10-27 15:30:46 +04:00
+++ 1.38/server-tools/instance-manager/instance_options.cc	2006-10-27 15:30:46 +04:00
@@ -29,6 +29,7 @@
 #include "buffer.h"
 #include "instance.h"
 #include "log.h"
+#include "options.h"
 #include "parse_output.h"
 #include "priv.h"
 
@@ -182,7 +183,7 @@ int Instance_options::fill_instance_vers
 err:
   if (rc)
     log_error("fill_instance_version: Failed to get version of '%s'",
-              mysqld_path);
+              (const char *) mysqld_path.str);
   return rc;
 }
 
@@ -396,7 +397,7 @@ int Instance_options::unlink_pidfile()
 }
 
 
-pid_t Instance_options::get_pid()
+pid_t Instance_options::load_pid()
 {
   FILE *pid_file_stream;
 
@@ -415,7 +416,7 @@ pid_t Instance_options::get_pid()
 }
 
 
-int Instance_options::complete_initialization(const char *default_path)
+bool Instance_options::complete_initialization()
 {
   int arg_idx;
   const char *tmp;
@@ -424,9 +425,13 @@ int Instance_options::complete_initializ
   if (!mysqld_path.str)
   {
     // Need one extra byte, as convert_dirname() adds a slash at the end.
-    if (!(mysqld_path.str= alloc_root(&alloc, strlen(default_path) + 2)))
-      goto err;
-    strcpy(mysqld_path.str, default_path);
+    mysqld_path.str= alloc_root(&alloc,
+                                strlen(Options::Main::default_mysqld_path) + 2);
+
+    if (!mysqld_path.str)
+      return TRUE;
+
+    strcpy(mysqld_path.str, Options::Main::default_mysqld_path);
   }
 
   // it's safe to cast this to char* since this is a buffer we are allocating
@@ -442,7 +447,7 @@ int Instance_options::complete_initializ
     shutdown_delay_val= atoi(shutdown_delay);
 
   if (!(tmp= strdup_root(&alloc, "--no-defaults")))
-    goto err;
+    return TRUE;
 
   if (!mysqld_pid_file)
   {
@@ -477,21 +482,21 @@ int Instance_options::complete_initializ
   }
 
   if (get_pid_filename(pid_file_with_path))
-    goto err;
+    return TRUE;
 
   /* we need to reserve space for the final zero + possible default options */
   if (!(argv= (char**)
         alloc_root(&alloc, (get_num_options() + 1
                             + MAX_NUMBER_OF_DEFAULT_OPTIONS) * sizeof(char*))))
-    goto err;
+    return TRUE;
   filled_default_options= 0;
 
   /* the path must be first in the argv */
   if (add_to_argv(mysqld_path.str))
-    goto err;
+    return TRUE;
 
   if (add_to_argv(tmp))
-    goto err;
+    return TRUE;
 
   arg_idx= filled_default_options;
   for (int opt_idx= 0; opt_idx < get_num_options(); ++opt_idx)
@@ -514,12 +519,9 @@ int Instance_options::complete_initializ
   argv[arg_idx]= 0;
 
   if (fill_log_options() || fill_mysqld_real_path() || fill_instance_version())
-    goto err;
-
-  return 0;
+    return TRUE;
 
-err:
-  return 1;
+  return FALSE;
 }
 
 
@@ -636,26 +638,26 @@ void Instance_options::print_argv()
 
 /*
   We execute this function to initialize some options.
-  Return value: 0 - ok. 1 - unable to allocate memory.
+
+  RETURN
+    FALSE - ok
+    TRUE  - memory allocation error
 */
 
-int Instance_options::init(const LEX_STRING *instance_name_arg)
+bool Instance_options::init(const LEX_STRING *instance_name_arg)
 {
   instance_name.length= instance_name_arg->length;
 
   init_alloc_root(&alloc, MEM_ROOT_BLOCK_SIZE, 0);
 
   if (options.init())
-    goto err;
+    return TRUE;
 
   if (!(instance_name.str= strmake_root(&alloc, instance_name_arg->str,
                                         instance_name_arg->length)))
-    goto err;
-
-  return 0;
+    return TRUE;
 
-err:
-  return 1;
+  return FALSE;
 }
 
 

--- 1.20/server-tools/instance-manager/instance_options.h	2006-10-27 15:30:46 +04:00
+++ 1.21/server-tools/instance-manager/instance_options.h	2006-10-27 15:30:46 +04:00
@@ -45,8 +45,9 @@ public:
 public:
   Instance_options();
   ~Instance_options();
+
   /* fills in argv */
-  int complete_initialization(const char *default_path);
+  bool complete_initialization();
 
   bool set_option(Named_value *option);
   void unset_option(const char *option_name);
@@ -55,12 +56,15 @@ public:
   inline Named_value get_option(int idx) const;
 
 public:
-  int init(const LEX_STRING *instance_name_arg);
-  pid_t get_pid();
+  bool init(const LEX_STRING *instance_name_arg);
+  pid_t load_pid();
   int get_pid_filename(char *result);
   int unlink_pidfile();
   void print_argv();
 
+  inline uint get_shutdown_delay() const;
+  inline int get_mysqld_port() const;
+
 public:
   /*
     We need this value to be greater or equal then FN_REFLEN found in
@@ -79,14 +83,10 @@ public:
   const char *mysqld_socket;
   const char *mysqld_datadir;
   const char *mysqld_pid_file;
-  const char *mysqld_port;
-  uint mysqld_port_val;
   LEX_STRING instance_name;
   LEX_STRING mysqld_path;
   LEX_STRING mysqld_real_path;
   const char *nonguarded;
-  const char *shutdown_delay;
-  uint shutdown_delay_val;
   /* log enums are defined in parse.h */
   char *logs[3];
 
@@ -102,6 +102,11 @@ private:
   int find_option(const char *option_name);
 
 private:
+  const char *mysqld_port;
+  uint mysqld_port_val;
+  const char *shutdown_delay;
+  uint shutdown_delay_val;
+
   uint filled_default_options;
   MEM_ROOT alloc;
 
@@ -118,6 +123,30 @@ inline int Instance_options::get_num_opt
 inline Named_value Instance_options::get_option(int idx) const
 {
   return options.get_element(idx);
+}
+
+inline uint Instance_options::get_shutdown_delay() const
+{
+  static const uint DEFAULT_SHUTDOWN_DELAY= 35;
+
+  /*
+    NOTE: it is important to check shutdown_delay here, but use
+    shutdown_delay_val. The idea is that if the option is unset,
+    shutdown_delay will be NULL, but shutdown_delay_val will not be reset.
+  */
+
+  return shutdown_delay ? shutdown_delay_val : DEFAULT_SHUTDOWN_DELAY;
+}
+
+inline int Instance_options::get_mysqld_port() const
+{
+  /*
+    NOTE: it is important to check mysqld_port here, but use mysqld_port_val.
+    The idea is that if the option is unset, mysqld_port will be NULL, but
+    mysqld_port_val will not be reset.
+  */
+
+  return mysqld_port ? mysqld_port_val : 0;
 }
 
 #endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_INSTANCE_OPTIONS_H */

--- 1.17/server-tools/instance-manager/mysql_connection.cc	2006-10-27 15:30:46 +04:00
+++ 1.18/server-tools/instance-manager/mysql_connection.cc	2006-10-27 15:30:46 +04:00
@@ -21,7 +21,6 @@
 #include "mysql_connection.h"
 
 #include <m_string.h>
-#include <m_string.h>
 #include <my_global.h>
 #include <mysql_com.h>
 #include <mysql.h>
@@ -29,6 +28,7 @@
 #include <violite.h>
 
 #include "command.h"
+#include "manager.h"
 #include "log.h"
 #include "messages.h"
 #include "mysqld_error.h"
@@ -42,15 +42,9 @@
 
 Mysql_connection_thread_args::Mysql_connection_thread_args(
                              struct st_vio *vio_arg,
-                             Thread_registry &thread_registry_arg,
-                             const User_map &user_map_arg,
-                             ulong connection_id_arg,
-                             Instance_map &instance_map_arg) :
+                             ulong connection_id_arg) :
     vio(vio_arg)
-    ,thread_registry(thread_registry_arg)
-    ,user_map(user_map_arg)
     ,connection_id(connection_id_arg)
-    ,instance_map(instance_map_arg)
   {}
 
 /*
@@ -76,6 +70,7 @@ public:
   ~Mysql_connection_thread();
 private:
   Thread_info thread_info;
+  Thread_registry &thread_registry;
   NET net;
   struct rand_struct rand_st;
   char scramble[SCRAMBLE_LENGTH + 1];
@@ -93,11 +88,9 @@ private:
 Mysql_connection_thread::Mysql_connection_thread(
                                    const Mysql_connection_thread_args &args) :
   Mysql_connection_thread_args(args.vio,
-                               args.thread_registry,
-                               args.user_map,
-                               args.connection_id,
-                               args.instance_map)
-  ,thread_info(pthread_self(), TRUE)
+                               args.connection_id),
+  thread_info(pthread_self(), TRUE),
+  thread_registry(Manager::get_instance().get_thread_registry())
 {
   thread_registry.register_thread(&thread_info);
 }
@@ -272,6 +265,7 @@ int Mysql_connection_thread::check_conne
   const char *password= strend(user)+1;
   ulong password_len= *password++;
   LEX_STRING user_name= { (char *) user, password - user - 2 };
+  User_map &user_map= Manager::get_instance().get_user_map();
 
   if (password_len != SCRAMBLE_LENGTH)
   {
@@ -338,7 +332,7 @@ int Mysql_connection_thread::dispatch_co
     log_info("query for connection %d : ----\n%s\n-------------------------",
 	     (int) connection_id,
              (const char *) packet);
-    if (Command *command= parse_command(&instance_map, packet))
+    if (Command *command= parse_command(packet))
     {
       int res= 0;
       log_info("query for connection %d successfully parsed",

--- 1.5/server-tools/instance-manager/mysql_connection.h	2006-10-27 15:30:46 +04:00
+++ 1.6/server-tools/instance-manager/mysql_connection.h	2006-10-27 15:30:46 +04:00
@@ -25,24 +25,15 @@
 
 pthread_handler_t mysql_connection(void *arg);
 
-class Thread_registry;
-class User_map;
-class Instance_map;
 struct st_vio;
 
 struct Mysql_connection_thread_args
 {
   struct st_vio *vio;
-  Thread_registry &thread_registry;
-  const User_map &user_map;
   ulong connection_id;
-  Instance_map &instance_map;
 
   Mysql_connection_thread_args(struct st_vio *vio_arg,
-                               Thread_registry &thread_registry_arg,
-                               const User_map &user_map_arg,
-                               ulong connection_id_arg,
-                               Instance_map &instance_map_arg);
+                               ulong connection_id_arg);
 };
 
 #endif // INCLUDES_MYSQL_INSTANCE_MANAGER_MYSQL_CONNECTION_H

--- 1.15/server-tools/instance-manager/parse.cc	2006-10-27 15:30:46 +04:00
+++ 1.16/server-tools/instance-manager/parse.cc	2006-10-27 15:30:46 +04:00
@@ -269,11 +269,11 @@ void skip_spaces(const char **text)
 }
 
 
-Command *parse_command(Instance_map *map, const char *text)
+Command *parse_command(const char *text)
 {
   uint word_len;
   LEX_STRING instance_name;
-  Command *command;
+  Command *command= NULL;
   const char *saved_text= text;
 
   Token tok1= shift_token(&text, &word_len);
@@ -294,7 +294,7 @@ Command *parse_command(Instance_map *map
 
     if (tok1 == TOK_CREATE)
     {
-      Create_instance *cmd= new Create_instance(map, &instance_name);
+      Create_instance *cmd= new Create_instance(&instance_name);
 
       if (!cmd)
         return NULL; /* Report ER_OUT_OF_RESOURCES. */
@@ -317,16 +317,16 @@ Command *parse_command(Instance_map *map
 
     switch (tok1) {
     case TOK_START:
-      command= new Start_instance(map, &instance_name);
+      command= new Start_instance(&instance_name);
       break;
     case TOK_STOP:
-      command= new Stop_instance(map, &instance_name);
+      command= new Stop_instance(&instance_name);
       break;
     case TOK_CREATE:
       ; /* command already initialized. */
       break;
     case TOK_DROP:
-      command= new Drop_instance(map, &instance_name);
+      command= new Drop_instance(&instance_name);
       break;
     default: /* this is impossible, but nevertheless... */
       DBUG_ASSERT(0);
@@ -340,7 +340,7 @@ Command *parse_command(Instance_map *map
     if (word_len)
       goto syntax_error;
 
-    command= new Flush_instances(map);
+    command= new Flush_instances();
     break;
   case TOK_UNSET:
   case TOK_SET:
@@ -348,9 +348,9 @@ Command *parse_command(Instance_map *map
       Abstract_option_cmd *cmd;
 
       if (tok1 == TOK_SET)
-        cmd= new Set_option(map);
+        cmd= new Set_option();
       else
-        cmd= new Unset_option(map);
+        cmd= new Unset_option();
 
       if (!cmd)
         return NULL; /* Report ER_OUT_OF_RESOURCES. */
@@ -371,7 +371,7 @@ Command *parse_command(Instance_map *map
       get_word(&text, &word_len, NONSPACE);
       if (word_len)
         goto syntax_error;
-      command= new Show_instances(map);
+      command= new Show_instances();
       break;
     case TOK_INSTANCE:
       switch (Token tok2= shift_token(&text, &word_len)) {
@@ -385,9 +385,9 @@ Command *parse_command(Instance_map *map
         if (word_len)
           goto syntax_error;
         if (tok2 == TOK_STATUS)
-          command= new Show_instance_status(map, &instance_name);
+          command= new Show_instance_status(&instance_name);
         else
-          command= new Show_instance_options(map, &instance_name);
+          command= new Show_instance_options(&instance_name);
         break;
       default:
         goto syntax_error;
@@ -414,7 +414,7 @@ Command *parse_command(Instance_map *map
             /* check that this is the end of the command */
             if (word_len)
               goto syntax_error;
-            command= new Show_instance_log_files(map, &instance_name);
+            command= new Show_instance_log_files(&instance_name);
             break;
           case TOK_ERROR:
           case TOK_GENERAL:
@@ -484,7 +484,7 @@ Command *parse_command(Instance_map *map
                 goto syntax_error;
             }
 
-            command= new Show_instance_log(map, &instance_name,
+            command= new Show_instance_log(&instance_name,
                                            log_type, log_size, log_offset);
           break;
           default:
@@ -504,5 +504,8 @@ Command *parse_command(Instance_map *map
 syntax_error:
     command= new Syntax_error();
   }
+
+  DBUG_ASSERT(command);
+
   return command;
 }

--- 1.9/server-tools/instance-manager/parse.h	2006-10-27 15:30:46 +04:00
+++ 1.10/server-tools/instance-manager/parse.h	2006-10-27 15:30:46 +04:00
@@ -21,7 +21,6 @@
 #include <m_string.h>
 
 class Command;
-class Instance_map;
 
 enum Log_type
 {
@@ -30,7 +29,7 @@ enum Log_type
   IM_LOG_SLOW
 };
 
-Command *parse_command(Instance_map *map, const char *text);
+Command *parse_command(const char *text);
 
 bool parse_option_value(const char *text, uint *text_len, char **value);
 

--- 1.12/server-tools/instance-manager/priv.cc	2006-10-27 15:30:46 +04:00
+++ 1.13/server-tools/instance-manager/priv.cc	2006-10-27 15:30:46 +04:00
@@ -18,6 +18,9 @@
 
 #include <my_global.h>
 #include <mysql_com.h>
+#include <my_sys.h>
+
+#include "log.h"
 
 #if defined(__ia64__) || defined(__ia64)
 /*
@@ -30,14 +33,13 @@
 #endif
 
 
-/* the pid of the manager process (of the signal thread on the LinuxThreads) */
-pid_t manager_pid;
-
+#ifndef __WIN__
 /*
   This flag is set if mysqlmanager has detected that it is running on the
   system using LinuxThreads
 */
 bool linuxthreads;
+#endif
 
 /*
   The following string must be less then 80 characters, as
@@ -89,4 +91,33 @@ int set_stacksize_n_create_thread(pthrea
   if (!rc)
     rc= pthread_create(thread, attr, start_routine, arg);
   return rc;
+}
+
+
+int create_pid_file(const char *pid_file_name, int pid)
+{
+  FILE *pid_file;
+
+  if (!(pid_file= my_fopen(pid_file_name, O_WRONLY | O_CREAT | O_BINARY,
+                           MYF(0))))
+  {
+    log_error("Error: can not create pid file '%s': %s (errno: %d)",
+              (const char *) pid_file_name,
+              (const char *) strerror(errno),
+              (int) errno);
+    return 1;
+  }
+
+  if (fprintf(pid_file, "%d\n", (int) pid) <= 0)
+  {
+    log_error("Error: can not write to pid file '%s': %s (errno: %d)",
+              (const char *) pid_file_name,
+              (const char *) strerror(errno),
+              (int) errno);
+    return 1;
+  }
+
+  my_fclose(pid_file, MYF(0));
+
+  return 0;
 }

--- 1.11/server-tools/instance-manager/priv.h	2006-10-27 15:30:46 +04:00
+++ 1.12/server-tools/instance-manager/priv.h	2006-10-27 15:30:46 +04:00
@@ -50,9 +50,6 @@ const int MAX_VERSION_LENGTH= 160;
 
 const int MAX_INSTANCE_NAME_SIZE= FN_REFLEN;
 
-/* the pid of the manager process (of the signal thread on the LinuxThreads) */
-extern pid_t manager_pid;
-
 #ifndef __WIN__
 /*
   This flag is set if mysqlmanager has detected that it is running on the
@@ -108,5 +105,7 @@ extern unsigned long open_files_limit;
 
 int set_stacksize_n_create_thread(pthread_t  *thread, pthread_attr_t *attr,
                                   void *(*start_routine)(void *), void *arg);
+
+int create_pid_file(const char *pid_file_name, int pid);
 
 #endif // INCLUDES_MYSQL_INSTANCE_MANAGER_PRIV_H

--- 1.7/server-tools/instance-manager/thread_registry.h	2006-10-27 15:30:46 +04:00
+++ 1.8/server-tools/instance-manager/thread_registry.h	2006-10-27 15:30:46 +04:00
@@ -101,6 +101,7 @@ public:
                  pthread_mutex_t *mutex);
   int cond_timedwait(Thread_info *info, pthread_cond_t *cond,
                      pthread_mutex_t *mutex, struct timespec *wait_time);
+
 private:
   void interrupt_threads();
   void wait_for_threads_to_unregister();
@@ -111,6 +112,10 @@ private:
   pthread_mutex_t LOCK_thread_registry;
   pthread_cond_t COND_thread_registry_is_empty;
   pthread_t sigwait_thread_pid;
+
+private:
+  Thread_registry(const Thread_registry &);
+  Thread_registry &operator =(const Thread_registry &);
 };
 
 

--- 1.17/server-tools/instance-manager/user_map.cc	2006-10-27 15:30:46 +04:00
+++ 1.18/server-tools/instance-manager/user_map.cc	2006-10-27 15:30:46 +04:00
@@ -74,11 +74,11 @@ int User::init(const char *line)
   password_length= strlen(password);
   if (password_length > SCRAMBLED_PASSWORD_CHAR_LENGTH)
   {
-    log_info("Error: password is too long (%d). Max length: %d. ",
-              "User line: '%s'.",
-              (int) password_length,
-              (int) SCRAMBLED_PASSWORD_CHAR_LENGTH,
-              (const char *) line);
+    log_info("Error: password is too long (%d). Max length: %d. "
+             "User line: '%s'.",
+             (int) password_length,
+             (int) SCRAMBLED_PASSWORD_CHAR_LENGTH,
+             (const char *) line);
     return 1;
   }
 

--- 1.9/server-tools/instance-manager/IMService.cpp	2006-10-27 15:30:46 +04:00
+++ 1.10/server-tools/instance-manager/IMService.cpp	2006-10-27 15:30:46 +04:00
@@ -36,7 +36,7 @@ void IMService::Run(DWORD argc, LPTSTR *
   ReportStatus((DWORD)SERVICE_RUNNING);
 
   // wait for main loop to terminate
-  manager();
+  Manager::exec();
   Options::cleanup();
 }
 
Thread
bk commit into 5.1 tree (anozdrin:1.2326) BUG#23215Alexander Nozdrin27 Oct