This is an implementation of two WL items:
- WL#3158: IM: Instance configuration extensions; - WL#3159: IM: --bootstrap and --start-default-instance modes The following new statements have been added: - CREATE INSTANCE; - DROP INSTANCE; The behaviour of the following statements have been changed: - SET; - UNSET; - FLUSH INSTANCES; - SHOW INSTANCES; - SHOW INSTANCE OPTIONS;
This commit is contained in:
parent
eee166d859
commit
c1113af15c
@ -64,7 +64,7 @@
|
||||
/* were just going to fake it here and get input from
|
||||
the keyboard */
|
||||
|
||||
char *get_tty_password(char *opt_message)
|
||||
char *get_tty_password(const char *opt_message)
|
||||
{
|
||||
char to[80];
|
||||
char *pos=to,*end=to+sizeof(to)-1;
|
||||
@ -150,7 +150,7 @@ static void get_password(char *to,uint length,int fd,bool echo)
|
||||
#endif /* ! HAVE_GETPASS */
|
||||
|
||||
|
||||
char *get_tty_password(char *opt_message)
|
||||
char *get_tty_password(const char *opt_message)
|
||||
{
|
||||
#ifdef HAVE_GETPASS
|
||||
char *passbuff;
|
||||
|
@ -246,4 +246,16 @@ extern int my_snprintf(char* to, size_t n, const char* fmt, ...);
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
/* LEX_STRING */
|
||||
|
||||
typedef struct LEX_STRING
|
||||
{
|
||||
char *str;
|
||||
uint length;
|
||||
};
|
||||
|
||||
#define STRING_WITH_LEN(X) (X), ((uint) (sizeof(X) - 1))
|
||||
#define C_STRING_WITH_SIZE(X) ((char *) (X)), ((uint) (sizeof(X) - 1))
|
||||
|
||||
#endif
|
||||
|
@ -76,6 +76,10 @@ extern int NEAR my_errno; /* Last error in mysys */
|
||||
#define MY_CHECK_ERROR 1 /* Params to my_end; Check open-close */
|
||||
#define MY_GIVE_INFO 2 /* Give time info about process*/
|
||||
|
||||
#define MY_REMOVE_NONE 0 /* Params for modify_defaults_file */
|
||||
#define MY_REMOVE_OPTION 1
|
||||
#define MY_REMOVE_SECTION 2
|
||||
|
||||
#define ME_HIGHBYTE 8 /* Shift for colours */
|
||||
#define ME_NOCUR 1 /* Don't use curses message */
|
||||
#define ME_OLDWIN 2 /* Use old window */
|
||||
|
@ -423,17 +423,11 @@ char *octet2hex(char *to, const char *str, unsigned int len);
|
||||
|
||||
/* end of password.c */
|
||||
|
||||
char *get_tty_password(char *opt_message);
|
||||
char *get_tty_password(const char *opt_message);
|
||||
const char *mysql_errno_to_sqlstate(unsigned int mysql_errno);
|
||||
|
||||
/* Some other useful functions */
|
||||
|
||||
my_bool my_init(void);
|
||||
extern int modify_defaults_file(const char *file_location, const char *option,
|
||||
const char *option_value,
|
||||
const char *section_name, int remove_option);
|
||||
int load_defaults(const char *conf_file, const char **groups,
|
||||
int *argc, char ***argv);
|
||||
my_bool my_thread_init(void);
|
||||
void my_thread_end(void);
|
||||
|
||||
|
@ -75,7 +75,7 @@
|
||||
#define _cputs(A) putstring(A)
|
||||
#endif
|
||||
|
||||
char *get_tty_password(char *opt_message)
|
||||
char *get_tty_password(const char *opt_message)
|
||||
{
|
||||
char to[80];
|
||||
char *pos=to,*end=to+sizeof(to)-1;
|
||||
@ -159,7 +159,7 @@ static void get_password(char *to,uint length,int fd,bool echo)
|
||||
#endif /* ! HAVE_GETPASS */
|
||||
|
||||
|
||||
char *get_tty_password(char *opt_message)
|
||||
char *get_tty_password(const char *opt_message)
|
||||
{
|
||||
#ifdef HAVE_GETPASS
|
||||
char *passbuff;
|
||||
|
@ -1212,8 +1212,11 @@ sub environment_setup () {
|
||||
$ENV{'NDBCLUSTER_PORT'}= $opt_ndbcluster_port;
|
||||
$ENV{'NDBCLUSTER_PORT_SLAVE'}=$opt_ndbcluster_port_slave;
|
||||
|
||||
$ENV{'IM_EXE'}= $exe_im;
|
||||
$ENV{'IM_PATH_PID'}= $instance_manager->{path_pid};
|
||||
$ENV{'IM_PORT'}= $instance_manager->{port};
|
||||
$ENV{'IM_DEFAULTS_PATH'}= $instance_manager->{defaults_file};
|
||||
$ENV{'IM_PASSWORD_PATH'}= $instance_manager->{password_file};
|
||||
|
||||
$ENV{'IM_MYSQLD1_SOCK'}= $instance_manager->{instances}->[0]->{path_sock};
|
||||
$ENV{'IM_MYSQLD1_PORT'}= $instance_manager->{instances}->[0]->{port};
|
||||
|
40
mysql-test/r/im_cmd_line.result
Normal file
40
mysql-test/r/im_cmd_line.result
Normal file
@ -0,0 +1,40 @@
|
||||
--> Listing users...
|
||||
im_admin
|
||||
|
||||
==> Adding user 'testuser'...
|
||||
|
||||
--> IM password file:
|
||||
testuser:*0D3CED9BEC10A777AEC23CCC353A8C08A633045E
|
||||
im_admin:*598D51AD2DFF7792045D6DF3DDF9AA1AF737B295
|
||||
--> EOF
|
||||
|
||||
--> Printing out line for 'testuser'...
|
||||
testuser:*0D3CED9BEC10A777AEC23CCC353A8C08A633045E
|
||||
|
||||
--> Listing users...
|
||||
im_admin
|
||||
testuser
|
||||
|
||||
==> Changing the password of 'testuser'...
|
||||
|
||||
--> IM password file:
|
||||
im_admin:*598D51AD2DFF7792045D6DF3DDF9AA1AF737B295
|
||||
testuser:*39C549BDECFBA8AFC3CE6B948C9359A0ECE08DE2
|
||||
--> EOF
|
||||
|
||||
--> Printing out line for 'testuser'...
|
||||
testuser:*39C549BDECFBA8AFC3CE6B948C9359A0ECE08DE2
|
||||
|
||||
--> Listing users...
|
||||
testuser
|
||||
im_admin
|
||||
|
||||
==> Dropping user 'testuser'...
|
||||
|
||||
--> IM password file:
|
||||
im_admin:*598D51AD2DFF7792045D6DF3DDF9AA1AF737B295
|
||||
--> EOF
|
||||
|
||||
--> Listing users...
|
||||
im_admin
|
||||
|
@ -1,5 +1,5 @@
|
||||
SHOW INSTANCES;
|
||||
instance_name status
|
||||
instance_name state
|
||||
mysqld1 online
|
||||
mysqld2 offline
|
||||
Killing the process...
|
||||
|
196
mysql-test/r/im_instance_conf.result
Normal file
196
mysql-test/r/im_instance_conf.result
Normal file
@ -0,0 +1,196 @@
|
||||
--------------------------------------------------------------------
|
||||
server_id =1
|
||||
server_id =2
|
||||
--------------------------------------------------------------------
|
||||
SHOW INSTANCES;
|
||||
instance_name state
|
||||
mysqld1 online
|
||||
mysqld2 offline
|
||||
|
||||
---> connection: mysql1_con
|
||||
SHOW VARIABLES LIKE 'server_id';
|
||||
Variable_name Value
|
||||
server_id 1
|
||||
|
||||
---> connection: default
|
||||
CREATE INSTANCE mysqld3;
|
||||
SHOW INSTANCES;
|
||||
instance_name state
|
||||
mysqld3 offline
|
||||
mysqld2 offline
|
||||
mysqld1 online
|
||||
--------------------------------------------------------------------
|
||||
server_id =1
|
||||
server_id =2
|
||||
--------------------------------------------------------------------
|
||||
CREATE INSTANCE mysqld1;
|
||||
ERROR HY000: Instance already exists
|
||||
CREATE INSTANCE mysqld2;
|
||||
ERROR HY000: Instance already exists
|
||||
CREATE INSTANCE mysqld3;
|
||||
ERROR HY000: Instance already exists
|
||||
--------------------------------------------------------------------
|
||||
nonguarded
|
||||
--------------------------------------------------------------------
|
||||
CREATE INSTANCE mysqld4 nonguarded;
|
||||
SHOW INSTANCES;
|
||||
instance_name state
|
||||
mysqld3 offline
|
||||
mysqld4 offline
|
||||
mysqld1 online
|
||||
mysqld2 offline
|
||||
--------------------------------------------------------------------
|
||||
nonguarded
|
||||
nonguarded
|
||||
--------------------------------------------------------------------
|
||||
--------------------------------------------------------------------
|
||||
--------------------------------------------------------------------
|
||||
--------------------------------------------------------------------
|
||||
CREATE INSTANCE mysqld5 test-A = 000, test-B = test;
|
||||
SHOW INSTANCES;
|
||||
instance_name state
|
||||
mysqld1 online
|
||||
mysqld4 offline
|
||||
mysqld5 offline
|
||||
mysqld2 offline
|
||||
mysqld3 offline
|
||||
--------------------------------------------------------------------
|
||||
test-A=000
|
||||
--------------------------------------------------------------------
|
||||
test-B=test
|
||||
--------------------------------------------------------------------
|
||||
--------------------------------------------------------------------
|
||||
--------------------------------------------------------------------
|
||||
CREATE INSTANCE mysqld6 test-C1 = 10 , test-C2 = 02 ;
|
||||
SHOW INSTANCES;
|
||||
instance_name state
|
||||
mysqld1 online
|
||||
mysqld2 offline
|
||||
mysqld5 offline
|
||||
mysqld6 offline
|
||||
mysqld3 offline
|
||||
mysqld4 offline
|
||||
--------------------------------------------------------------------
|
||||
test-C1=10
|
||||
--------------------------------------------------------------------
|
||||
test-C2=02
|
||||
--------------------------------------------------------------------
|
||||
--------------------------------------------------------------------
|
||||
--------------------------------------------------------------------
|
||||
--------------------------------------------------------------------
|
||||
CREATE INSTANCE mysqld7 test-D = test-D-value ;
|
||||
ERROR 42000: You have an error in your command syntax. Check the manual that corresponds to your MySQL Instance Manager version for the right syntax to use
|
||||
SHOW INSTANCES;
|
||||
instance_name state
|
||||
mysqld1 online
|
||||
mysqld2 offline
|
||||
mysqld5 offline
|
||||
mysqld6 offline
|
||||
mysqld3 offline
|
||||
mysqld4 offline
|
||||
CREATE INSTANCE mysqld8 test-E 0 ;
|
||||
ERROR 42000: You have an error in your command syntax. Check the manual that corresponds to your MySQL Instance Manager version for the right syntax to use
|
||||
SHOW INSTANCES;
|
||||
instance_name state
|
||||
mysqld1 online
|
||||
mysqld2 offline
|
||||
mysqld5 offline
|
||||
mysqld6 offline
|
||||
mysqld3 offline
|
||||
mysqld4 offline
|
||||
CREATE INSTANCE mysqld8 test-F = ;
|
||||
ERROR 42000: You have an error in your command syntax. Check the manual that corresponds to your MySQL Instance Manager version for the right syntax to use
|
||||
SHOW INSTANCES;
|
||||
instance_name state
|
||||
mysqld1 online
|
||||
mysqld2 offline
|
||||
mysqld5 offline
|
||||
mysqld6 offline
|
||||
mysqld3 offline
|
||||
mysqld4 offline
|
||||
--------------------------------------------------------------------
|
||||
--------------------------------------------------------------------
|
||||
--------------------------------------------------------------------
|
||||
--------------------------------------------------------------------
|
||||
--------------------------------------------------------------------
|
||||
--------------------------------------------------------------------
|
||||
--------------------------------------------------------------------
|
||||
--------------------------------------------------------------------
|
||||
CREATE INSTANCE mysqld9 test-1=" hello world ", test-2=' ';
|
||||
SHOW INSTANCES;
|
||||
instance_name state
|
||||
mysqld1 online
|
||||
mysqld2 offline
|
||||
mysqld5 offline
|
||||
mysqld6 offline
|
||||
mysqld3 offline
|
||||
mysqld4 offline
|
||||
mysqld9 offline
|
||||
CREATE INSTANCE mysqld9a test-3='\b\babc\sdef';
|
||||
SHOW INSTANCES;
|
||||
instance_name state
|
||||
mysqld1 online
|
||||
mysqld9a offline
|
||||
mysqld5 offline
|
||||
mysqld6 offline
|
||||
mysqld3 offline
|
||||
mysqld4 offline
|
||||
mysqld9 offline
|
||||
mysqld2 offline
|
||||
CREATE INSTANCE mysqld9b test-4='abc\tdef', test-5='abc\ndef';
|
||||
SHOW INSTANCES;
|
||||
instance_name state
|
||||
mysqld9b offline
|
||||
mysqld9a offline
|
||||
mysqld5 offline
|
||||
mysqld6 offline
|
||||
mysqld3 offline
|
||||
mysqld4 offline
|
||||
mysqld9 offline
|
||||
mysqld2 offline
|
||||
mysqld1 online
|
||||
CREATE INSTANCE mysqld9c test-6="abc\rdef", test-7="abc\\def";
|
||||
SHOW INSTANCES;
|
||||
instance_name state
|
||||
mysqld9b offline
|
||||
mysqld6 offline
|
||||
mysqld5 offline
|
||||
mysqld9c offline
|
||||
mysqld3 offline
|
||||
mysqld4 offline
|
||||
mysqld9 offline
|
||||
mysqld2 offline
|
||||
mysqld1 online
|
||||
mysqld9a offline
|
||||
CREATE INSTANCE mysqld10 test-bad=' \ ';
|
||||
ERROR 42000: You have an error in your command syntax. Check the manual that corresponds to your MySQL Instance Manager version for the right syntax to use
|
||||
SHOW INSTANCES;
|
||||
instance_name state
|
||||
mysqld9b offline
|
||||
mysqld6 offline
|
||||
mysqld5 offline
|
||||
mysqld9c offline
|
||||
mysqld3 offline
|
||||
mysqld4 offline
|
||||
mysqld9 offline
|
||||
mysqld2 offline
|
||||
mysqld1 online
|
||||
mysqld9a offline
|
||||
--------------------------------------------------------------------
|
||||
test-1= hello world
|
||||
--------------------------------------------------------------------
|
||||
test-2=
|
||||
--------------------------------------------------------------------
|
||||
test-3=abc def
|
||||
--------------------------------------------------------------------
|
||||
test-4=abc def
|
||||
--------------------------------------------------------------------
|
||||
test-5=abc
|
||||
--------------------------------------------------------------------
|
||||
test-6=abc
def
|
||||
--------------------------------------------------------------------
|
||||
test-7=abc\def
|
||||
--------------------------------------------------------------------
|
||||
--------------------------------------------------------------------
|
||||
CREATE INSTANCE qqq1;
|
||||
ERROR HY000: Malformed instance name.
|
@ -1,69 +1,93 @@
|
||||
|
||||
--------------------------------------------------------------------
|
||||
-- 1.1.1.
|
||||
--------------------------------------------------------------------
|
||||
SHOW INSTANCES;
|
||||
instance_name status
|
||||
instance_name state
|
||||
mysqld1 online
|
||||
mysqld2 offline
|
||||
SHOW INSTANCE STATUS mysqld1;
|
||||
instance_name status version_number version
|
||||
mysqld1 online VERSION_NUMBER VERSION
|
||||
SHOW INSTANCE STATUS mysqld2;
|
||||
instance_name status version_number version
|
||||
mysqld2 offline VERSION_NUMBER VERSION
|
||||
|
||||
--------------------------------------------------------------------
|
||||
-- 1.1.2.
|
||||
--------------------------------------------------------------------
|
||||
START INSTANCE mysqld2;
|
||||
SHOW INSTANCES;
|
||||
instance_name status
|
||||
instance_name state
|
||||
mysqld1 online
|
||||
mysqld2 online
|
||||
SHOW INSTANCE STATUS mysqld1;
|
||||
instance_name status version_number version
|
||||
mysqld1 online VERSION_NUMBER VERSION
|
||||
SHOW INSTANCE STATUS mysqld2;
|
||||
instance_name status version_number version
|
||||
mysqld2 online VERSION_NUMBER VERSION
|
||||
SHOW VARIABLES LIKE 'port';
|
||||
Variable_name Value
|
||||
port IM_MYSQLD1_PORT
|
||||
port IM_MYSQLD2_PORT
|
||||
|
||||
--------------------------------------------------------------------
|
||||
-- 1.1.3.
|
||||
--------------------------------------------------------------------
|
||||
STOP INSTANCE mysqld2;
|
||||
SHOW INSTANCES;
|
||||
instance_name status
|
||||
instance_name state
|
||||
mysqld1 online
|
||||
mysqld2 offline
|
||||
SHOW INSTANCE STATUS mysqld1;
|
||||
instance_name status version_number version
|
||||
mysqld1 online VERSION_NUMBER VERSION
|
||||
instance_name state version_number version mysqld_compatible
|
||||
mysqld1 online VERSION_NUMBER VERSION no
|
||||
SHOW INSTANCE STATUS mysqld2;
|
||||
instance_name status version_number version
|
||||
mysqld2 offline VERSION_NUMBER VERSION
|
||||
instance_name state version_number version mysqld_compatible
|
||||
mysqld2 offline VERSION_NUMBER VERSION no
|
||||
|
||||
--------------------------------------------------------------------
|
||||
-- 1.1.4.
|
||||
--------------------------------------------------------------------
|
||||
START INSTANCE mysqld3;
|
||||
ERROR HY000: Bad instance name. Check that the instance with such a name exists
|
||||
START INSTANCE mysqld1;
|
||||
ERROR HY000: The instance is already started
|
||||
|
||||
--------------------------------------------------------------------
|
||||
-- 1.1.5.
|
||||
--------------------------------------------------------------------
|
||||
STOP INSTANCE mysqld3;
|
||||
ERROR HY000: Bad instance name. Check that the instance with such a name exists
|
||||
|
||||
--------------------------------------------------------------------
|
||||
-- 1.1.6.
|
||||
--------------------------------------------------------------------
|
||||
SHOW INSTANCES;
|
||||
instance_name status
|
||||
instance_name state
|
||||
mysqld1 online
|
||||
mysqld2 offline
|
||||
Killing the process...
|
||||
Sleeping...
|
||||
Success: the process was restarted.
|
||||
|
||||
--------------------------------------------------------------------
|
||||
-- 1.1.7.
|
||||
--------------------------------------------------------------------
|
||||
SHOW INSTANCES;
|
||||
instance_name status
|
||||
instance_name state
|
||||
mysqld1 online
|
||||
mysqld2 offline
|
||||
START INSTANCE mysqld2;
|
||||
SHOW INSTANCES;
|
||||
instance_name status
|
||||
instance_name state
|
||||
mysqld1 online
|
||||
mysqld2 online
|
||||
Killing the process...
|
||||
Sleeping...
|
||||
Success: the process was killed.
|
||||
SHOW INSTANCES;
|
||||
instance_name status
|
||||
instance_name state
|
||||
mysqld1 online
|
||||
mysqld2 offline
|
||||
|
||||
--------------------------------------------------------------------
|
||||
-- 1.1.8.
|
||||
--------------------------------------------------------------------
|
||||
SHOW INSTANCE STATUS;
|
||||
ERROR 42000: You have an error in your command syntax. Check the manual that corresponds to your MySQL Instance Manager version for the right syntax to use
|
||||
|
||||
--------------------------------------------------------------------
|
||||
-- BUG#12813
|
||||
--------------------------------------------------------------------
|
||||
START INSTANCE mysqld1,mysqld2,mysqld3;
|
||||
ERROR 42000: You have an error in your command syntax. Check the manual that corresponds to your MySQL Instance Manager version for the right syntax to use
|
||||
STOP INSTANCE mysqld1,mysqld2,mysqld3;
|
||||
|
150
mysql-test/r/im_options.result
Normal file
150
mysql-test/r/im_options.result
Normal file
@ -0,0 +1,150 @@
|
||||
--------------------------------------------------------------------
|
||||
server_id =1
|
||||
server_id =2
|
||||
--------------------------------------------------------------------
|
||||
SHOW VARIABLES LIKE 'server_id';
|
||||
Variable_name Value
|
||||
server_id 1
|
||||
SHOW INSTANCES;
|
||||
instance_name state
|
||||
mysqld1 starting
|
||||
mysqld2 offline
|
||||
UNSET mysqld1.server_id;
|
||||
ERROR HY000: The instance is active. Stop the instance first
|
||||
SET mysqld1.server_id = 11;
|
||||
ERROR HY000: The instance is active. Stop the instance first
|
||||
CREATE INSTANCE mysqld3 datadir = '/';
|
||||
START INSTANCE mysqld3;
|
||||
UNSET mysqld3.server_id;
|
||||
ERROR HY000: The instance is active. Stop the instance first
|
||||
SET mysqld3.server_id = 11;
|
||||
ERROR HY000: The instance is active. Stop the instance first
|
||||
STOP INSTANCE mysqld3;
|
||||
SHOW INSTANCE STATUS mysqld3;
|
||||
instance_name state version_number version mysqld_compatible
|
||||
mysqld3 offline VERSION_NUMBER VERSION no
|
||||
UNSET mysqld2.server_id;
|
||||
UNSET mysqld2.server_id;
|
||||
SHOW INSTANCE OPTIONS mysqld2;
|
||||
option_name value
|
||||
instance_name option_value
|
||||
socket option_value
|
||||
pid-file option_value
|
||||
port option_value
|
||||
datadir option_value
|
||||
log option_value
|
||||
log-error option_value
|
||||
log-slow-queries option_value
|
||||
language option_value
|
||||
character-sets-dir option_value
|
||||
basedir option_value
|
||||
skip-stack-trace option_value
|
||||
skip-innodb option_value
|
||||
skip-bdb option_value
|
||||
skip-ndbcluster option_value
|
||||
nonguarded option_value
|
||||
log-output option_value
|
||||
SET mysqld2.server_id = 2;
|
||||
SET mysqld2.server_id = 2;
|
||||
SHOW INSTANCE OPTIONS mysqld2;
|
||||
option_name value
|
||||
instance_name option_value
|
||||
socket option_value
|
||||
pid-file option_value
|
||||
port option_value
|
||||
datadir option_value
|
||||
log option_value
|
||||
log-error option_value
|
||||
log-slow-queries option_value
|
||||
language option_value
|
||||
character-sets-dir option_value
|
||||
basedir option_value
|
||||
skip-stack-trace option_value
|
||||
skip-innodb option_value
|
||||
skip-bdb option_value
|
||||
skip-ndbcluster option_value
|
||||
nonguarded option_value
|
||||
log-output option_value
|
||||
server_id option_value
|
||||
UNSET mysqld2.server_id = 11;
|
||||
ERROR 42000: You have an error in your command syntax. Check the manual that corresponds to your MySQL Instance Manager version for the right syntax to use
|
||||
SET mysqld2.aaa, mysqld3.bbb, mysqld2.ccc = 0010, mysqld3.ddd = 0020;
|
||||
--------------------------------------------------------------------
|
||||
aaa
|
||||
--------------------------------------------------------------------
|
||||
bbb
|
||||
--------------------------------------------------------------------
|
||||
ccc=0010
|
||||
--------------------------------------------------------------------
|
||||
ddd=0020
|
||||
--------------------------------------------------------------------
|
||||
UNSET mysqld2.aaa, mysqld3.bbb, mysqld2.ccc, mysqld3.ddd;
|
||||
--------------------------------------------------------------------
|
||||
--------------------------------------------------------------------
|
||||
--------------------------------------------------------------------
|
||||
--------------------------------------------------------------------
|
||||
--------------------------------------------------------------------
|
||||
SET mysqld2.aaa, mysqld3.bbb, mysqld.ccc = 0010;
|
||||
ERROR HY000: Bad instance name. Check that the instance with such a name exists
|
||||
--------------------------------------------------------------------
|
||||
--------------------------------------------------------------------
|
||||
--------------------------------------------------------------------
|
||||
--------------------------------------------------------------------
|
||||
SET mysqld2.aaa, mysqld3.bbb, mysqld1.ccc = 0010;
|
||||
ERROR HY000: The instance is active. Stop the instance first
|
||||
--------------------------------------------------------------------
|
||||
--------------------------------------------------------------------
|
||||
--------------------------------------------------------------------
|
||||
--------------------------------------------------------------------
|
||||
UNSET mysqld2.server_id, mysqld3.server_id, mysqld.ccc;
|
||||
ERROR HY000: Bad instance name. Check that the instance with such a name exists
|
||||
--------------------------------------------------------------------
|
||||
server_id =1
|
||||
server_id=2
|
||||
--------------------------------------------------------------------
|
||||
UNSET mysqld2.server_id, mysqld3.server_id, mysqld1.ccc;
|
||||
ERROR HY000: The instance is active. Stop the instance first
|
||||
--------------------------------------------------------------------
|
||||
server_id =1
|
||||
server_id=2
|
||||
--------------------------------------------------------------------
|
||||
DROP INSTANCE mysqld3;
|
||||
SET mysqld2.server_id=222;
|
||||
SET mysqld2.server_id = 222;
|
||||
SET mysqld2.server_id = 222 ;
|
||||
SET mysqld2 . server_id = 222 ;
|
||||
SET mysqld2 . server_id = 222 , mysqld2 . aaa , mysqld2 . bbb ;
|
||||
--------------------------------------------------------------------
|
||||
server_id =1
|
||||
server_id=222
|
||||
--------------------------------------------------------------------
|
||||
aaa
|
||||
--------------------------------------------------------------------
|
||||
bbb
|
||||
--------------------------------------------------------------------
|
||||
UNSET mysqld2 . aaa , mysqld2 . bbb ;
|
||||
--------------------------------------------------------------------
|
||||
server_id =1
|
||||
server_id=222
|
||||
--------------------------------------------------------------------
|
||||
--------------------------------------------------------------------
|
||||
--------------------------------------------------------------------
|
||||
--------------------------------------------------------------------
|
||||
server_id =1
|
||||
server_id=222
|
||||
--------------------------------------------------------------------
|
||||
SHOW VARIABLES LIKE 'server_id';
|
||||
Variable_name Value
|
||||
server_id 1
|
||||
SHOW INSTANCES;
|
||||
instance_name state
|
||||
mysqld1 online
|
||||
mysqld2 offline
|
||||
FLUSH INSTANCES;
|
||||
ERROR HY000: At least one instance is active. Stop all instances first
|
||||
STOP INSTANCE mysqld1;
|
||||
SHOW INSTANCES;
|
||||
instance_name state
|
||||
mysqld1 offline
|
||||
mysqld2 offline
|
||||
FLUSH INSTANCES;
|
@ -1,20 +0,0 @@
|
||||
server_id =1
|
||||
server_id =2
|
||||
SHOW VARIABLES LIKE 'server_id';
|
||||
Variable_name Value
|
||||
server_id 1
|
||||
SET mysqld1.server_id = 11;
|
||||
server_id =11
|
||||
server_id =2
|
||||
SHOW VARIABLES LIKE 'server_id';
|
||||
Variable_name Value
|
||||
server_id 1
|
||||
SET mysqld2.server_id = 12;
|
||||
server_id =11
|
||||
server_id =12
|
||||
FLUSH INSTANCES;
|
||||
server_id =11
|
||||
server_id =12
|
||||
SHOW VARIABLES LIKE 'server_id';
|
||||
Variable_name Value
|
||||
server_id 1
|
@ -1,15 +0,0 @@
|
||||
server_id =1
|
||||
server_id =2
|
||||
SHOW VARIABLES LIKE 'server_id';
|
||||
Variable_name Value
|
||||
server_id 1
|
||||
UNSET mysqld1.server_id;
|
||||
server_id =2
|
||||
SHOW VARIABLES LIKE 'server_id';
|
||||
Variable_name Value
|
||||
server_id 1
|
||||
UNSET mysqld2.server_id;
|
||||
FLUSH INSTANCES;
|
||||
SHOW VARIABLES LIKE 'server_id';
|
||||
Variable_name Value
|
||||
server_id 1
|
@ -1,11 +1,10 @@
|
||||
SHOW INSTANCES;
|
||||
instance_name status
|
||||
instance_name state
|
||||
mysqld1 online
|
||||
mysqld2 offline
|
||||
SHOW INSTANCE OPTIONS mysqld1;
|
||||
option_name value
|
||||
instance_name VALUE
|
||||
mysqld-path VALUE
|
||||
socket VALUE
|
||||
pid-file VALUE
|
||||
port VALUE
|
||||
@ -25,8 +24,6 @@ log-output VALUE
|
||||
SHOW INSTANCE OPTIONS mysqld2;
|
||||
option_name value
|
||||
instance_name VALUE
|
||||
mysqld-path VALUE
|
||||
nonguarded VALUE
|
||||
socket VALUE
|
||||
pid-file VALUE
|
||||
port VALUE
|
||||
@ -42,6 +39,7 @@ skip-stack-trace VALUE
|
||||
skip-innodb VALUE
|
||||
skip-bdb VALUE
|
||||
skip-ndbcluster VALUE
|
||||
nonguarded VALUE
|
||||
log-output VALUE
|
||||
START INSTANCE mysqld2;
|
||||
STOP INSTANCE mysqld2;
|
||||
|
68
mysql-test/t/im_cmd_line.imtest
Normal file
68
mysql-test/t/im_cmd_line.imtest
Normal file
@ -0,0 +1,68 @@
|
||||
###########################################################################
|
||||
#
|
||||
# Tests for user-management command-line options.
|
||||
#
|
||||
###########################################################################
|
||||
|
||||
--source include/im_check_os.inc
|
||||
|
||||
###########################################################################
|
||||
|
||||
# List users so we are sure about starting conditions.
|
||||
|
||||
--echo --> Listing users...
|
||||
--exec $IM_EXE --defaults-file="$IM_DEFAULTS_PATH" --list-users 2>&1 >/dev/null
|
||||
--echo
|
||||
|
||||
# Add a new user.
|
||||
|
||||
--echo ==> Adding user 'testuser'...
|
||||
--exec $IM_EXE --defaults-file="$IM_DEFAULTS_PATH" --add-user --username=testuser --password=abc 2>&1 >/dev/null
|
||||
--echo
|
||||
|
||||
--echo --> IM password file:
|
||||
--exec cat $IM_PASSWORD_PATH
|
||||
--echo --> EOF
|
||||
--echo
|
||||
|
||||
--echo --> Printing out line for 'testuser'...
|
||||
--exec $IM_EXE --defaults-file="$IM_DEFAULTS_PATH" --passwd --username=testuser --password=abc | tail -1
|
||||
--echo
|
||||
|
||||
--echo --> Listing users...
|
||||
--exec $IM_EXE --defaults-file="$IM_DEFAULTS_PATH" --list-users 2>&1 >/dev/null
|
||||
--echo
|
||||
|
||||
# Edit user's attributes.
|
||||
|
||||
--echo ==> Changing the password of 'testuser'...
|
||||
--exec $IM_EXE --defaults-file="$IM_DEFAULTS_PATH" --edit-user --username=testuser --password=xyz 2>&1 >/dev/null
|
||||
--echo
|
||||
|
||||
--echo --> IM password file:
|
||||
--exec cat $IM_PASSWORD_PATH
|
||||
--echo --> EOF
|
||||
--echo
|
||||
|
||||
--echo --> Printing out line for 'testuser'...
|
||||
--exec $IM_EXE --defaults-file="$IM_DEFAULTS_PATH" --passwd --username=testuser --password=xyz | tail -1
|
||||
--echo
|
||||
|
||||
--echo --> Listing users...
|
||||
--exec $IM_EXE --defaults-file="$IM_DEFAULTS_PATH" --list-users 2>&1 >/dev/null
|
||||
--echo
|
||||
|
||||
# Drop user.
|
||||
|
||||
--echo ==> Dropping user 'testuser'...
|
||||
--exec $IM_EXE --defaults-file="$IM_DEFAULTS_PATH" --drop-user --username=testuser 2>&1 >/dev/null
|
||||
--echo
|
||||
|
||||
--echo --> IM password file:
|
||||
--exec cat $IM_PASSWORD_PATH
|
||||
--echo --> EOF
|
||||
--echo
|
||||
|
||||
--echo --> Listing users...
|
||||
--exec $IM_EXE --defaults-file="$IM_DEFAULTS_PATH" --list-users 2>&1 >/dev/null
|
||||
--echo
|
@ -1,2 +1,3 @@
|
||||
--run-as-service
|
||||
--log=$MYSQLTEST_VARDIR/log/im.log
|
||||
--monitoring-interval=1
|
||||
|
@ -10,6 +10,9 @@
|
||||
|
||||
###########################################################################
|
||||
|
||||
--sleep 3
|
||||
# should be longer than monitoring interval and enough to start instance.
|
||||
|
||||
SHOW INSTANCES;
|
||||
|
||||
--exec $MYSQL_TEST_DIR/t/kill_n_check.sh $IM_PATH_PID restarted
|
||||
|
1
mysql-test/t/im_instance_conf-im.opt
Normal file
1
mysql-test/t/im_instance_conf-im.opt
Normal file
@ -0,0 +1 @@
|
||||
--monitoring-interval=1
|
228
mysql-test/t/im_instance_conf.imtest
Normal file
228
mysql-test/t/im_instance_conf.imtest
Normal file
@ -0,0 +1,228 @@
|
||||
###########################################################################
|
||||
#
|
||||
# This test suite checks the following statements:
|
||||
# - CREATE INSTANCE <instance_name> [option1[=option1_value], ...];
|
||||
# - DROP INSTANCE <instance_name>;
|
||||
#
|
||||
# For CREATE INSTANCE we check that:
|
||||
# - CREATE INSTANCE succeeds for non-existing instance;
|
||||
# - CREATE INSTANCE fails for existing instance;
|
||||
# - CREATE INSTANCE can get additional options with and w/o values;
|
||||
# - CREATE INSTANCE parses options and handles grammar errors correctly.
|
||||
# Check that strings with spaces are handled correctly, unknown (for
|
||||
# mysqld) options should also be handled;
|
||||
# - CREATE INSTANCE updates both config file and internal configuration cache;
|
||||
# - CREATE INSTANCE allows to create instances only with properly formed
|
||||
# names (mysqld*);
|
||||
#
|
||||
# For DROP INSTANCE we check that:
|
||||
# - DROP INSTANCE succeeds for existing instance;
|
||||
# - DROP INSTANCE fails for non-existing instance;
|
||||
# - DROP INSTANCE fails for active instance.
|
||||
# - DROP INSTANCE updates both config file and internal configuration cache;
|
||||
#
|
||||
###########################################################################
|
||||
|
||||
--source include/im_check_os.inc
|
||||
|
||||
###########################################################################
|
||||
#
|
||||
# Check starting conditions.
|
||||
#
|
||||
###########################################################################
|
||||
|
||||
# Check that the configuration file contains only instances that we expect.
|
||||
|
||||
--echo --------------------------------------------------------------------
|
||||
--exec grep server_id $MYSQLTEST_VARDIR/im.cnf;
|
||||
--echo --------------------------------------------------------------------
|
||||
|
||||
# Check that mysqld1 is reported as running.
|
||||
|
||||
--sleep 3
|
||||
# should be longer than monitoring interval and enough to start instance.
|
||||
|
||||
SHOW INSTANCES;
|
||||
|
||||
# Check that the expected mysqld instance is actually run (check that we can
|
||||
# connect and execute something).
|
||||
|
||||
--echo
|
||||
--echo ---> connection: mysql1_con
|
||||
--connect (mysql1_con,localhost,root,,mysql,$IM_MYSQLD1_PORT,$IM_MYSQLD1_SOCK)
|
||||
--connection mysql1_con
|
||||
|
||||
SHOW VARIABLES LIKE 'server_id';
|
||||
|
||||
--disconnect mysql1_con
|
||||
|
||||
--echo
|
||||
--echo ---> connection: default
|
||||
--connection default
|
||||
|
||||
###########################################################################
|
||||
#
|
||||
# CREATE INSTANCE tests.
|
||||
#
|
||||
###########################################################################
|
||||
|
||||
# Check that CREATE INSTANCE succeeds for non-existing instance and also check
|
||||
# that both config file and internal configuration cache have been updated.
|
||||
|
||||
CREATE INSTANCE mysqld3;
|
||||
|
||||
SHOW INSTANCES;
|
||||
|
||||
--echo --------------------------------------------------------------------
|
||||
--exec grep server_id $MYSQLTEST_VARDIR/im.cnf ;
|
||||
--echo --------------------------------------------------------------------
|
||||
|
||||
# Check that CREATE INSTANCE fails for existing instance. Let's all three
|
||||
# existing instances (running one, stopped one and just created one). Just in
|
||||
# case...
|
||||
|
||||
--error 3012 # ER_CREATE_EXISTING_INSTANCE
|
||||
CREATE INSTANCE mysqld1;
|
||||
|
||||
--error 3012 # ER_CREATE_EXISTING_INSTANCE
|
||||
CREATE INSTANCE mysqld2;
|
||||
|
||||
--error 3012 # ER_CREATE_EXISTING_INSTANCE
|
||||
CREATE INSTANCE mysqld3;
|
||||
|
||||
# Check that CREATE INSTANCE can get additional options with and w/o values.
|
||||
# Ensure that config file is updated properly.
|
||||
|
||||
# - without values;
|
||||
|
||||
--echo --------------------------------------------------------------------
|
||||
--exec grep nonguarded $MYSQLTEST_VARDIR/im.cnf;
|
||||
--echo --------------------------------------------------------------------
|
||||
|
||||
CREATE INSTANCE mysqld4 nonguarded;
|
||||
|
||||
SHOW INSTANCES;
|
||||
|
||||
--echo --------------------------------------------------------------------
|
||||
--exec grep nonguarded $MYSQLTEST_VARDIR/im.cnf;
|
||||
--echo --------------------------------------------------------------------
|
||||
|
||||
# - with value;
|
||||
|
||||
--echo --------------------------------------------------------------------
|
||||
--exec grep test-A $MYSQLTEST_VARDIR/im.cnf || true;
|
||||
--echo --------------------------------------------------------------------
|
||||
--exec grep test-B $MYSQLTEST_VARDIR/im.cnf || true;
|
||||
--echo --------------------------------------------------------------------
|
||||
|
||||
CREATE INSTANCE mysqld5 test-A = 000, test-B = test;
|
||||
|
||||
SHOW INSTANCES;
|
||||
|
||||
--echo --------------------------------------------------------------------
|
||||
--exec grep test-A $MYSQLTEST_VARDIR/im.cnf;
|
||||
--echo --------------------------------------------------------------------
|
||||
--exec grep test-B $MYSQLTEST_VARDIR/im.cnf;
|
||||
--echo --------------------------------------------------------------------
|
||||
|
||||
# Check that CREATE INSTANCE parses options and handles grammar errors
|
||||
# correctly. Check that strings with spaces are handled correctly,
|
||||
# unknown (for mysqld) options should also be handled.
|
||||
|
||||
# - check handling of extra spaces;
|
||||
|
||||
--echo --------------------------------------------------------------------
|
||||
--exec grep test-C $MYSQLTEST_VARDIR/im.cnf || true;
|
||||
--echo --------------------------------------------------------------------
|
||||
|
||||
CREATE INSTANCE mysqld6 test-C1 = 10 , test-C2 = 02 ;
|
||||
|
||||
SHOW INSTANCES;
|
||||
|
||||
--echo --------------------------------------------------------------------
|
||||
--exec grep test-C1 $MYSQLTEST_VARDIR/im.cnf;
|
||||
--echo --------------------------------------------------------------------
|
||||
--exec grep test-C2 $MYSQLTEST_VARDIR/im.cnf;
|
||||
--echo --------------------------------------------------------------------
|
||||
|
||||
# - check handling of grammar error;
|
||||
|
||||
--echo --------------------------------------------------------------------
|
||||
--exec grep test-D $MYSQLTEST_VARDIR/im.cnf || true;
|
||||
--echo --------------------------------------------------------------------
|
||||
--exec grep test-E $MYSQLTEST_VARDIR/im.cnf || true;
|
||||
--echo --------------------------------------------------------------------
|
||||
|
||||
--error ER_SYNTAX_ERROR
|
||||
CREATE INSTANCE mysqld7 test-D = test-D-value ;
|
||||
SHOW INSTANCES;
|
||||
|
||||
--error ER_SYNTAX_ERROR
|
||||
CREATE INSTANCE mysqld8 test-E 0 ;
|
||||
SHOW INSTANCES;
|
||||
|
||||
--error ER_SYNTAX_ERROR
|
||||
CREATE INSTANCE mysqld8 test-F = ;
|
||||
SHOW INSTANCES;
|
||||
|
||||
--echo --------------------------------------------------------------------
|
||||
--exec grep test-D $MYSQLTEST_VARDIR/im.cnf || true;
|
||||
--echo --------------------------------------------------------------------
|
||||
--exec grep test-E $MYSQLTEST_VARDIR/im.cnf || true;
|
||||
--echo --------------------------------------------------------------------
|
||||
|
||||
# - check parsing of string option values
|
||||
|
||||
--echo --------------------------------------------------------------------
|
||||
--exec grep test-1 $MYSQLTEST_VARDIR/im.cnf || true;
|
||||
--echo --------------------------------------------------------------------
|
||||
--exec grep test-2 $MYSQLTEST_VARDIR/im.cnf || true;
|
||||
--echo --------------------------------------------------------------------
|
||||
--exec grep test-3 $MYSQLTEST_VARDIR/im.cnf || true;
|
||||
--echo --------------------------------------------------------------------
|
||||
--exec grep test-4 $MYSQLTEST_VARDIR/im.cnf || true;
|
||||
--echo --------------------------------------------------------------------
|
||||
|
||||
CREATE INSTANCE mysqld9 test-1=" hello world ", test-2=' ';
|
||||
SHOW INSTANCES;
|
||||
|
||||
CREATE INSTANCE mysqld9a test-3='\b\babc\sdef';
|
||||
# test-3='abc def'
|
||||
SHOW INSTANCES;
|
||||
|
||||
CREATE INSTANCE mysqld9b test-4='abc\tdef', test-5='abc\ndef';
|
||||
SHOW INSTANCES;
|
||||
|
||||
CREATE INSTANCE mysqld9c test-6="abc\rdef", test-7="abc\\def";
|
||||
# test-6=abc
|
||||
SHOW INSTANCES;
|
||||
|
||||
--error ER_SYNTAX_ERROR
|
||||
CREATE INSTANCE mysqld10 test-bad=' \ ';
|
||||
SHOW INSTANCES;
|
||||
|
||||
--echo --------------------------------------------------------------------
|
||||
--exec grep test-1 $MYSQLTEST_VARDIR/im.cnf;
|
||||
--echo --------------------------------------------------------------------
|
||||
--exec grep test-2 $MYSQLTEST_VARDIR/im.cnf;
|
||||
--echo --------------------------------------------------------------------
|
||||
--exec grep test-3 $MYSQLTEST_VARDIR/im.cnf;
|
||||
--echo --------------------------------------------------------------------
|
||||
--exec grep test-4 $MYSQLTEST_VARDIR/im.cnf;
|
||||
--echo --------------------------------------------------------------------
|
||||
--exec grep test-5 $MYSQLTEST_VARDIR/im.cnf;
|
||||
--echo --------------------------------------------------------------------
|
||||
--exec grep test-6 $MYSQLTEST_VARDIR/im.cnf;
|
||||
--echo --------------------------------------------------------------------
|
||||
--exec grep test-7 $MYSQLTEST_VARDIR/im.cnf;
|
||||
--echo --------------------------------------------------------------------
|
||||
--exec grep test-bad $MYSQLTEST_VARDIR/im.cnf || true;
|
||||
--echo --------------------------------------------------------------------
|
||||
|
||||
|
||||
# Check that CREATE INSTANCE allows to create instances only with properly
|
||||
# formed names (mysqld*).
|
||||
|
||||
--error 3014 # ER_MALFORMED_INSTANCE_NAME
|
||||
CREATE INSTANCE qqq1;
|
||||
|
1
mysql-test/t/im_life_cycle-im.opt
Normal file
1
mysql-test/t/im_life_cycle-im.opt
Normal file
@ -0,0 +1 @@
|
||||
--monitoring-interval=1
|
@ -17,11 +17,15 @@
|
||||
#
|
||||
###########################################################################
|
||||
|
||||
--echo
|
||||
--echo --------------------------------------------------------------------
|
||||
--echo -- 1.1.1.
|
||||
--echo --------------------------------------------------------------------
|
||||
|
||||
--sleep 3
|
||||
# should be longer than monitoring interval and enough to start instance.
|
||||
|
||||
SHOW INSTANCES;
|
||||
--replace_column 3 VERSION_NUMBER 4 VERSION
|
||||
SHOW INSTANCE STATUS mysqld1;
|
||||
--replace_column 3 VERSION_NUMBER 4 VERSION
|
||||
SHOW INSTANCE STATUS mysqld2;
|
||||
|
||||
###########################################################################
|
||||
#
|
||||
@ -33,20 +37,22 @@ SHOW INSTANCE STATUS mysqld2;
|
||||
#
|
||||
###########################################################################
|
||||
|
||||
--echo
|
||||
--echo --------------------------------------------------------------------
|
||||
--echo -- 1.1.2.
|
||||
--echo --------------------------------------------------------------------
|
||||
|
||||
START INSTANCE mysqld2;
|
||||
# FIXME
|
||||
# FIXME: START INSTANCE should be synchronous.
|
||||
--sleep 3
|
||||
# should be longer than monitoring interval and enough to start instance.
|
||||
|
||||
SHOW INSTANCES;
|
||||
--replace_column 3 VERSION_NUMBER 4 VERSION
|
||||
SHOW INSTANCE STATUS mysqld1;
|
||||
--replace_column 3 VERSION_NUMBER 4 VERSION
|
||||
SHOW INSTANCE STATUS mysqld2;
|
||||
|
||||
--connect (mysql_con,localhost,root,,mysql,$IM_MYSQLD1_PORT,$IM_MYSQLD1_SOCK)
|
||||
--connect (mysql_con,localhost,root,,mysql,$IM_MYSQLD2_PORT,$IM_MYSQLD2_SOCK)
|
||||
--connection mysql_con
|
||||
|
||||
--replace_result $IM_MYSQLD1_PORT IM_MYSQLD1_PORT
|
||||
--replace_result $IM_MYSQLD2_PORT IM_MYSQLD2_PORT
|
||||
SHOW VARIABLES LIKE 'port';
|
||||
|
||||
--connection default
|
||||
@ -61,9 +67,15 @@ SHOW VARIABLES LIKE 'port';
|
||||
#
|
||||
###########################################################################
|
||||
|
||||
--echo
|
||||
--echo --------------------------------------------------------------------
|
||||
--echo -- 1.1.3.
|
||||
--echo --------------------------------------------------------------------
|
||||
|
||||
STOP INSTANCE mysqld2;
|
||||
# FIXME
|
||||
# FIXME: STOP INSTANCE should be synchronous.
|
||||
--sleep 3
|
||||
# should be longer than monitoring interval and enough to stop instance.
|
||||
|
||||
SHOW INSTANCES;
|
||||
--replace_column 3 VERSION_NUMBER 4 VERSION
|
||||
@ -81,16 +93,17 @@ SHOW INSTANCE STATUS mysqld2;
|
||||
#
|
||||
###########################################################################
|
||||
|
||||
--error 3000
|
||||
--echo
|
||||
--echo --------------------------------------------------------------------
|
||||
--echo -- 1.1.4.
|
||||
--echo --------------------------------------------------------------------
|
||||
|
||||
--error 3000 # ER_BAD_INSTANCE_NAME
|
||||
START INSTANCE mysqld3;
|
||||
|
||||
--error 3002
|
||||
--error 3002 # ER_INSTANCE_ALREADY_STARTED
|
||||
START INSTANCE mysqld1;
|
||||
|
||||
# FIXME TODO
|
||||
# BUG#12813: START/STOP INSTANCE commands accept a list as argument
|
||||
# START INSTANCE mysqld1, mysqld2;
|
||||
|
||||
###########################################################################
|
||||
#
|
||||
# 1.1.5. Check that Instance Manager reports correct errors for 'STOP INSTANCE'
|
||||
@ -101,39 +114,54 @@ START INSTANCE mysqld1;
|
||||
#
|
||||
###########################################################################
|
||||
|
||||
--error 3000
|
||||
--echo
|
||||
--echo --------------------------------------------------------------------
|
||||
--echo -- 1.1.5.
|
||||
--echo --------------------------------------------------------------------
|
||||
|
||||
--error 3000 # ER_BAD_INSTANCE_NAME
|
||||
STOP INSTANCE mysqld3;
|
||||
|
||||
# TODO: IM should be fixed.
|
||||
# BUG#12673: Instance Manager allows to stop the instance many times
|
||||
# --error 3002
|
||||
# --error 3002 # ER_INSTANCE_ALREADY_STARTED
|
||||
# STOP INSTANCE mysqld2;
|
||||
|
||||
# FIXME TODO
|
||||
# BUG#12813: START/STOP INSTANCE commands accept a list as argument
|
||||
# STOP INSTANCE mysqld1, mysqld2;
|
||||
|
||||
###########################################################################
|
||||
#
|
||||
# 1.1.6. Check that Instance Manager is able to restart guarded instances.
|
||||
#
|
||||
###########################################################################
|
||||
|
||||
--echo
|
||||
--echo --------------------------------------------------------------------
|
||||
--echo -- 1.1.6.
|
||||
--echo --------------------------------------------------------------------
|
||||
|
||||
SHOW INSTANCES;
|
||||
|
||||
--exec $MYSQL_TEST_DIR/t/kill_n_check.sh $IM_MYSQLD1_PATH_PID restarted
|
||||
|
||||
--sleep 3
|
||||
# should be longer than monitoring interval and enough to start instance.
|
||||
|
||||
###########################################################################
|
||||
#
|
||||
# 1.1.7. Check that Instance Manager does not restart non-guarded instance.
|
||||
#
|
||||
###########################################################################
|
||||
|
||||
--echo
|
||||
--echo --------------------------------------------------------------------
|
||||
--echo -- 1.1.7.
|
||||
--echo --------------------------------------------------------------------
|
||||
|
||||
SHOW INSTANCES;
|
||||
|
||||
START INSTANCE mysqld2;
|
||||
# FIXME
|
||||
# FIXME: START INSTANCE should be synchronous.
|
||||
--sleep 3
|
||||
# should be longer than monitoring interval and enough to start instance.
|
||||
|
||||
SHOW INSTANCES;
|
||||
|
||||
@ -147,7 +175,13 @@ SHOW INSTANCES;
|
||||
# incomplete SHOW INSTANCE STATUS command.
|
||||
#
|
||||
###########################################################################
|
||||
--error 1149
|
||||
|
||||
--echo
|
||||
--echo --------------------------------------------------------------------
|
||||
--echo -- 1.1.8.
|
||||
--echo --------------------------------------------------------------------
|
||||
|
||||
--error ER_SYNTAX_ERROR
|
||||
SHOW INSTANCE STATUS;
|
||||
|
||||
#
|
||||
@ -159,8 +193,13 @@ SHOW INSTANCE STATUS;
|
||||
# a list as argument.
|
||||
#
|
||||
|
||||
--error 1149
|
||||
--echo
|
||||
--echo --------------------------------------------------------------------
|
||||
--echo -- BUG#12813
|
||||
--echo --------------------------------------------------------------------
|
||||
|
||||
--error ER_SYNTAX_ERROR
|
||||
START INSTANCE mysqld1,mysqld2,mysqld3;
|
||||
|
||||
--error 1149
|
||||
--error ER_SYNTAX_ERROR
|
||||
STOP INSTANCE mysqld1,mysqld2,mysqld3;
|
||||
|
268
mysql-test/t/im_options.imtest
Normal file
268
mysql-test/t/im_options.imtest
Normal file
@ -0,0 +1,268 @@
|
||||
###########################################################################
|
||||
#
|
||||
# This test suite checks the following statements:
|
||||
# - SET <instance id>.<option name> = <option value>;
|
||||
# - UNSET <instance id>.<option name> = <option value>;
|
||||
# - FLUSH INSTANCES;
|
||||
#
|
||||
# For SET/UNSET we check that:
|
||||
# - SET ignores spaces correctly;
|
||||
# - UNSET does not allow option-value part (= <option value>);
|
||||
# - SET/UNSET can be applied several times w/o error;
|
||||
# - SET/UNSET is allowed only for stopped instances;
|
||||
# - SET/UNSET updates both the configuration cache in IM and
|
||||
# the configuration file;
|
||||
#
|
||||
# For FLUSH INSTANCES we check that:
|
||||
# - FLUSH INSTANCES is allowed only when all instances are stopped;
|
||||
#
|
||||
# According to the IM implementation details, we should play at least with the
|
||||
# following options:
|
||||
# - server_id
|
||||
# - port
|
||||
# - nonguarded
|
||||
|
||||
# Let's test SET statement on the option 'server_id'. It's expected that
|
||||
# originally the instances have the following server ids and states:
|
||||
# - mysqld1: server_id: 1; running (online)
|
||||
# - mysqld2: server_id: 2; stopped (offline)
|
||||
#
|
||||
###########################################################################
|
||||
|
||||
--source include/im_check_os.inc
|
||||
|
||||
###########################################################################
|
||||
#
|
||||
# Check starting conditions.
|
||||
#
|
||||
###########################################################################
|
||||
|
||||
# - check the configuration file;
|
||||
|
||||
--echo --------------------------------------------------------------------
|
||||
--exec grep server_id $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;
|
||||
|
||||
###########################################################################
|
||||
#
|
||||
# Check that SET/UNSET is allowed only for stopped instances.
|
||||
#
|
||||
###########################################################################
|
||||
|
||||
# - check that SET/UNSET is denied for running instances;
|
||||
|
||||
--error 3015 # ER_INSTANCE_IS_ACTIVE
|
||||
UNSET mysqld1.server_id;
|
||||
|
||||
--error 3015 # ER_INSTANCE_IS_ACTIVE
|
||||
SET mysqld1.server_id = 11;
|
||||
|
||||
# - check that SET/UNSET is denied for active instances:
|
||||
# - create dummy misconfigured instance;
|
||||
# - start it;
|
||||
# - try to set/unset options;
|
||||
|
||||
CREATE INSTANCE mysqld3 datadir = '/';
|
||||
START INSTANCE mysqld3;
|
||||
|
||||
# FIXME: START INSTANCE should be synchronous.
|
||||
--sleep 3
|
||||
# should be longer than monitoring interval and enough to start instance.
|
||||
|
||||
# NOTE: We can not analyze state of the instance here -- it can be Failed or
|
||||
# Starting because Instance Manager is trying to start the misconfigured
|
||||
# instance several times.
|
||||
|
||||
--error 3015 # ER_INSTANCE_IS_ACTIVE
|
||||
UNSET mysqld3.server_id;
|
||||
|
||||
--error 3015 # ER_INSTANCE_IS_ACTIVE
|
||||
SET mysqld3.server_id = 11;
|
||||
|
||||
STOP INSTANCE mysqld3;
|
||||
|
||||
# FIXME: STOP INSTANCE should be synchronous.
|
||||
--sleep 3
|
||||
# should be longer than monitoring interval and enough to stop instance.
|
||||
|
||||
--replace_column 3 VERSION_NUMBER 4 VERSION
|
||||
SHOW INSTANCE STATUS mysqld3;
|
||||
|
||||
# - check that SET/UNSET succeed for stopped instances;
|
||||
# - check that SET/UNSET can be applied multiple times;
|
||||
|
||||
UNSET mysqld2.server_id;
|
||||
UNSET mysqld2.server_id;
|
||||
|
||||
--replace_column 2 option_value
|
||||
SHOW INSTANCE OPTIONS mysqld2;
|
||||
|
||||
SET mysqld2.server_id = 2;
|
||||
SET mysqld2.server_id = 2;
|
||||
|
||||
--replace_column 2 option_value
|
||||
SHOW INSTANCE OPTIONS mysqld2;
|
||||
|
||||
# - check that UNSET does not allow option-value part (= <option value>);
|
||||
|
||||
--error ER_SYNTAX_ERROR
|
||||
UNSET mysqld2.server_id = 11;
|
||||
|
||||
# - check that SET/UNSET working properly with multiple options;
|
||||
|
||||
SET mysqld2.aaa, mysqld3.bbb, mysqld2.ccc = 0010, mysqld3.ddd = 0020;
|
||||
|
||||
--echo --------------------------------------------------------------------
|
||||
--exec grep aaa $MYSQLTEST_VARDIR/im.cnf ;
|
||||
--echo --------------------------------------------------------------------
|
||||
--exec grep bbb $MYSQLTEST_VARDIR/im.cnf ;
|
||||
--echo --------------------------------------------------------------------
|
||||
--exec grep ccc $MYSQLTEST_VARDIR/im.cnf ;
|
||||
--echo --------------------------------------------------------------------
|
||||
--exec grep ddd $MYSQLTEST_VARDIR/im.cnf ;
|
||||
--echo --------------------------------------------------------------------
|
||||
|
||||
UNSET mysqld2.aaa, mysqld3.bbb, mysqld2.ccc, mysqld3.ddd;
|
||||
|
||||
--echo --------------------------------------------------------------------
|
||||
--exec grep aaa $MYSQLTEST_VARDIR/im.cnf || true;
|
||||
--echo --------------------------------------------------------------------
|
||||
--exec grep bbb $MYSQLTEST_VARDIR/im.cnf || true;
|
||||
--echo --------------------------------------------------------------------
|
||||
--exec grep ccc $MYSQLTEST_VARDIR/im.cnf || true;
|
||||
--echo --------------------------------------------------------------------
|
||||
--exec grep ddd $MYSQLTEST_VARDIR/im.cnf || true;
|
||||
--echo --------------------------------------------------------------------
|
||||
|
||||
# - check that if some instance name is invalid or the active is active,
|
||||
# whole SET-statement will not be executed;
|
||||
|
||||
--error 3000 # ER_BAD_INSTANCE_NAME
|
||||
SET mysqld2.aaa, mysqld3.bbb, mysqld.ccc = 0010;
|
||||
|
||||
--echo --------------------------------------------------------------------
|
||||
--exec grep aaa $MYSQLTEST_VARDIR/im.cnf || true;
|
||||
--echo --------------------------------------------------------------------
|
||||
--exec grep bbb $MYSQLTEST_VARDIR/im.cnf || true;
|
||||
--echo --------------------------------------------------------------------
|
||||
--exec grep ccc $MYSQLTEST_VARDIR/im.cnf || true;
|
||||
--echo --------------------------------------------------------------------
|
||||
|
||||
--error 3015 # ER_INSTANCE_IS_ACTIVE
|
||||
SET mysqld2.aaa, mysqld3.bbb, mysqld1.ccc = 0010;
|
||||
|
||||
--echo --------------------------------------------------------------------
|
||||
--exec grep aaa $MYSQLTEST_VARDIR/im.cnf || true;
|
||||
--echo --------------------------------------------------------------------
|
||||
--exec grep bbb $MYSQLTEST_VARDIR/im.cnf || true;
|
||||
--echo --------------------------------------------------------------------
|
||||
--exec grep ccc $MYSQLTEST_VARDIR/im.cnf || true;
|
||||
--echo --------------------------------------------------------------------
|
||||
|
||||
# - check that if some instance name is invalid or the active is active,
|
||||
# whole UNSET-statement will not be executed;
|
||||
|
||||
--error 3000 # ER_BAD_INSTANCE_NAME
|
||||
UNSET mysqld2.server_id, mysqld3.server_id, mysqld.ccc;
|
||||
|
||||
--echo --------------------------------------------------------------------
|
||||
--exec grep server_id $MYSQLTEST_VARDIR/im.cnf;
|
||||
--echo --------------------------------------------------------------------
|
||||
|
||||
--error 3015 # ER_INSTANCE_IS_ACTIVE
|
||||
UNSET mysqld2.server_id, mysqld3.server_id, mysqld1.ccc;
|
||||
|
||||
--echo --------------------------------------------------------------------
|
||||
--exec grep server_id $MYSQLTEST_VARDIR/im.cnf;
|
||||
--echo --------------------------------------------------------------------
|
||||
|
||||
DROP INSTANCE mysqld3;
|
||||
|
||||
# - check that spaces are handled correctly;
|
||||
|
||||
SET mysqld2.server_id=222;
|
||||
SET mysqld2.server_id = 222;
|
||||
SET mysqld2.server_id = 222 ;
|
||||
SET mysqld2 . server_id = 222 ;
|
||||
SET mysqld2 . server_id = 222 , mysqld2 . aaa , mysqld2 . bbb ;
|
||||
|
||||
--echo --------------------------------------------------------------------
|
||||
--exec grep server_id $MYSQLTEST_VARDIR/im.cnf ;
|
||||
--echo --------------------------------------------------------------------
|
||||
--exec grep aaa $MYSQLTEST_VARDIR/im.cnf ;
|
||||
--echo --------------------------------------------------------------------
|
||||
--exec grep bbb $MYSQLTEST_VARDIR/im.cnf ;
|
||||
--echo --------------------------------------------------------------------
|
||||
|
||||
UNSET mysqld2 . aaa , mysqld2 . bbb ;
|
||||
|
||||
--echo --------------------------------------------------------------------
|
||||
--exec grep server_id $MYSQLTEST_VARDIR/im.cnf ;
|
||||
--echo --------------------------------------------------------------------
|
||||
--exec grep aaa $MYSQLTEST_VARDIR/im.cnf || true;
|
||||
--echo --------------------------------------------------------------------
|
||||
--exec grep bbb $MYSQLTEST_VARDIR/im.cnf || true;
|
||||
--echo --------------------------------------------------------------------
|
||||
|
||||
###########################################################################
|
||||
#
|
||||
# Check that SET/UNSET updates both the configuration cache in IM and
|
||||
# the configuration file.
|
||||
#
|
||||
###########################################################################
|
||||
|
||||
# - check that the configuration file has been updated (i.e. contains
|
||||
# server_id=SERVER_ID for mysqld2);
|
||||
|
||||
--echo --------------------------------------------------------------------
|
||||
--exec grep server_id $MYSQLTEST_VARDIR/im.cnf ;
|
||||
--echo --------------------------------------------------------------------
|
||||
|
||||
# - (for mysqld1) check that the running instance has not been affected:
|
||||
# connect to the instance and check that 'SHOW VARIABLES LIKE 'server_id''
|
||||
# returns zero;
|
||||
|
||||
--connection mysql1_con
|
||||
|
||||
SHOW VARIABLES LIKE 'server_id';
|
||||
|
||||
--connection default
|
||||
|
||||
# - check that internal cache of Instance Manager has been affected;
|
||||
# TODO: we should check only server_id option here.
|
||||
|
||||
# SHOW INSTANCE OPTIONS mysqld2;
|
||||
|
||||
###########################################################################
|
||||
#
|
||||
# Check that FLUSH INSTANCES is allowed only when all instances are stopped.
|
||||
#
|
||||
###########################################################################
|
||||
|
||||
SHOW INSTANCES;
|
||||
|
||||
--error 3016 # ER_THERE_IS_ACTIVE_INSTACE
|
||||
FLUSH INSTANCES;
|
||||
|
||||
STOP INSTANCE mysqld1;
|
||||
# FIXME: STOP INSTANCE should be synchronous.
|
||||
--sleep 3
|
||||
# should be longer than monitoring interval and enough to stop instance.
|
||||
|
||||
SHOW INSTANCES;
|
||||
|
||||
FLUSH INSTANCES;
|
@ -1,142 +0,0 @@
|
||||
###########################################################################
|
||||
#
|
||||
# This file contains test for (3) test suite.
|
||||
#
|
||||
# Consult WL#2789 for more information.
|
||||
#
|
||||
###########################################################################
|
||||
|
||||
#
|
||||
# Check the options-management commands:
|
||||
# - SET;
|
||||
# - FLUSH INSTANCES;
|
||||
#
|
||||
# Let's test the commands on the option 'server_id'. It's expected that
|
||||
# originally the instances have the following server ids:
|
||||
# - mysqld1: 1
|
||||
# - mysqld2: 2
|
||||
#
|
||||
# 1. SET <instance_id>.server_id= SERVER_ID); where SERVER_ID is 11 or 12.
|
||||
# 1.1. check that the configuration file has been updated (i.e. contains
|
||||
# server_id=SERVER_ID for the instance);
|
||||
# 1.2. (for mysqld1) check that the running instance has not been affected:
|
||||
# connect to the instance and check that 'SHOW VARIABLES LIKE 'server_id''
|
||||
# returns zero;
|
||||
# 1.3. check that internal cache of Instance Manager has not been affected
|
||||
# (i.e. SHOW INSTANCE OPTIONS <instance> does not contain updated value).
|
||||
#
|
||||
# 2. FLUSH INSTANCES;
|
||||
# 2.1. check that the configuration file has not been updated;
|
||||
# 2.2. (for mysqld1) check that the running instance has not been affected:
|
||||
# connect to the instance and check that 'SHOW VARIABLES LIKE 'server_id''
|
||||
# returns zero value;
|
||||
# 2.3. check that internal cache of Instance Manager has been updated (i.e.
|
||||
# SHOW INSTANCE OPTIONS <instance> contains 'server_id=SERVER_ID' line).
|
||||
#
|
||||
# 3. Restore options.
|
||||
#
|
||||
|
||||
###########################################################################
|
||||
|
||||
--source include/im_check_os.inc
|
||||
|
||||
###########################################################################
|
||||
#
|
||||
# 0. Check starting conditions.
|
||||
#
|
||||
###########################################################################
|
||||
|
||||
# - check the configuration file;
|
||||
|
||||
--exec grep server_id $MYSQLTEST_VARDIR/im.cnf ;
|
||||
|
||||
# - 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.
|
||||
# TODO: we should check only server_id option here.
|
||||
|
||||
# SHOW INSTANCE OPTIONS mysqld1;
|
||||
# SHOW INSTANCE OPTIONS mysqld2;
|
||||
|
||||
###########################################################################
|
||||
#
|
||||
# 1. SET <instance_id>.server_id= SERVER_ID); where SERVER_ID is 11 or 12.
|
||||
#
|
||||
###########################################################################
|
||||
|
||||
# * mysqld1
|
||||
|
||||
SET mysqld1.server_id = 11;
|
||||
|
||||
# - check that the configuration file has been updated (i.e. contains
|
||||
# server_id=SERVER_ID for the instance);
|
||||
|
||||
--exec grep server_id $MYSQLTEST_VARDIR/im.cnf ;
|
||||
|
||||
# - (for mysqld1) check that the running instance has not been affected:
|
||||
# connect to the instance and check that 'SHOW VARIABLES LIKE 'server_id''
|
||||
# returns zero;
|
||||
|
||||
--connection mysql1_con
|
||||
|
||||
SHOW VARIABLES LIKE 'server_id';
|
||||
|
||||
--connection default
|
||||
|
||||
# - check that internal cache of Instance Manager has not been affected
|
||||
# (i.e. SHOW INSTANCE OPTIONS <instance> does not contain updated value).
|
||||
# TODO: we should check only server_id option here.
|
||||
|
||||
# SHOW INSTANCE OPTIONS mysqld1;
|
||||
|
||||
# * mysqld2
|
||||
|
||||
SET mysqld2.server_id = 12;
|
||||
|
||||
# - check that the configuration file has been updated (i.e. contains
|
||||
# server_id=SERVER_ID for the instance);
|
||||
|
||||
--exec grep server_id $MYSQLTEST_VARDIR/im.cnf ;
|
||||
|
||||
# - check that internal cache of Instance Manager has not been affected
|
||||
# (i.e. SHOW INSTANCE OPTIONS <instance> does not contain updated value).
|
||||
# TODO: we should check only server_id option here.
|
||||
|
||||
# SHOW INSTANCE OPTIONS mysqld2;
|
||||
|
||||
###########################################################################
|
||||
#
|
||||
# 2. FLUSH INSTANCES;
|
||||
#
|
||||
###########################################################################
|
||||
|
||||
FLUSH INSTANCES;
|
||||
|
||||
# - check that the configuration file has not been updated;
|
||||
|
||||
--exec grep server_id $MYSQLTEST_VARDIR/im.cnf ;
|
||||
|
||||
# - (for mysqld1) check that the running instance has not been affected:
|
||||
# connect to the instance and check that 'SHOW VARIABLES LIKE 'server_id''
|
||||
# returns zero value;
|
||||
|
||||
--connection mysql1_con
|
||||
|
||||
SHOW VARIABLES LIKE 'server_id';
|
||||
|
||||
--connection default
|
||||
|
||||
# - check that internal cache of Instance Manager has been updated (i.e.
|
||||
# SHOW INSTANCE OPTIONS <instance> contains 'server_id=' line).
|
||||
# TODO: we should check only server_id option here.
|
||||
|
||||
# SHOW INSTANCE OPTIONS mysqld1;
|
||||
# SHOW INSTANCE OPTIONS mysqld2;
|
@ -1,150 +0,0 @@
|
||||
###########################################################################
|
||||
#
|
||||
# This file contains test for (3) test suite.
|
||||
#
|
||||
# Consult WL#2789 for more information.
|
||||
#
|
||||
###########################################################################
|
||||
|
||||
#
|
||||
# Check the options-management commands:
|
||||
# - UNSET;
|
||||
# - FLUSH INSTANCES;
|
||||
#
|
||||
# Let's test the commands on the option 'server_id'. It's expected that
|
||||
# originally the instances have the following server ids:
|
||||
# - mysqld1: 1
|
||||
# - mysqld2: 2
|
||||
#
|
||||
# The test case:
|
||||
#
|
||||
# 1. UNSET <instance_id>.server_id;
|
||||
#
|
||||
# Do the step for both instances.
|
||||
#
|
||||
# 1.1. check that the configuration file has been updated (i.e. does not
|
||||
# contain 'server_id=' line for the instance);
|
||||
# 1.2. (for mysqld1) check that the running instance has not been affected:
|
||||
# connect to the instance and check that 'SHOW VARIABLES LIKE 'server_id''
|
||||
# returns non-zero value;
|
||||
# 1.3. check that internal cache of Instance Manager is not affected (i.e.
|
||||
# SHOW INSTANCE OPTIONS <instance> contains non-zero value for server_id);
|
||||
#
|
||||
# 2. FLUSH INSTANCES;
|
||||
#
|
||||
# Do the step for both instances.
|
||||
#
|
||||
# 2.1. check that the configuration file has not been updated (i.e. does not
|
||||
# contain 'server_id=' for the instance);
|
||||
# 2.2. (for mysqld1) check that the running instance has not been affected:
|
||||
# connect to the instance and check that 'SHOW VARIABLES LIKE 'server_id''
|
||||
# returns non-zero value;
|
||||
# 2.3. check that internal cache of Instance Manager has been updated (i.e.
|
||||
# SHOW INSTANCE OPTIONS <instance> does not contain 'server_id=' line).
|
||||
#
|
||||
|
||||
###########################################################################
|
||||
|
||||
--source include/im_check_os.inc
|
||||
|
||||
###########################################################################
|
||||
#
|
||||
# 0. Check starting conditions.
|
||||
#
|
||||
###########################################################################
|
||||
|
||||
# - check the configuration file;
|
||||
|
||||
--exec grep server_id $MYSQLTEST_VARDIR/im.cnf ;
|
||||
|
||||
# - 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.
|
||||
# TODO: we should check only server_id option here.
|
||||
|
||||
# SHOW INSTANCE OPTIONS mysqld1;
|
||||
# SHOW INSTANCE OPTIONS mysqld2;
|
||||
|
||||
###########################################################################
|
||||
#
|
||||
# 1. UNSET <instance_id>.server_id;
|
||||
#
|
||||
###########################################################################
|
||||
|
||||
# * mysqld1
|
||||
|
||||
UNSET mysqld1.server_id;
|
||||
|
||||
# - check that the configuration file has been updated (i.e. does not
|
||||
# contain 'server_id=' line for the instance);
|
||||
|
||||
--exec grep server_id $MYSQLTEST_VARDIR/im.cnf ;
|
||||
|
||||
# - check that the running instance has not been affected: connect to the
|
||||
# instance and check that 'SHOW VARIABLES LIKE 'server_id'' returns non-zero
|
||||
# value;
|
||||
|
||||
--connection mysql1_con
|
||||
|
||||
SHOW VARIABLES LIKE 'server_id';
|
||||
|
||||
--connection default
|
||||
|
||||
# - check that internal cache of Instance Manager is not affected (i.e. SHOW
|
||||
# INSTANCE OPTIONS <instance> contains non-zero value for server_id);
|
||||
# TODO: we should check only server_id option here.
|
||||
|
||||
# SHOW INSTANCE OPTIONS mysqld1;
|
||||
|
||||
# * mysqld2
|
||||
|
||||
UNSET mysqld2.server_id;
|
||||
|
||||
# - check that the configuration file has been updated (i.e. does not
|
||||
# contain 'server_id=' line for the instance);
|
||||
|
||||
--exec grep server_id $MYSQLTEST_VARDIR/im.cnf || true;
|
||||
|
||||
# - check that internal cache of Instance Manager is not affected (i.e. SHOW
|
||||
# INSTANCE OPTIONS <instance> contains non-zero value for server_id);
|
||||
# TODO: we should check only server_id option here.
|
||||
|
||||
# SHOW INSTANCE OPTIONS mysqld2;
|
||||
|
||||
###########################################################################
|
||||
#
|
||||
# 2. FLUSH INSTANCES;
|
||||
#
|
||||
###########################################################################
|
||||
|
||||
FLUSH INSTANCES;
|
||||
|
||||
# - check that the configuration file has not been updated (i.e. does not
|
||||
# contain 'server_id=' for the instance);
|
||||
|
||||
--exec grep server_id $MYSQLTEST_VARDIR/im.cnf || true;
|
||||
|
||||
# - (for mysqld1) check that the running instance has not been affected:
|
||||
# connect to the instance and check that 'SHOW VARIABLES LIKE 'server_id''
|
||||
# returns non-zero value;
|
||||
|
||||
--connection mysql1_con
|
||||
|
||||
SHOW VARIABLES LIKE 'server_id';
|
||||
|
||||
--connection default
|
||||
|
||||
# - check that internal cache of Instance Manager has been updated (i.e.
|
||||
# SHOW INSTANCE OPTIONS <instance> does not contain 'server_id=' line).
|
||||
# TODO: we should check only server_id option here.
|
||||
|
||||
# SHOW INSTANCE OPTIONS mysqld1;
|
||||
# SHOW INSTANCE OPTIONS mysqld2;
|
1
mysql-test/t/im_utils-im.opt
Normal file
1
mysql-test/t/im_utils-im.opt
Normal file
@ -0,0 +1 @@
|
||||
--monitoring-interval=1
|
@ -17,6 +17,9 @@
|
||||
# - the second instance is offline;
|
||||
#
|
||||
|
||||
--sleep 3
|
||||
# should be longer than monitoring interval and enough to start instance.
|
||||
|
||||
SHOW INSTANCES;
|
||||
|
||||
#
|
||||
@ -41,8 +44,9 @@ SHOW INSTANCE OPTIONS mysqld2;
|
||||
|
||||
START INSTANCE mysqld2;
|
||||
|
||||
# FIXME
|
||||
-- sleep 3
|
||||
# FIXME: START INSTANCE should be synchronous.
|
||||
--sleep 3
|
||||
# should be longer than monitoring interval and enough to start instance.
|
||||
|
||||
STOP INSTANCE mysqld2;
|
||||
|
||||
|
@ -244,7 +244,8 @@ err:
|
||||
handle_option_ctx structure.
|
||||
group_name The name of the group the option belongs to.
|
||||
option The very option to be processed. It is already
|
||||
prepared to be used in argv (has -- prefix)
|
||||
prepared to be used in argv (has -- prefix). If it
|
||||
is NULL, we are handling a new group (section).
|
||||
|
||||
DESCRIPTION
|
||||
This handler checks whether a group is one of the listed and adds an option
|
||||
@ -263,6 +264,9 @@ static int handle_default_option(void *in_ctx, const char *group_name,
|
||||
char *tmp;
|
||||
struct handle_option_ctx *ctx= (struct handle_option_ctx *) in_ctx;
|
||||
|
||||
if (!option)
|
||||
return 0;
|
||||
|
||||
if (find_type((char *)group_name, ctx->group, 3))
|
||||
{
|
||||
if (!(tmp= alloc_root(ctx->alloc, (uint) strlen(option) + 1)))
|
||||
@ -719,6 +723,10 @@ static int search_default_file_with_ext(Process_option_func opt_handler,
|
||||
end[0]=0;
|
||||
|
||||
strnmov(curr_gr, ptr, min((uint) (end-ptr)+1, 4096));
|
||||
|
||||
/* signal that a new group is found */
|
||||
opt_handler(handler_ctx, curr_gr, NULL);
|
||||
|
||||
continue;
|
||||
}
|
||||
if (!found_group)
|
||||
|
@ -40,11 +40,13 @@ static char *add_option(char *dst, const char *option_value,
|
||||
SYNOPSYS
|
||||
modify_defaults_file()
|
||||
file_location The location of configuration file to edit
|
||||
option option to look for
|
||||
option value The value of the option we would like to set
|
||||
section_name the name of the section
|
||||
remove_option This is true if we want to remove the option.
|
||||
False otherwise.
|
||||
option The name of the option to look for (can be NULL)
|
||||
option value The value of the option we would like to set (can be NULL)
|
||||
section_name The name of the section (must be NOT NULL)
|
||||
remove_option This defines what we want to remove:
|
||||
- MY_REMOVE_NONE -- nothing to remove;
|
||||
- MY_REMOVE_OPTION -- remove the specified option;
|
||||
- MY_REMOVE_SECTION -- remove the specified section;
|
||||
IMPLEMENTATION
|
||||
We open the option file first, then read the file line-by-line,
|
||||
looking for the section we need. At the same time we put these lines
|
||||
@ -67,7 +69,9 @@ int modify_defaults_file(const char *file_location, const char *option,
|
||||
FILE *cnf_file;
|
||||
MY_STAT file_stat;
|
||||
char linebuff[BUFF_SIZE], *src_ptr, *dst_ptr, *file_buffer;
|
||||
uint opt_len, optval_len, sect_len, nr_newlines= 0, buffer_size;
|
||||
uint opt_len= 0;
|
||||
uint optval_len= 0;
|
||||
uint sect_len, nr_newlines= 0, buffer_size;
|
||||
my_bool in_section= FALSE, opt_applied= 0;
|
||||
uint reserve_extended;
|
||||
uint new_opt_len;
|
||||
@ -81,8 +85,11 @@ int modify_defaults_file(const char *file_location, const char *option,
|
||||
if (my_fstat(fileno(cnf_file), &file_stat, MYF(0)))
|
||||
goto malloc_err;
|
||||
|
||||
opt_len= (uint) strlen(option);
|
||||
optval_len= (uint) strlen(option_value);
|
||||
if (option && option_value)
|
||||
{
|
||||
opt_len= (uint) strlen(option);
|
||||
optval_len= (uint) strlen(option_value);
|
||||
}
|
||||
|
||||
new_opt_len= opt_len + 1 + optval_len + NEWLINE_LEN;
|
||||
|
||||
@ -119,8 +126,8 @@ int modify_defaults_file(const char *file_location, const char *option,
|
||||
continue;
|
||||
}
|
||||
|
||||
/* correct the option */
|
||||
if (in_section && !strncmp(src_ptr, option, opt_len) &&
|
||||
/* correct the option (if requested) */
|
||||
if (option && in_section && !strncmp(src_ptr, option, opt_len) &&
|
||||
(*(src_ptr + opt_len) == '=' ||
|
||||
my_isspace(&my_charset_latin1, *(src_ptr + opt_len)) ||
|
||||
*(src_ptr + opt_len) == '\0'))
|
||||
@ -143,7 +150,12 @@ int modify_defaults_file(const char *file_location, const char *option,
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If going to new group and we have option to apply, do it now */
|
||||
/*
|
||||
If we are going to the new group and have an option to apply, do
|
||||
it now. If we are removing a single option or the whole section
|
||||
this will only trigger opt_applied flag.
|
||||
*/
|
||||
|
||||
if (in_section && !opt_applied && *src_ptr == '[')
|
||||
{
|
||||
dst_ptr= add_option(dst_ptr, option_value, option, remove_option);
|
||||
@ -153,7 +165,10 @@ int modify_defaults_file(const char *file_location, const char *option,
|
||||
|
||||
for (; nr_newlines; nr_newlines--)
|
||||
dst_ptr= strmov(dst_ptr, NEWLINE);
|
||||
dst_ptr= strmov(dst_ptr, linebuff);
|
||||
|
||||
/* Skip the section if MY_REMOVE_SECTION was given */
|
||||
if (!in_section || remove_option != MY_REMOVE_SECTION)
|
||||
dst_ptr= strmov(dst_ptr, linebuff);
|
||||
}
|
||||
/* Look for a section */
|
||||
if (*src_ptr == '[')
|
||||
@ -167,18 +182,31 @@ int modify_defaults_file(const char *file_location, const char *option,
|
||||
{}
|
||||
|
||||
if (*src_ptr != ']')
|
||||
{
|
||||
in_section= FALSE;
|
||||
continue; /* Missing closing parenthesis. Assume this was no group */
|
||||
}
|
||||
|
||||
if (remove_option == MY_REMOVE_SECTION)
|
||||
dst_ptr= dst_ptr - strlen(linebuff);
|
||||
|
||||
in_section= TRUE;
|
||||
}
|
||||
else
|
||||
in_section= FALSE; /* mark that this section is of no interest to us */
|
||||
}
|
||||
}
|
||||
/* File ended. */
|
||||
if (!opt_applied && !remove_option && in_section)
|
||||
|
||||
/*
|
||||
File ended. Apply an option or set opt_applied flag (in case of
|
||||
MY_REMOVE_SECTION) so that the changes are saved. Do not do anything
|
||||
if we are removing non-existent option.
|
||||
*/
|
||||
|
||||
if (!opt_applied && in_section && (remove_option != MY_REMOVE_OPTION))
|
||||
{
|
||||
/* New option still remains to apply at the end */
|
||||
if (*(dst_ptr - 1) != '\n')
|
||||
if (!remove_option && *(dst_ptr - 1) != '\n')
|
||||
dst_ptr= strmov(dst_ptr, NEWLINE);
|
||||
dst_ptr= add_option(dst_ptr, option_value, option, remove_option);
|
||||
opt_applied= 1;
|
||||
|
@ -20,7 +20,7 @@ IMService::~IMService(void)
|
||||
void IMService::Stop()
|
||||
{
|
||||
ReportStatus(SERVICE_STOP_PENDING);
|
||||
|
||||
|
||||
// stop the IM work
|
||||
raise(SIGTERM);
|
||||
}
|
||||
@ -32,7 +32,7 @@ void IMService::Run(DWORD argc, LPTSTR *argv)
|
||||
|
||||
Options o;
|
||||
o.load(argc, argv);
|
||||
|
||||
|
||||
// init goes here
|
||||
ReportStatus((DWORD)SERVICE_RUNNING);
|
||||
|
||||
@ -46,13 +46,13 @@ void IMService::Log(const char *msg)
|
||||
log_info(msg);
|
||||
}
|
||||
|
||||
int HandleServiceOptions(Options options)
|
||||
int HandleServiceOptions()
|
||||
{
|
||||
int ret_val= 0;
|
||||
|
||||
IMService winService;
|
||||
|
||||
if (options.install_as_service)
|
||||
if (Options::Service::install_as_service)
|
||||
{
|
||||
if (winService.IsInstalled())
|
||||
log_info("Service is already installed");
|
||||
@ -64,7 +64,7 @@ int HandleServiceOptions(Options options)
|
||||
ret_val= 1;
|
||||
}
|
||||
}
|
||||
else if (options.remove_service)
|
||||
else if (Options::Service::remove_service)
|
||||
{
|
||||
if (! winService.IsInstalled())
|
||||
log_info("Service is not installed");
|
||||
@ -77,6 +77,19 @@ int HandleServiceOptions(Options options)
|
||||
}
|
||||
}
|
||||
else
|
||||
ret_val= !winService.Init();
|
||||
{
|
||||
log_info("Initializing Instance Manager service...");
|
||||
|
||||
if (!winService.Init())
|
||||
{
|
||||
log_info("Service failed to initialize.");
|
||||
fprintf(stderr,
|
||||
"The service should be started by Windows Service Manager.\n"
|
||||
"The MySQL Manager should be started with '--standalone'\n"
|
||||
"to run from command line.");
|
||||
ret_val= 1;
|
||||
}
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
@ -1,3 +1,21 @@
|
||||
/*
|
||||
Copyright (C) 2006 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "windowsservice.h"
|
||||
|
||||
@ -12,3 +30,5 @@ protected:
|
||||
void Stop();
|
||||
void Run(DWORD argc, LPTSTR *argv);
|
||||
};
|
||||
|
||||
extern int HandleServiceOptions();
|
||||
|
@ -76,7 +76,10 @@ mysqlmanager_SOURCES= command.cc command.h mysqlmanager.cc \
|
||||
guardian.cc guardian.h \
|
||||
parse_output.cc parse_output.h \
|
||||
mysql_manager_error.h \
|
||||
portability.h
|
||||
portability.h \
|
||||
exit_codes.h \
|
||||
user_management_commands.h \
|
||||
user_management_commands.cc
|
||||
|
||||
mysqlmanager_LDADD= @CLIENT_EXTRA_LDFLAGS@ \
|
||||
liboptions.la \
|
||||
@ -90,6 +93,9 @@ mysqlmanager_LDADD= @CLIENT_EXTRA_LDFLAGS@ \
|
||||
EXTRA_DIST = WindowsService.cpp WindowsService.h IMService.cpp \
|
||||
IMService.h cmakelists.txt
|
||||
|
||||
AM_CFLAGS = -Werror
|
||||
AM_CXXFLAGS = -Werror
|
||||
|
||||
tags:
|
||||
ctags -R *.h *.cc
|
||||
|
||||
|
@ -7,9 +7,9 @@ static WindowsService *gService;
|
||||
WindowsService::WindowsService(void) :
|
||||
statusCheckpoint(0),
|
||||
serviceName(NULL),
|
||||
inited(false),
|
||||
inited(FALSE),
|
||||
dwAcceptedControls(SERVICE_ACCEPT_STOP),
|
||||
debugging(false)
|
||||
debugging(FALSE)
|
||||
{
|
||||
gService= this;
|
||||
status.dwServiceType= SERVICE_WIN32_OWN_PROCESS;
|
||||
@ -22,11 +22,12 @@ WindowsService::~WindowsService(void)
|
||||
|
||||
BOOL WindowsService::Install()
|
||||
{
|
||||
bool ret_val= false;
|
||||
bool ret_val= FALSE;
|
||||
SC_HANDLE newService;
|
||||
SC_HANDLE scm;
|
||||
|
||||
if (IsInstalled()) return true;
|
||||
if (IsInstalled())
|
||||
return TRUE;
|
||||
|
||||
// determine the name of the currently executing file
|
||||
char szFilePath[_MAX_PATH];
|
||||
@ -34,7 +35,7 @@ BOOL WindowsService::Install()
|
||||
|
||||
// open a connection to the SCM
|
||||
if (!(scm= OpenSCManager(0, 0,SC_MANAGER_CREATE_SERVICE)))
|
||||
return false;
|
||||
return FALSE;
|
||||
|
||||
newService= CreateService(scm, serviceName, displayName,
|
||||
SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
|
||||
@ -45,7 +46,7 @@ BOOL WindowsService::Install()
|
||||
if (newService)
|
||||
{
|
||||
CloseServiceHandle(newService);
|
||||
ret_val= true;
|
||||
ret_val= TRUE;
|
||||
}
|
||||
|
||||
CloseServiceHandle(scm);
|
||||
@ -56,34 +57,35 @@ BOOL WindowsService::Init()
|
||||
{
|
||||
assert(serviceName != NULL);
|
||||
|
||||
if (inited) return true;
|
||||
if (inited)
|
||||
return TRUE;
|
||||
|
||||
SERVICE_TABLE_ENTRY stb[] =
|
||||
{
|
||||
{ (LPSTR)serviceName, (LPSERVICE_MAIN_FUNCTION) ServiceMain},
|
||||
{ NULL, NULL }
|
||||
};
|
||||
inited= true;
|
||||
inited= TRUE;
|
||||
return StartServiceCtrlDispatcher(stb); //register with the Service Manager
|
||||
}
|
||||
|
||||
BOOL WindowsService::Remove()
|
||||
{
|
||||
bool ret_val= false;
|
||||
bool ret_val= FALSE;
|
||||
|
||||
if (! IsInstalled())
|
||||
return true;
|
||||
if (!IsInstalled())
|
||||
return TRUE;
|
||||
|
||||
// open a connection to the SCM
|
||||
SC_HANDLE scm= OpenSCManager(0, 0,SC_MANAGER_CREATE_SERVICE);
|
||||
if (! scm)
|
||||
return false;
|
||||
if (!scm)
|
||||
return FALSE;
|
||||
|
||||
SC_HANDLE service= OpenService(scm, serviceName, DELETE);
|
||||
if (service)
|
||||
{
|
||||
if (DeleteService(service))
|
||||
ret_val= true;
|
||||
ret_val= TRUE;
|
||||
DWORD dw= ::GetLastError();
|
||||
CloseServiceHandle(service);
|
||||
}
|
||||
@ -116,7 +118,8 @@ void WindowsService::SetAcceptedControls(DWORD acceptedControls)
|
||||
BOOL WindowsService::ReportStatus(DWORD currentState, DWORD waitHint,
|
||||
DWORD dwError)
|
||||
{
|
||||
if(debugging) return TRUE;
|
||||
if (debugging)
|
||||
return TRUE;
|
||||
|
||||
if(currentState == SERVICE_START_PENDING)
|
||||
status.dwControlsAccepted= 0;
|
||||
|
@ -1,3 +1,21 @@
|
||||
/*
|
||||
Copyright (C) 2006 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
class WindowsService
|
||||
|
@ -22,10 +22,12 @@
|
||||
#pragma interface
|
||||
#endif
|
||||
|
||||
/* Class responsible for allocation of im commands. */
|
||||
/* Class responsible for allocation of IM commands. */
|
||||
|
||||
class Instance_map;
|
||||
|
||||
struct st_net;
|
||||
|
||||
/*
|
||||
Command - entry point for any command.
|
||||
GangOf4: 'Command' design pattern
|
||||
@ -37,8 +39,18 @@ public:
|
||||
Command(Instance_map *instance_map_arg= 0);
|
||||
virtual ~Command();
|
||||
|
||||
/* method of executing: */
|
||||
virtual int execute(struct st_net *net, ulong connection_id) = 0;
|
||||
/*
|
||||
This operation incapsulates behaviour of the command.
|
||||
|
||||
SYNOPSYS
|
||||
net The network connection to the client.
|
||||
connection_id Client connection ID
|
||||
|
||||
RETURN
|
||||
0 On success
|
||||
non 0 On error. Client error code is returned.
|
||||
*/
|
||||
virtual int execute(st_net *net, ulong connection_id) = 0;
|
||||
|
||||
protected:
|
||||
Instance_map *instance_map;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -16,10 +16,20 @@
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
#include <my_global.h>
|
||||
#include <my_sys.h>
|
||||
#include <hash.h>
|
||||
|
||||
#include "command.h"
|
||||
#include "instance.h"
|
||||
#include "parse.h"
|
||||
|
||||
#if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE)
|
||||
#pragma interface
|
||||
#endif
|
||||
|
||||
struct LEX_STRING;
|
||||
|
||||
/*
|
||||
Print all instances of this instance manager.
|
||||
Grammar: SHOW ISTANCES
|
||||
@ -31,12 +41,16 @@ public:
|
||||
Show_instances(Instance_map *instance_map_arg): Command(instance_map_arg)
|
||||
{}
|
||||
|
||||
int execute(struct st_net *net, ulong connection_id);
|
||||
int execute(st_net *net, ulong connection_id);
|
||||
|
||||
private:
|
||||
int write_header(st_net *net);
|
||||
int write_data(st_net *net);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
Reread configuration file and refresh instance map.
|
||||
Reread configuration file and refresh internal cache.
|
||||
Grammar: FLUSH INSTANCES
|
||||
*/
|
||||
|
||||
@ -46,7 +60,43 @@ public:
|
||||
Flush_instances(Instance_map *instance_map_arg): Command(instance_map_arg)
|
||||
{}
|
||||
|
||||
int execute(struct st_net *net, ulong connection_id);
|
||||
int execute(st_net *net, ulong connection_id);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
Abstract class for Instance-specific commands.
|
||||
*/
|
||||
|
||||
class Abstract_instance_cmd : public Command
|
||||
{
|
||||
public:
|
||||
Abstract_instance_cmd(Instance_map *instance_map_arg,
|
||||
const LEX_STRING *instance_name_arg);
|
||||
|
||||
public:
|
||||
virtual int execute(st_net *net, ulong connection_id);
|
||||
|
||||
protected:
|
||||
/* MT-NOTE: this operation is called under acquired Instance_map's lock. */
|
||||
virtual int execute_impl(st_net *net, Instance *instance) = 0;
|
||||
|
||||
/*
|
||||
This operation is invoked on successful return of execute_impl() and is
|
||||
intended to send closing data.
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
|
||||
@ -55,31 +105,40 @@ public:
|
||||
Grammar: SHOW ISTANCE STATUS <instance_name>
|
||||
*/
|
||||
|
||||
class Show_instance_status : public Command
|
||||
class Show_instance_status : public Abstract_instance_cmd
|
||||
{
|
||||
public:
|
||||
|
||||
Show_instance_status(Instance_map *instance_map_arg,
|
||||
const char *name, uint len);
|
||||
int execute(struct st_net *net, ulong connection_id);
|
||||
const char *instance_name;
|
||||
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);
|
||||
|
||||
private:
|
||||
int write_header(st_net *net);
|
||||
int write_data(st_net *net, Instance *instance);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
Print options if chosen instance.
|
||||
Print options of chosen instance.
|
||||
Grammar: SHOW INSTANCE OPTIONS <instance_name>
|
||||
*/
|
||||
|
||||
class Show_instance_options : public Command
|
||||
class Show_instance_options : public Abstract_instance_cmd
|
||||
{
|
||||
public:
|
||||
|
||||
Show_instance_options(Instance_map *instance_map_arg,
|
||||
const char *name, uint len);
|
||||
const LEX_STRING *instance_name_arg);
|
||||
|
||||
int execute(struct st_net *net, ulong connection_id);
|
||||
const char *instance_name;
|
||||
protected:
|
||||
virtual int execute_impl(st_net *net, Instance *instance);
|
||||
virtual int send_ok_response(st_net *net, ulong connection_id);
|
||||
|
||||
private:
|
||||
int write_header(st_net *net);
|
||||
int write_data(st_net *net, Instance *instance);
|
||||
};
|
||||
|
||||
|
||||
@ -88,14 +147,15 @@ public:
|
||||
Grammar: START INSTANCE <instance_name>
|
||||
*/
|
||||
|
||||
class Start_instance : public Command
|
||||
class Start_instance : public Abstract_instance_cmd
|
||||
{
|
||||
public:
|
||||
Start_instance(Instance_map *instance_map_arg, const char *name, uint len);
|
||||
Start_instance(Instance_map *instance_map_arg,
|
||||
const LEX_STRING *instance_name_arg);
|
||||
|
||||
int execute(struct st_net *net, ulong connection_id);
|
||||
const char *instance_name;
|
||||
Instance *instance;
|
||||
protected:
|
||||
virtual int execute_impl(st_net *net, Instance *instance);
|
||||
virtual int send_ok_response(st_net *net, ulong connection_id);
|
||||
};
|
||||
|
||||
|
||||
@ -104,33 +164,95 @@ public:
|
||||
Grammar: STOP INSTANCE <instance_name>
|
||||
*/
|
||||
|
||||
class Stop_instance : public Command
|
||||
class Stop_instance : public Abstract_instance_cmd
|
||||
{
|
||||
public:
|
||||
Stop_instance(Instance_map *instance_map_arg, const char *name, uint len);
|
||||
Stop_instance(Instance_map *instance_map_arg,
|
||||
const LEX_STRING *instance_name_arg);
|
||||
|
||||
Instance *instance;
|
||||
int execute(struct st_net *net, ulong connection_id);
|
||||
const char *instance_name;
|
||||
protected:
|
||||
virtual int execute_impl(st_net *net, Instance *instance);
|
||||
virtual int send_ok_response(st_net *net, ulong connection_id);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
Print requested part of the log
|
||||
Grammar:
|
||||
SHOW <instance_name> log {ERROR | SLOW | GENERAL} size[, offset_from_end]
|
||||
Create an instance.
|
||||
Grammar: CREATE INSTANCE <instance_name> [<options>]
|
||||
*/
|
||||
|
||||
class Show_instance_log : public Command
|
||||
class Create_instance : public Command
|
||||
{
|
||||
public:
|
||||
Create_instance(Instance_map *instance_map_arg,
|
||||
const LEX_STRING *instance_name_arg);
|
||||
|
||||
Show_instance_log(Instance_map *instance_map_arg, const char *name,
|
||||
uint len, Log_type log_type_arg, const char *size_arg,
|
||||
const char *offset_arg);
|
||||
int execute(struct st_net *net, ulong connection_id);
|
||||
public:
|
||||
bool init(const char **text);
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
Drop an instance.
|
||||
Grammar: DROP INSTANCE <instance_name>
|
||||
|
||||
Operation is permitted only if the instance is stopped. On successful
|
||||
completion the instance section is removed from config file and the instance
|
||||
is removed from the instance map.
|
||||
*/
|
||||
|
||||
class Drop_instance : public Abstract_instance_cmd
|
||||
{
|
||||
public:
|
||||
Drop_instance(Instance_map *instance_map_arg,
|
||||
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);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
Print requested part of the log.
|
||||
Grammar:
|
||||
SHOW <instance_name> LOG {ERROR | SLOW | GENERAL} size[, offset_from_end]
|
||||
*/
|
||||
|
||||
class Show_instance_log : public Abstract_instance_cmd
|
||||
{
|
||||
public:
|
||||
Show_instance_log(Instance_map *instance_map_arg,
|
||||
const LEX_STRING *instance_name_arg,
|
||||
Log_type log_type_arg, uint size_arg, uint offset_arg);
|
||||
|
||||
protected:
|
||||
virtual int execute_impl(st_net *net, Instance *instance);
|
||||
virtual int send_ok_response(st_net *net, ulong connection_id);
|
||||
|
||||
private:
|
||||
int check_params(Instance *instance);
|
||||
int write_header(st_net *net);
|
||||
int write_data(st_net *net, Instance *instance);
|
||||
|
||||
private:
|
||||
Log_type log_type;
|
||||
const char *instance_name;
|
||||
uint size;
|
||||
uint offset;
|
||||
};
|
||||
@ -141,75 +263,112 @@ public:
|
||||
Grammar: SHOW <instance_name> LOG FILES
|
||||
*/
|
||||
|
||||
class Show_instance_log_files : public Command
|
||||
class Show_instance_log_files : public Abstract_instance_cmd
|
||||
{
|
||||
public:
|
||||
|
||||
Show_instance_log_files(Instance_map *instance_map_arg,
|
||||
const char *name, uint len);
|
||||
int execute(struct st_net *net, ulong connection_id);
|
||||
const char *instance_name;
|
||||
const char *option;
|
||||
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);
|
||||
|
||||
private:
|
||||
int write_header(st_net *net);
|
||||
int write_data(st_net *net, Instance *instance);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
Syntax error command. This command is issued if parser reported a syntax
|
||||
error. We need it to distinguish the parse error and the situation when
|
||||
parser internal error occured. E.g. parsing failed because we hadn't had
|
||||
enought memory. In the latter case parse_command() should return an error.
|
||||
Abstract class for option-management commands.
|
||||
*/
|
||||
|
||||
class Instance_options_list;
|
||||
|
||||
class Abstract_option_cmd : public Command
|
||||
{
|
||||
public:
|
||||
~Abstract_option_cmd();
|
||||
|
||||
public:
|
||||
bool add_option(const LEX_STRING *instance_name, Named_value *option);
|
||||
|
||||
public:
|
||||
bool init(const char **text);
|
||||
|
||||
virtual int execute(st_net *net, ulong connection_id);
|
||||
|
||||
protected:
|
||||
Abstract_option_cmd(Instance_map *instance_map_arg);
|
||||
|
||||
int correct_file(Instance *instance, Named_value *option, bool skip);
|
||||
|
||||
protected:
|
||||
virtual bool parse_args(const char **text) = 0;
|
||||
virtual int process_option(Instance *instance, Named_value *option) = 0;
|
||||
|
||||
private:
|
||||
Instance_options_list *
|
||||
get_instance_options_list(const LEX_STRING *instance_name);
|
||||
|
||||
int execute_impl(st_net *net, ulong connection_id);
|
||||
|
||||
private:
|
||||
HASH instance_options_map;
|
||||
bool initialized;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
Set an option for the instance.
|
||||
Grammar: SET instance_name.option[=option_value][, ...]
|
||||
*/
|
||||
|
||||
class Set_option : public Abstract_option_cmd
|
||||
{
|
||||
public:
|
||||
Set_option(Instance_map *instance_map_arg);
|
||||
|
||||
protected:
|
||||
virtual bool parse_args(const char **text);
|
||||
virtual int process_option(Instance *instance, Named_value *option);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
Remove option of the instance.
|
||||
Grammar: UNSET instance_name.option[, ...]
|
||||
*/
|
||||
|
||||
class Unset_option: public Abstract_option_cmd
|
||||
{
|
||||
public:
|
||||
Unset_option(Instance_map *instance_map_arg);
|
||||
|
||||
protected:
|
||||
virtual bool parse_args(const char **text);
|
||||
virtual int process_option(Instance *instance, Named_value *option);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
Syntax error command.
|
||||
|
||||
This command is issued if parser reported a syntax error. We need it to
|
||||
distinguish between syntax error and internal parser error. E.g. parsing
|
||||
failed because we hadn't had enought memory. In the latter case the parser
|
||||
just returns NULL.
|
||||
*/
|
||||
|
||||
class Syntax_error : public Command
|
||||
{
|
||||
public:
|
||||
int execute(struct st_net *net, ulong connection_id);
|
||||
};
|
||||
/* This is just to avoid compiler warning. */
|
||||
Syntax_error() :Command(NULL)
|
||||
{}
|
||||
|
||||
/*
|
||||
Set an option for the instance.
|
||||
Grammar: SET instance_name.option=option_value
|
||||
*/
|
||||
|
||||
class Set_option : public Command
|
||||
{
|
||||
public:
|
||||
Set_option(Instance_map *instance_map_arg, const char *name, uint len,
|
||||
const char *option_arg, uint option_len,
|
||||
const char *option_value_arg, uint option_value_len);
|
||||
/*
|
||||
the following function is virtual to let Unset_option to use
|
||||
*/
|
||||
virtual int do_command(struct st_net *net);
|
||||
int execute(struct st_net *net, ulong connection_id);
|
||||
protected:
|
||||
int correct_file(int skip);
|
||||
public:
|
||||
const char *instance_name;
|
||||
uint instance_name_len;
|
||||
/* buffer for the option */
|
||||
enum { MAX_OPTION_LEN= 1024 };
|
||||
char option[MAX_OPTION_LEN];
|
||||
char option_value[MAX_OPTION_LEN];
|
||||
int execute(st_net *net, ulong connection_id);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
Remove option of the instance from config file
|
||||
Grammar: UNSET instance_name.option
|
||||
*/
|
||||
|
||||
class Unset_option: public Set_option
|
||||
{
|
||||
public:
|
||||
Unset_option(Instance_map *instance_map_arg, const char *name, uint len,
|
||||
const char *option_arg, uint option_len,
|
||||
const char *option_value_arg, uint option_value_len):
|
||||
Set_option(instance_map_arg, name, len, option_arg, option_len,
|
||||
option_value_arg, option_value_len)
|
||||
{}
|
||||
int do_command(struct st_net *net);
|
||||
};
|
||||
|
||||
|
||||
#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_COMMANDS_H */
|
||||
|
41
server-tools/instance-manager/exit_codes.h
Normal file
41
server-tools/instance-manager/exit_codes.h
Normal file
@ -0,0 +1,41 @@
|
||||
#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_EXIT_CODES_H
|
||||
#define INCLUDES_MYSQL_INSTANCE_MANAGER_EXIT_CODES_H
|
||||
|
||||
/*
|
||||
Copyright (C) 2006 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
This file contains a list of exit codes, which are used when Instance
|
||||
Manager is working in user-management mode.
|
||||
*/
|
||||
|
||||
const int ERR_OK = 0;
|
||||
|
||||
const int ERR_OUT_OF_MEMORY = 1;
|
||||
const int ERR_INVALID_USAGE = 2;
|
||||
const int ERR_INTERNAL_ERROR = 3;
|
||||
const int ERR_IO_ERROR = 4;
|
||||
const int ERR_PASSWORD_FILE_CORRUPTED = 5;
|
||||
const int ERR_PASSWORD_FILE_DOES_NOT_EXIST = 6;
|
||||
|
||||
const int ERR_CAN_NOT_READ_USER_NAME = 10;
|
||||
const int ERR_CAN_NOT_READ_PASSWORD = 11;
|
||||
const int ERR_USER_ALREADY_EXISTS = 12;
|
||||
const int ERR_USER_NOT_FOUND = 13;
|
||||
|
||||
#endif // INCLUDES_MYSQL_INSTANCE_MANAGER_EXIT_CODES_H
|
@ -21,16 +21,14 @@
|
||||
|
||||
#include "guardian.h"
|
||||
|
||||
#include "instance_map.h"
|
||||
#include "instance.h"
|
||||
#include "mysql_manager_error.h"
|
||||
#include "log.h"
|
||||
#include "portability.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "instance.h"
|
||||
#include "instance_map.h"
|
||||
#include "log.h"
|
||||
#include "mysql_manager_error.h"
|
||||
|
||||
|
||||
pthread_handler_t guardian(void *arg)
|
||||
@ -40,6 +38,37 @@ pthread_handler_t guardian(void *arg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
const char *
|
||||
Guardian_thread::get_instance_state_name(enum_instance_state state)
|
||||
{
|
||||
switch (state) {
|
||||
case NOT_STARTED:
|
||||
return "offline";
|
||||
|
||||
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. */
|
||||
}
|
||||
|
||||
|
||||
Guardian_thread::Guardian_thread(Thread_registry &thread_registry_arg,
|
||||
Instance_map *instance_map_arg,
|
||||
uint monitoring_interval_arg) :
|
||||
@ -89,10 +118,17 @@ void Guardian_thread::process_instance(Instance *instance,
|
||||
if (current_node->state == STOPPING)
|
||||
{
|
||||
/* this brach is executed during shutdown */
|
||||
if (instance->options.shutdown_delay_val)
|
||||
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 */
|
||||
/* 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)
|
||||
@ -159,7 +195,11 @@ void Guardian_thread::process_instance(Instance *instance,
|
||||
instance->options.instance_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
log_info("guardian: cannot start instance %s. Abandoning attempts "
|
||||
"to (re)start it", instance->options.instance_name);
|
||||
current_node->state= CRASHED_AND_ABANDONED;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CRASHED_AND_ABANDONED:
|
||||
@ -242,7 +282,9 @@ int Guardian_thread::is_stopped()
|
||||
SYNOPSYS
|
||||
Guardian_thread::init()
|
||||
|
||||
NOTE: One should always lock guardian before calling this routine.
|
||||
NOTE: The operation should be invoked with the following locks acquired:
|
||||
- Guardian_thread;
|
||||
- Instance_map;
|
||||
|
||||
RETURN
|
||||
0 - ok
|
||||
@ -261,12 +303,11 @@ int Guardian_thread::init()
|
||||
|
||||
while ((instance= iterator.next()))
|
||||
{
|
||||
if (!(instance->options.nonguarded))
|
||||
if (guard(instance, TRUE)) /* do not lock guardian */
|
||||
{
|
||||
instance_map->unlock();
|
||||
return 1;
|
||||
}
|
||||
if (instance->options.nonguarded)
|
||||
continue;
|
||||
|
||||
if (guard(instance, TRUE)) /* do not lock guardian */
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -334,24 +375,14 @@ int Guardian_thread::stop_guard(Instance *instance)
|
||||
LIST *node;
|
||||
|
||||
pthread_mutex_lock(&LOCK_guardian);
|
||||
node= guarded_instances;
|
||||
|
||||
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)
|
||||
{
|
||||
guarded_instances= list_delete(guarded_instances, node);
|
||||
pthread_mutex_unlock(&LOCK_guardian);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
node= node->next;
|
||||
}
|
||||
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;
|
||||
}
|
||||
@ -420,7 +451,7 @@ int Guardian_thread::stop_instances(bool stop_instances_arg)
|
||||
|
||||
void Guardian_thread::lock()
|
||||
{
|
||||
pthread_mutex_lock(&LOCK_guardian);
|
||||
pthread_mutex_lock(&LOCK_guardian);
|
||||
}
|
||||
|
||||
|
||||
@ -428,3 +459,41 @@ void Guardian_thread::unlock()
|
||||
{
|
||||
pthread_mutex_unlock(&LOCK_guardian);
|
||||
}
|
||||
|
||||
|
||||
LIST *Guardian_thread::find_instance_node(Instance *instance)
|
||||
{
|
||||
LIST *node= guarded_instances;
|
||||
|
||||
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;
|
||||
|
||||
node= node->next;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
@ -17,11 +17,11 @@
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
#include <my_global.h>
|
||||
#include "thread_registry.h"
|
||||
|
||||
#include <my_sys.h>
|
||||
#include <my_list.h>
|
||||
|
||||
#include "thread_registry.h"
|
||||
|
||||
#if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE)
|
||||
#pragma interface
|
||||
#endif
|
||||
@ -79,6 +79,8 @@ public:
|
||||
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,
|
||||
@ -94,11 +96,28 @@ public:
|
||||
int guard(Instance *instance, bool nolock= FALSE);
|
||||
/* Stop instance protection */
|
||||
int stop_guard(Instance *instance);
|
||||
/* Returns true if guardian thread is stopped */
|
||||
/* 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.
|
||||
|
||||
MT-NOTE: must be called under acquired lock.
|
||||
*/
|
||||
LIST *find_instance_node(Instance *instance);
|
||||
|
||||
/* The operation is used to check if the instance is active or not. */
|
||||
bool is_active(Instance *instance);
|
||||
|
||||
/*
|
||||
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);
|
||||
|
||||
public:
|
||||
pthread_cond_t COND_guardian;
|
||||
|
||||
@ -108,6 +127,7 @@ private:
|
||||
/* check instance state and act accordingly */
|
||||
void process_instance(Instance *instance, GUARD_NODE *current_node,
|
||||
LIST **guarded_instances, LIST *elem);
|
||||
|
||||
int stopped;
|
||||
|
||||
private:
|
||||
@ -115,9 +135,15 @@ private:
|
||||
Thread_info thread_info;
|
||||
LIST *guarded_instances;
|
||||
MEM_ROOT alloc;
|
||||
enum { MEM_ROOT_BLOCK_SIZE= 512 };
|
||||
/* this variable is set to TRUE when we want to stop Guardian thread */
|
||||
bool shutdown_requested;
|
||||
};
|
||||
|
||||
|
||||
inline Guardian_thread::enum_instance_state
|
||||
Guardian_thread::get_instance_state(LIST *instance_node)
|
||||
{
|
||||
return ((GUARD_NODE *) instance_node->data)->state;
|
||||
}
|
||||
|
||||
#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_GUARDIAN_H */
|
||||
|
@ -20,18 +20,27 @@
|
||||
|
||||
#include "instance.h"
|
||||
|
||||
#include "mysql_manager_error.h"
|
||||
#include "log.h"
|
||||
#include "instance_map.h"
|
||||
#include "priv.h"
|
||||
#include "portability.h"
|
||||
#include <my_global.h>
|
||||
#include <mysql.h>
|
||||
|
||||
#include <signal.h>
|
||||
#ifndef __WIN__
|
||||
#include <sys/wait.h>
|
||||
#endif
|
||||
#include <my_sys.h>
|
||||
#include <signal.h>
|
||||
#include <m_string.h>
|
||||
#include <mysql.h>
|
||||
|
||||
#include "guardian.h"
|
||||
#include "instance_map.h"
|
||||
#include "log.h"
|
||||
#include "mysql_manager_error.h"
|
||||
#include "portability.h"
|
||||
#include "priv.h"
|
||||
|
||||
|
||||
const LEX_STRING
|
||||
Instance::DFLT_INSTANCE_NAME= { C_STRING_WITH_SIZE("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,
|
||||
@ -152,7 +161,7 @@ static int start_process(Instance_options *instance_options,
|
||||
|
||||
switch (*pi) {
|
||||
case 0: /* never happens on QNX */
|
||||
execv(instance_options->mysqld_path, instance_options->argv);
|
||||
execv(instance_options->mysqld_path.str, instance_options->argv);
|
||||
/* exec never returns */
|
||||
exit(1);
|
||||
case -1:
|
||||
@ -180,7 +189,7 @@ static int start_process(Instance_options *instance_options,
|
||||
char *cmdline= new char[cmdlen];
|
||||
if (cmdline == NULL)
|
||||
return 1;
|
||||
|
||||
|
||||
cmdline[0]= 0;
|
||||
for (int i= 0; instance_options->argv[i] != 0; i++)
|
||||
{
|
||||
@ -232,9 +241,7 @@ static int start_process(Instance_options *instance_options,
|
||||
static void start_and_monitor_instance(Instance_options *old_instance_options,
|
||||
Instance_map *instance_map)
|
||||
{
|
||||
enum { MAX_INSTANCE_NAME_LEN= 512 };
|
||||
char instance_name_buff[MAX_INSTANCE_NAME_LEN];
|
||||
uint instance_name_len;
|
||||
Instance_name instance_name(&old_instance_options->instance_name);
|
||||
Instance *current_instance;
|
||||
My_process_info process_info;
|
||||
|
||||
@ -248,11 +255,8 @@ static void start_and_monitor_instance(Instance_options *old_instance_options,
|
||||
Save the instance name in the case if Instance object we
|
||||
are using is destroyed. (E.g. by "FLUSH INSTANCES")
|
||||
*/
|
||||
strmake(instance_name_buff, old_instance_options->instance_name,
|
||||
MAX_INSTANCE_NAME_LEN - 1);
|
||||
instance_name_len= old_instance_options->instance_name_len;
|
||||
|
||||
log_info("starting instance %s", instance_name_buff);
|
||||
log_info("starting instance %s", (const char *) instance_name.get_c_str());
|
||||
|
||||
if (start_process(old_instance_options, &process_info))
|
||||
{
|
||||
@ -266,15 +270,36 @@ static void start_and_monitor_instance(Instance_options *old_instance_options,
|
||||
/* don't check for return value */
|
||||
wait_process(&process_info);
|
||||
|
||||
current_instance= instance_map->find(instance_name_buff, instance_name_len);
|
||||
instance_map->lock();
|
||||
|
||||
current_instance= instance_map->find(instance_name.get_str());
|
||||
|
||||
if (current_instance)
|
||||
current_instance->set_crash_flag_n_wake_all();
|
||||
|
||||
instance_map->unlock();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
bool Instance::is_name_valid(const LEX_STRING *name)
|
||||
{
|
||||
const char *name_suffix= name->str + INSTANCE_NAME_PREFIX_LEN;
|
||||
|
||||
if (strncmp(name->str, INSTANCE_NAME_PREFIX, INSTANCE_NAME_PREFIX_LEN) != 0)
|
||||
return FALSE;
|
||||
|
||||
return *name_suffix == 0 || my_isdigit(default_charset_info, *name_suffix);
|
||||
}
|
||||
|
||||
|
||||
bool Instance::is_mysqld_compatible_name(const LEX_STRING *name)
|
||||
{
|
||||
return strcmp(name->str, INSTANCE_NAME_PREFIX) == 0;
|
||||
}
|
||||
|
||||
|
||||
Instance_map *Instance::get_map()
|
||||
{
|
||||
return instance_map;
|
||||
@ -309,11 +334,11 @@ int Instance::start()
|
||||
{
|
||||
/* clear crash flag */
|
||||
pthread_mutex_lock(&LOCK_instance);
|
||||
crashed= 0;
|
||||
crashed= FALSE;
|
||||
pthread_mutex_unlock(&LOCK_instance);
|
||||
|
||||
|
||||
if (!is_running())
|
||||
if (configured && !is_running())
|
||||
{
|
||||
remove_pid();
|
||||
|
||||
@ -339,8 +364,8 @@ int Instance::start()
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* the instance is started already */
|
||||
return ER_INSTANCE_ALREADY_STARTED;
|
||||
/* The instance is started already or misconfigured. */
|
||||
return configured ? ER_INSTANCE_ALREADY_STARTED : ER_INSTANCE_MISCONFIGURED;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -363,7 +388,7 @@ void Instance::set_crash_flag_n_wake_all()
|
||||
{
|
||||
/* set instance state to crashed */
|
||||
pthread_mutex_lock(&LOCK_instance);
|
||||
crashed= 1;
|
||||
crashed= TRUE;
|
||||
pthread_mutex_unlock(&LOCK_instance);
|
||||
|
||||
/*
|
||||
@ -378,7 +403,7 @@ void Instance::set_crash_flag_n_wake_all()
|
||||
|
||||
|
||||
|
||||
Instance::Instance(): crashed(0)
|
||||
Instance::Instance(): crashed(FALSE), configured(FALSE)
|
||||
{
|
||||
pthread_mutex_init(&LOCK_instance, 0);
|
||||
pthread_cond_init(&COND_instance_stopped, 0);
|
||||
@ -392,9 +417,9 @@ Instance::~Instance()
|
||||
}
|
||||
|
||||
|
||||
int Instance::is_crashed()
|
||||
bool Instance::is_crashed()
|
||||
{
|
||||
int val;
|
||||
bool val;
|
||||
pthread_mutex_lock(&LOCK_instance);
|
||||
val= crashed;
|
||||
pthread_mutex_unlock(&LOCK_instance);
|
||||
@ -413,10 +438,17 @@ bool Instance::is_running()
|
||||
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= strchr(options.mysqld_socket, '=') + 1;
|
||||
socket= options.mysqld_socket;
|
||||
|
||||
/* no port was specified => instance falled back to default value */
|
||||
if (!options.mysqld_port && !options.mysqld_socket)
|
||||
@ -469,8 +501,15 @@ int Instance::stop()
|
||||
struct timespec timeout;
|
||||
uint waitchild= (uint) DEFAULT_SHUTDOWN_DELAY;
|
||||
|
||||
if (options.shutdown_delay_val)
|
||||
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;
|
||||
}
|
||||
|
||||
kill_instance(SIGTERM);
|
||||
/* sleep on condition to wait for SIGCHLD */
|
||||
@ -588,20 +627,33 @@ void Instance::kill_instance(int signum)
|
||||
}
|
||||
|
||||
/*
|
||||
We execute this function to initialize instance parameters.
|
||||
Return value: 0 - ok. 1 - unable to init DYNAMIC_ARRAY.
|
||||
Initialize instance parameters.
|
||||
|
||||
SYNOPSYS
|
||||
Instance::init()
|
||||
name_arg name of the instance
|
||||
|
||||
RETURN:
|
||||
0 ok
|
||||
!0 error
|
||||
*/
|
||||
|
||||
int Instance::init(const char *name_arg)
|
||||
int Instance::init(const LEX_STRING *name_arg)
|
||||
{
|
||||
mysqld_compatible= is_mysqld_compatible_name(name_arg);
|
||||
|
||||
return options.init(name_arg);
|
||||
}
|
||||
|
||||
|
||||
int Instance::complete_initialization(Instance_map *instance_map_arg,
|
||||
const char *mysqld_path,
|
||||
uint instance_type)
|
||||
const char *mysqld_path)
|
||||
{
|
||||
instance_map= instance_map_arg;
|
||||
return options.complete_initialization(mysqld_path, instance_type);
|
||||
configured= !options.complete_initialization(mysqld_path);
|
||||
return 0;
|
||||
/*
|
||||
TODO: return actual status (from
|
||||
Instance_options::complete_initialization()) here.
|
||||
*/
|
||||
}
|
||||
|
@ -17,7 +17,10 @@
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
#include <my_global.h>
|
||||
#include <m_string.h>
|
||||
|
||||
#include "instance_options.h"
|
||||
#include "priv.h"
|
||||
|
||||
#if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE)
|
||||
#pragma interface
|
||||
@ -25,31 +28,120 @@
|
||||
|
||||
class Instance_map;
|
||||
|
||||
|
||||
/*
|
||||
Instance_name -- the class represents instance name -- a string of length
|
||||
less than MAX_INSTANCE_NAME_SIZE.
|
||||
|
||||
Generally, this is just a string with self-memory-management and should be
|
||||
eliminated in the future.
|
||||
*/
|
||||
|
||||
class Instance_name
|
||||
{
|
||||
public:
|
||||
Instance_name(const LEX_STRING *name);
|
||||
|
||||
public:
|
||||
inline const LEX_STRING *get_str() const
|
||||
{
|
||||
return &str;
|
||||
}
|
||||
|
||||
inline const char *get_c_str() const
|
||||
{
|
||||
return str.str;
|
||||
}
|
||||
|
||||
inline uint get_length() const
|
||||
{
|
||||
return str.length;
|
||||
}
|
||||
|
||||
private:
|
||||
LEX_STRING str;
|
||||
char str_buffer[MAX_INSTANCE_NAME_SIZE];
|
||||
};
|
||||
|
||||
|
||||
class Instance
|
||||
{
|
||||
public:
|
||||
/*
|
||||
The following two constants defines name of the default mysqld-instance
|
||||
("mysqld").
|
||||
*/
|
||||
static const LEX_STRING DFLT_INSTANCE_NAME;
|
||||
|
||||
public:
|
||||
/*
|
||||
The operation is intended to check whether string is a well-formed
|
||||
instance name or not.
|
||||
*/
|
||||
static bool is_name_valid(const LEX_STRING *name);
|
||||
|
||||
/*
|
||||
The operation is intended to check if the given instance name is
|
||||
mysqld-compatible or not.
|
||||
*/
|
||||
static bool is_mysqld_compatible_name(const LEX_STRING *name);
|
||||
|
||||
public:
|
||||
Instance();
|
||||
|
||||
~Instance();
|
||||
int init(const char *name);
|
||||
int init(const LEX_STRING *name_arg);
|
||||
int complete_initialization(Instance_map *instance_map_arg,
|
||||
const char *mysqld_path, uint instance_type);
|
||||
const char *mysqld_path);
|
||||
|
||||
bool is_running();
|
||||
int start();
|
||||
int stop();
|
||||
/* send a signal to the instance */
|
||||
void kill_instance(int signo);
|
||||
int is_crashed();
|
||||
bool is_crashed();
|
||||
void set_crash_flag_n_wake_all();
|
||||
Instance_map *get_map();
|
||||
|
||||
/*
|
||||
The operation is intended to check if the instance is mysqld-compatible
|
||||
or not.
|
||||
*/
|
||||
inline bool is_mysqld_compatible() const;
|
||||
|
||||
/*
|
||||
The operation is intended to check if the instance is configured properly
|
||||
or not. Misconfigured instances are not managed.
|
||||
*/
|
||||
inline bool is_configured() const;
|
||||
|
||||
inline const LEX_STRING *get_name() const;
|
||||
|
||||
public:
|
||||
enum { DEFAULT_SHUTDOWN_DELAY= 35 };
|
||||
Instance_options options;
|
||||
|
||||
private:
|
||||
int crashed;
|
||||
/* This attributes is a flag, specifies if the instance has been crashed. */
|
||||
bool crashed;
|
||||
|
||||
/*
|
||||
This attribute specifies if the instance is configured properly or not.
|
||||
Misconfigured instances are not managed.
|
||||
*/
|
||||
bool configured;
|
||||
|
||||
/*
|
||||
This attribute specifies whether the instance is mysqld-compatible or not.
|
||||
Mysqld-compatible instances can contain only mysqld-specific options.
|
||||
At the moment an instance is mysqld-compatible if its name is "mysqld".
|
||||
|
||||
The idea is that [mysqld] section should contain only mysqld-specific
|
||||
options (no Instance Manager-specific options) to be readable by mysqld
|
||||
program.
|
||||
*/
|
||||
bool mysqld_compatible;
|
||||
|
||||
/*
|
||||
Mutex protecting the instance. Currently we use it to avoid the
|
||||
double start of the instance. This happens when the instance is starting
|
||||
@ -66,4 +158,22 @@ private:
|
||||
void remove_pid();
|
||||
};
|
||||
|
||||
|
||||
inline bool Instance::is_mysqld_compatible() const
|
||||
{
|
||||
return mysqld_compatible;
|
||||
}
|
||||
|
||||
|
||||
inline bool Instance::is_configured() const
|
||||
{
|
||||
return configured;
|
||||
}
|
||||
|
||||
|
||||
inline const LEX_STRING *Instance::get_name() const
|
||||
{
|
||||
return &options.instance_name;
|
||||
}
|
||||
|
||||
#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_INSTANCE_H */
|
||||
|
@ -20,15 +20,21 @@
|
||||
|
||||
#include "instance_map.h"
|
||||
|
||||
#include "buffer.h"
|
||||
#include "instance.h"
|
||||
#include "log.h"
|
||||
#include "options.h"
|
||||
|
||||
#include <my_global.h>
|
||||
#include <m_ctype.h>
|
||||
#include <mysql_com.h>
|
||||
#include <m_string.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"
|
||||
#include "priv.h"
|
||||
|
||||
/*
|
||||
Note: As we are going to suppost different types of connections,
|
||||
we shouldn't have connection-specific functions. To avoid it we could
|
||||
@ -45,8 +51,8 @@ static byte* get_instance_key(const byte* u, uint* len,
|
||||
my_bool __attribute__((unused)) t)
|
||||
{
|
||||
const Instance *instance= (const Instance *) u;
|
||||
*len= instance->options.instance_name_len;
|
||||
return (byte *) instance->options.instance_name;
|
||||
*len= instance->options.instance_name.length;
|
||||
return (byte *) instance->options.instance_name.str;
|
||||
}
|
||||
|
||||
static void delete_instance(void *u)
|
||||
@ -79,15 +85,59 @@ static void delete_instance(void *u)
|
||||
|
||||
static int process_option(void *ctx, const char *group, const char *option)
|
||||
{
|
||||
Instance_map *map= NULL;
|
||||
Instance_map *map= (Instance_map*) ctx;
|
||||
LEX_STRING group_str;
|
||||
|
||||
map = (Instance_map*) ctx;
|
||||
return map->process_one_option(group, option);
|
||||
group_str.str= (char *) group;
|
||||
group_str.length= strlen(group);
|
||||
|
||||
return map->process_one_option(&group_str, option);
|
||||
}
|
||||
|
||||
C_MODE_END
|
||||
|
||||
|
||||
/*
|
||||
Parse option string.
|
||||
|
||||
SYNOPSIS
|
||||
parse_option()
|
||||
option_str [IN] option string (e.g. "--name=value")
|
||||
option_name_buf [OUT] parsed name of the option.
|
||||
Must be of (MAX_OPTION_LEN + 1) size.
|
||||
option_value_buf [OUT] parsed value of the option.
|
||||
Must be of (MAX_OPTION_LEN + 1) size.
|
||||
|
||||
DESCRIPTION
|
||||
This is an auxiliary function and should not be used externally. It is
|
||||
intended to parse whole option string into option name and option value.
|
||||
*/
|
||||
|
||||
static void parse_option(const char *option_str,
|
||||
char *option_name_buf,
|
||||
char *option_value_buf)
|
||||
{
|
||||
char *eq_pos;
|
||||
const char *ptr= option_str;
|
||||
|
||||
while (*ptr == '-')
|
||||
++ptr;
|
||||
|
||||
strmake(option_name_buf, ptr, MAX_OPTION_LEN + 1);
|
||||
|
||||
eq_pos= strchr(ptr, '=');
|
||||
if (eq_pos)
|
||||
{
|
||||
option_name_buf[eq_pos - ptr]= 0;
|
||||
strmake(option_value_buf, eq_pos + 1, MAX_OPTION_LEN + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
option_value_buf[0]= 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Process one option from the configuration file.
|
||||
|
||||
@ -103,34 +153,64 @@ C_MODE_END
|
||||
of the instance map object.
|
||||
*/
|
||||
|
||||
int Instance_map::process_one_option(const char *group, const char *option)
|
||||
int Instance_map::process_one_option(const LEX_STRING *group,
|
||||
const char *option)
|
||||
{
|
||||
Instance *instance= NULL;
|
||||
static const char prefix[]= { 'm', 'y', 's', 'q', 'l', 'd' };
|
||||
|
||||
if (strncmp(group, prefix, sizeof prefix) == 0 &&
|
||||
((my_isdigit(default_charset_info, group[sizeof prefix]))
|
||||
|| group[sizeof(prefix)] == '\0'))
|
||||
if (!Instance::is_name_valid(group))
|
||||
{
|
||||
/*
|
||||
Current section name is not a valid instance name.
|
||||
We should skip it w/o error.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(instance= (Instance *) hash_search(&hash, (byte *) group->str,
|
||||
group->length)))
|
||||
{
|
||||
if (!(instance= new Instance()))
|
||||
return 1;
|
||||
|
||||
if (instance->init(group) || add_instance(instance))
|
||||
{
|
||||
if (!(instance= (Instance *) hash_search(&hash, (byte *) group,
|
||||
strlen(group))))
|
||||
{
|
||||
if (!(instance= new Instance))
|
||||
goto err;
|
||||
if (instance->init(group) || my_hash_insert(&hash, (byte *) instance))
|
||||
goto err_instance;
|
||||
}
|
||||
|
||||
if (instance->options.add_option(option))
|
||||
goto err; /* the instance'll be deleted when we destroy the map */
|
||||
delete instance;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
if (instance->is_mysqld_compatible())
|
||||
log_info("Warning: instance name '%s' is mysqld-compatible.",
|
||||
(const char *) group->str);
|
||||
|
||||
err_instance:
|
||||
delete instance;
|
||||
err:
|
||||
return 1;
|
||||
log_info("mysqld instance '%s' has been added successfully.",
|
||||
(const char *) group->str);
|
||||
}
|
||||
|
||||
if (option)
|
||||
{
|
||||
char option_name[MAX_OPTION_LEN + 1];
|
||||
char option_value[MAX_OPTION_LEN + 1];
|
||||
|
||||
parse_option(option, option_name, option_value);
|
||||
|
||||
if (instance->is_mysqld_compatible() &&
|
||||
Instance_options::is_option_im_specific(option_name))
|
||||
{
|
||||
log_info("Warning: configuration of mysqld-compatible instance '%s' "
|
||||
"contains IM-specific option '%s'. "
|
||||
"This breaks backward compatibility for the configuration file.",
|
||||
(const char *) group->str,
|
||||
(const char *) option_name);
|
||||
}
|
||||
|
||||
Named_value option(option_name, option_value);
|
||||
|
||||
if (instance->options.set_option(&option))
|
||||
return 1; /* the instance'll be deleted when we destroy the map */
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -181,7 +261,7 @@ void Instance_map::unlock()
|
||||
- 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
|
||||
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
|
||||
@ -194,9 +274,9 @@ void Instance_map::unlock()
|
||||
In order to avoid such side effects one should never call
|
||||
FLUSH INSTANCES without prior stop of all running instances.
|
||||
|
||||
TODO
|
||||
FLUSH INSTANCES should return an error if it's called
|
||||
while there is a running instance.
|
||||
NOTE: The operation should be invoked with the following locks acquired:
|
||||
- Guardian_thread;
|
||||
- Instance_map;
|
||||
*/
|
||||
|
||||
int Instance_map::flush_instances()
|
||||
@ -209,67 +289,169 @@ int Instance_map::flush_instances()
|
||||
guardian (2) reload the instance map (3) reinitialize the guardian
|
||||
with new instances.
|
||||
*/
|
||||
guardian->lock();
|
||||
pthread_mutex_lock(&LOCK_instance_map);
|
||||
hash_free(&hash);
|
||||
hash_init(&hash, default_charset_info, START_HASH_SIZE, 0, 0,
|
||||
get_instance_key, delete_instance, 0);
|
||||
|
||||
rc= load();
|
||||
guardian->init();
|
||||
pthread_mutex_unlock(&LOCK_instance_map);
|
||||
guardian->unlock();
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
Instance *
|
||||
Instance_map::find(const char *name, uint name_len)
|
||||
bool Instance_map::is_there_active_instance()
|
||||
{
|
||||
Instance *instance;
|
||||
pthread_mutex_lock(&LOCK_instance_map);
|
||||
instance= (Instance *) hash_search(&hash, (byte *) name, name_len);
|
||||
pthread_mutex_unlock(&LOCK_instance_map);
|
||||
return instance;
|
||||
Iterator iterator(this);
|
||||
|
||||
while ((instance= iterator.next()))
|
||||
{
|
||||
if (guardian->find_instance_node(instance) != NULL ||
|
||||
instance->is_running())
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
int Instance_map::complete_initialization()
|
||||
int Instance_map::add_instance(Instance *instance)
|
||||
{
|
||||
Instance *instance;
|
||||
uint i= 0;
|
||||
return my_hash_insert(&hash, (byte *) instance);
|
||||
}
|
||||
|
||||
|
||||
if (hash.records == 0) /* no instances found */
|
||||
int Instance_map::remove_instance(Instance *instance)
|
||||
{
|
||||
return hash_delete(&hash, (byte *) instance);
|
||||
}
|
||||
|
||||
|
||||
int Instance_map::create_instance(const LEX_STRING *instance_name,
|
||||
const Named_value_arr *options)
|
||||
{
|
||||
Instance *instance= new Instance();
|
||||
|
||||
if (!instance)
|
||||
{
|
||||
if ((instance= new Instance) == 0)
|
||||
goto err;
|
||||
|
||||
if (instance->init("mysqld") || my_hash_insert(&hash, (byte *) instance))
|
||||
goto err_instance;
|
||||
|
||||
/*
|
||||
After an instance have been added to the instance_map,
|
||||
hash_free should handle it's deletion => goto err, not
|
||||
err_instance.
|
||||
*/
|
||||
if (instance->complete_initialization(this, mysqld_path,
|
||||
DEFAULT_SINGLE_INSTANCE))
|
||||
goto err;
|
||||
log_error("Error: can not initialize (name: '%s').",
|
||||
(const char *) instance_name->str);
|
||||
return ER_OUT_OF_RESOURCES;
|
||||
}
|
||||
else
|
||||
while (i < hash.records)
|
||||
|
||||
if (instance->init(instance_name))
|
||||
{
|
||||
log_error("Error: can not initialize (name: '%s').",
|
||||
(const char *) instance_name->str);
|
||||
delete instance;
|
||||
return ER_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
for (int i= 0; options && i < options->get_size(); ++i)
|
||||
{
|
||||
Named_value option= options->get_element(i);
|
||||
|
||||
if (instance->is_mysqld_compatible() &&
|
||||
Instance_options::is_option_im_specific(option.get_name()))
|
||||
{
|
||||
instance= (Instance *) hash_element(&hash, i);
|
||||
if (instance->complete_initialization(this, mysqld_path, USUAL_INSTANCE))
|
||||
goto err;
|
||||
i++;
|
||||
log_error("Error: IM-option (%s) can not be used "
|
||||
"in configuration of mysqld-compatible instance (%s).",
|
||||
(const char *) option.get_name(),
|
||||
(const char *) instance_name->str);
|
||||
delete instance;
|
||||
return ER_INCOMPATIBLE_OPTION;
|
||||
}
|
||||
|
||||
instance->options.set_option(&option);
|
||||
}
|
||||
|
||||
if (instance->is_mysqld_compatible())
|
||||
log_info("Warning: instance name '%s' is mysqld-compatible.",
|
||||
(const char *) instance_name->str);
|
||||
|
||||
if (instance->complete_initialization(this, mysqld_path))
|
||||
{
|
||||
log_error("Error: can not complete initialization of instance (name: '%s').",
|
||||
(const char *) instance_name->str);
|
||||
delete instance;
|
||||
return ER_OUT_OF_RESOURCES;
|
||||
/* TODO: return more appropriate error code in this case. */
|
||||
}
|
||||
|
||||
if (add_instance(instance))
|
||||
{
|
||||
log_error("Error: can not register instance (name: '%s').",
|
||||
(const char *) instance_name->str);
|
||||
delete instance;
|
||||
return ER_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
return 0;
|
||||
err_instance:
|
||||
delete instance;
|
||||
err:
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
Instance * Instance_map::find(const LEX_STRING *name)
|
||||
{
|
||||
return (Instance *) hash_search(&hash, (byte *) name->str, name->length);
|
||||
}
|
||||
|
||||
|
||||
bool Instance_map::complete_initialization()
|
||||
{
|
||||
bool mysqld_found;
|
||||
|
||||
/* Complete initialization of all registered instances. */
|
||||
|
||||
for (uint i= 0; i < hash.records; ++i)
|
||||
{
|
||||
Instance *instance= (Instance *) hash_element(&hash, i);
|
||||
|
||||
if (instance->complete_initialization(this, mysqld_path))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* That's all if we are runnning in an ordinary mode. */
|
||||
|
||||
if (!Options::Main::mysqld_safe_compatible)
|
||||
return FALSE;
|
||||
|
||||
/* In mysqld-compatible mode we must ensure that there 'mysqld' instance. */
|
||||
|
||||
mysqld_found= find(&Instance::DFLT_INSTANCE_NAME) != NULL;
|
||||
|
||||
if (mysqld_found)
|
||||
return FALSE;
|
||||
|
||||
if (create_instance(&Instance::DFLT_INSTANCE_NAME, NULL))
|
||||
{
|
||||
log_error("Error: could not create default instance.");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
switch (create_instance_in_file(&Instance::DFLT_INSTANCE_NAME, NULL))
|
||||
{
|
||||
case 0:
|
||||
case ER_CONF_FILE_DOES_NOT_EXIST:
|
||||
/*
|
||||
Continue if the instance has been added to the config file
|
||||
successfully, or the config file just does not exist.
|
||||
*/
|
||||
break;
|
||||
|
||||
default:
|
||||
log_error("Error: could not add default instance to the config file.");
|
||||
|
||||
Instance *instance= find(&Instance::DFLT_INSTANCE_NAME);
|
||||
|
||||
if (instance)
|
||||
remove_instance(instance); /* instance is deleted here. */
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
@ -297,10 +479,10 @@ int Instance_map::load()
|
||||
name and start looking for files named "my.cnf.cnf" in all
|
||||
default dirs. Which is not what we want.
|
||||
*/
|
||||
if (Options::is_forced_default_file)
|
||||
if (Options::Main::is_forced_default_file)
|
||||
{
|
||||
snprintf(defaults_file_arg, FN_REFLEN, "--defaults-file=%s",
|
||||
Options::config_file);
|
||||
Options::Main::config_file);
|
||||
|
||||
argv_options[1]= defaults_file_arg;
|
||||
argv_options[2]= '\0';
|
||||
@ -314,15 +496,12 @@ int Instance_map::load()
|
||||
If the routine failed, we'll simply fallback to defaults in
|
||||
complete_initialization().
|
||||
*/
|
||||
if (my_search_option_files(Options::config_file, &argc,
|
||||
if (my_search_option_files(Options::Main::config_file, &argc,
|
||||
(char ***) &argv, &args_used,
|
||||
process_option, (void*) this))
|
||||
log_info("Falling back to compiled-in defaults");
|
||||
|
||||
if (complete_initialization())
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
return complete_initialization();
|
||||
}
|
||||
|
||||
|
||||
@ -343,3 +522,105 @@ Instance *Instance_map::Iterator::next()
|
||||
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";
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Create a new configuration section for mysqld-instance in the config file.
|
||||
|
||||
SYNOPSYS
|
||||
create_instance_in_file()
|
||||
instance_name mysqld-instance name
|
||||
options options for the new mysqld-instance
|
||||
|
||||
RETURN
|
||||
0 On success
|
||||
ER_CONF_FILE_DOES_NOT_EXIST If config file does not exist
|
||||
ER_ACCESS_OPTION_FILE If config file is not writable or some I/O
|
||||
error ocurred during writing configuration
|
||||
*/
|
||||
|
||||
int create_instance_in_file(const LEX_STRING *instance_name,
|
||||
const Named_value_arr *options)
|
||||
{
|
||||
File cnf_file;
|
||||
|
||||
if (my_access(Options::Main::config_file, W_OK))
|
||||
{
|
||||
log_error("Error: configuration file (%s) does not exist.",
|
||||
(const char *) Options::Main::config_file);
|
||||
return ER_CONF_FILE_DOES_NOT_EXIST;
|
||||
}
|
||||
|
||||
cnf_file= my_open(Options::Main::config_file, O_WRONLY | O_APPEND, MYF(0));
|
||||
|
||||
if (cnf_file <= 0)
|
||||
{
|
||||
log_error("Error: can not open configuration file (%s): %s.",
|
||||
(const char *) Options::Main::config_file,
|
||||
(const char *) strerror(errno));
|
||||
return ER_ACCESS_OPTION_FILE;
|
||||
}
|
||||
|
||||
if (my_write(cnf_file, (byte*)NEWLINE, NEWLINE_LEN, MYF(MY_NABP)) ||
|
||||
my_write(cnf_file, (byte*)"[", 1, MYF(MY_NABP)) ||
|
||||
my_write(cnf_file, (byte*)instance_name->str, instance_name->length,
|
||||
MYF(MY_NABP)) ||
|
||||
my_write(cnf_file, (byte*)"]", 1, MYF(MY_NABP)) ||
|
||||
my_write(cnf_file, (byte*)NEWLINE, NEWLINE_LEN, MYF(MY_NABP)))
|
||||
{
|
||||
log_error("Error: can not write to configuration file (%s): %s.",
|
||||
(const char *) Options::Main::config_file,
|
||||
(const char *) strerror(errno));
|
||||
my_close(cnf_file, MYF(0));
|
||||
return ER_ACCESS_OPTION_FILE;
|
||||
}
|
||||
|
||||
for (int i= 0; options && i < options->get_size(); ++i)
|
||||
{
|
||||
char option_str[MAX_OPTION_STR_LEN];
|
||||
char *ptr;
|
||||
int option_str_len;
|
||||
Named_value option= options->get_element(i);
|
||||
|
||||
ptr= strxnmov(option_str, MAX_OPTION_LEN + 1, option.get_name(), NullS);
|
||||
|
||||
if (option.get_value()[0])
|
||||
ptr= strxnmov(ptr, MAX_OPTION_LEN + 2, "=", option.get_value(), NullS);
|
||||
|
||||
option_str_len= ptr - option_str;
|
||||
|
||||
if (my_write(cnf_file, (byte*)option_str, option_str_len, MYF(MY_NABP)) ||
|
||||
my_write(cnf_file, (byte*)NEWLINE, NEWLINE_LEN, MYF(MY_NABP)))
|
||||
{
|
||||
log_error("Error: can not write to configuration file (%s): %s.",
|
||||
(const char *) Options::Main::config_file,
|
||||
(const char *) strerror(errno));
|
||||
my_close(cnf_file, MYF(0));
|
||||
return ER_ACCESS_OPTION_FILE;
|
||||
}
|
||||
}
|
||||
|
||||
my_close(cnf_file, MYF(0));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -17,10 +17,6 @@
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
#include <my_global.h>
|
||||
|
||||
#include "protocol.h"
|
||||
#include "guardian.h"
|
||||
|
||||
#include <my_sys.h>
|
||||
#include <hash.h>
|
||||
|
||||
@ -28,10 +24,18 @@
|
||||
#pragma interface
|
||||
#endif
|
||||
|
||||
struct LEX_STRING;
|
||||
|
||||
class Guardian_thread;
|
||||
class Instance;
|
||||
class Named_value_arr;
|
||||
|
||||
extern int load_all_groups(char ***groups, const char *filename);
|
||||
extern void free_groups(char **groups);
|
||||
|
||||
extern int create_instance_in_file(const LEX_STRING *instance_name,
|
||||
const Named_value_arr *options);
|
||||
|
||||
|
||||
/*
|
||||
Instance_map - stores all existing instances
|
||||
@ -56,22 +60,64 @@ public:
|
||||
};
|
||||
friend class Iterator;
|
||||
public:
|
||||
/* returns a pointer to the instance or NULL, if there is no such instance */
|
||||
Instance *find(const char *name, uint name_len);
|
||||
/*
|
||||
Return a pointer to the instance or NULL, if there is no such instance.
|
||||
MT-NOTE: must be called under acquired lock.
|
||||
*/
|
||||
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();
|
||||
|
||||
/*
|
||||
Process a given option and assign it to appropricate instance. This is
|
||||
required for the option handler, passed to my_search_option_files().
|
||||
*/
|
||||
int process_one_option(const char *group, const char *option);
|
||||
int process_one_option(const LEX_STRING *group, const char *option);
|
||||
|
||||
/*
|
||||
Add an instance into the internal hash.
|
||||
|
||||
MT-NOTE: the operation must be called under acquired lock.
|
||||
*/
|
||||
int add_instance(Instance *instance);
|
||||
|
||||
/*
|
||||
Remove instance from the internal hash.
|
||||
|
||||
MT-NOTE: the operation must be called under acquired lock.
|
||||
*/
|
||||
int remove_instance(Instance *instance);
|
||||
|
||||
/*
|
||||
Create a new instance and register it in the internal hash.
|
||||
|
||||
MT-NOTE: the operation must be called under acquired lock.
|
||||
*/
|
||||
int create_instance(const LEX_STRING *instance_name,
|
||||
const Named_value_arr *options);
|
||||
|
||||
Instance_map(const char *default_mysqld_path_arg);
|
||||
~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;
|
||||
@ -80,7 +126,7 @@ private:
|
||||
/* loads options from config files */
|
||||
int load();
|
||||
/* inits instances argv's after all options have been loaded */
|
||||
int complete_initialization();
|
||||
bool complete_initialization();
|
||||
private:
|
||||
enum { START_HASH_SIZE = 16 };
|
||||
pthread_mutex_t LOCK_instance_map;
|
||||
|
@ -20,27 +20,24 @@
|
||||
|
||||
#include "instance_options.h"
|
||||
|
||||
#include "parse_output.h"
|
||||
#include "buffer.h"
|
||||
|
||||
#include <my_global.h>
|
||||
#include <my_sys.h>
|
||||
#include <signal.h>
|
||||
#include <m_string.h>
|
||||
|
||||
#ifdef __WIN__
|
||||
#define NEWLINE_LEN 2
|
||||
#else
|
||||
#define NEWLINE_LEN 1
|
||||
#endif
|
||||
#include <signal.h>
|
||||
|
||||
#include "buffer.h"
|
||||
#include "instance.h"
|
||||
#include "log.h"
|
||||
#include "parse_output.h"
|
||||
#include "priv.h"
|
||||
|
||||
|
||||
/* Create "mysqld ..." command in the buffer */
|
||||
|
||||
static inline int create_mysqld_command(Buffer *buf,
|
||||
const char *mysqld_path_str,
|
||||
uint mysqld_path_len,
|
||||
const char *option,
|
||||
uint option_len)
|
||||
const LEX_STRING *mysqld_path,
|
||||
const LEX_STRING *option)
|
||||
{
|
||||
int position= 0;
|
||||
|
||||
@ -49,13 +46,13 @@ static inline int create_mysqld_command(Buffer *buf,
|
||||
#ifdef __WIN__
|
||||
buf->append(position++, "\"", 1);
|
||||
#endif
|
||||
buf->append(position, mysqld_path_str, mysqld_path_len);
|
||||
position+= mysqld_path_len;
|
||||
buf->append(position, mysqld_path->str, mysqld_path->length);
|
||||
position+= mysqld_path->length;
|
||||
#ifdef __WIN__
|
||||
buf->append(position++, "\"", 1);
|
||||
#endif
|
||||
/* here the '\0' character is copied from the option string */
|
||||
buf->append(position, option, option_len);
|
||||
buf->append(position, option->str, option->length + 1);
|
||||
|
||||
return buf->is_error();
|
||||
}
|
||||
@ -63,6 +60,39 @@ static inline int create_mysqld_command(Buffer *buf,
|
||||
}
|
||||
|
||||
|
||||
bool Instance_options::is_option_im_specific(const char *option_name)
|
||||
{
|
||||
static const char *IM_SPECIFIC_OPTIONS[] =
|
||||
{
|
||||
"nonguarded",
|
||||
"mysqld-path",
|
||||
"shutdown-delay",
|
||||
NULL
|
||||
};
|
||||
|
||||
for (int i= 0; IM_SPECIFIC_OPTIONS[i]; ++i)
|
||||
{
|
||||
if (!strcmp(option_name, IM_SPECIFIC_OPTIONS[i]))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
Instance_options::Instance_options()
|
||||
:mysqld_version(NULL), mysqld_socket(NULL), mysqld_datadir(NULL),
|
||||
mysqld_pid_file(NULL), mysqld_port(NULL), mysqld_port_val(0),
|
||||
nonguarded(NULL), shutdown_delay(NULL), shutdown_delay_val(0),
|
||||
filled_default_options(0)
|
||||
{
|
||||
mysqld_path.str= NULL;
|
||||
mysqld_path.length= 0;
|
||||
|
||||
memset(logs, 0, sizeof(logs));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Get compiled-in value of default_option
|
||||
|
||||
@ -86,13 +116,13 @@ int Instance_options::get_default_option(char *result, size_t result_len,
|
||||
const char *option_name)
|
||||
{
|
||||
int rc= 1;
|
||||
char verbose_option[]= " --no-defaults --verbose --help";
|
||||
LEX_STRING verbose_option=
|
||||
{ C_STRING_WITH_SIZE(" --no-defaults --verbose --help") };
|
||||
|
||||
/* reserve space fot the path + option + final '\0' */
|
||||
Buffer cmd(mysqld_path_len + sizeof(verbose_option));
|
||||
/* reserve space for the path + option + final '\0' */
|
||||
Buffer cmd(mysqld_path.length + verbose_option.length + 1);
|
||||
|
||||
if (create_mysqld_command(&cmd, mysqld_path, mysqld_path_len,
|
||||
verbose_option, sizeof(verbose_option)))
|
||||
if (create_mysqld_command(&cmd, &mysqld_path, &verbose_option))
|
||||
goto err;
|
||||
|
||||
/* +2 eats first "--" from the option string (E.g. "--datadir") */
|
||||
@ -120,21 +150,19 @@ err:
|
||||
|
||||
int Instance_options::fill_instance_version()
|
||||
{
|
||||
enum { MAX_VERSION_STRING_LENGTH= 160 };
|
||||
char result[MAX_VERSION_STRING_LENGTH];
|
||||
char version_option[]= " --no-defaults --version";
|
||||
char result[MAX_VERSION_LENGTH];
|
||||
LEX_STRING version_option=
|
||||
{ C_STRING_WITH_SIZE(" --no-defaults --version") };
|
||||
int rc= 1;
|
||||
Buffer cmd(mysqld_path_len + sizeof(version_option));
|
||||
Buffer cmd(mysqld_path.length + version_option.length + 1);
|
||||
|
||||
if (create_mysqld_command(&cmd, mysqld_path, mysqld_path_len,
|
||||
version_option, sizeof(version_option)))
|
||||
if (create_mysqld_command(&cmd, &mysqld_path, &version_option))
|
||||
goto err;
|
||||
|
||||
bzero(result, MAX_VERSION_STRING_LENGTH);
|
||||
bzero(result, MAX_VERSION_LENGTH);
|
||||
|
||||
rc= parse_output_and_get_value(cmd.buffer, "Ver",
|
||||
result, MAX_VERSION_STRING_LENGTH,
|
||||
GET_LINE);
|
||||
rc= parse_output_and_get_value(cmd.buffer, "Ver", result,
|
||||
MAX_VERSION_LENGTH, GET_LINE);
|
||||
|
||||
if (*result != '\0')
|
||||
{
|
||||
@ -145,6 +173,7 @@ int Instance_options::fill_instance_version()
|
||||
start= result;
|
||||
while (my_isspace(default_charset_info, *start))
|
||||
++start;
|
||||
|
||||
mysqld_version= strdup_root(&alloc, start);
|
||||
}
|
||||
err:
|
||||
@ -200,8 +229,7 @@ int Instance_options::fill_log_options()
|
||||
else
|
||||
{
|
||||
/* below is safe, as --datadir always has a value */
|
||||
strmake(datadir,
|
||||
strchr(mysqld_datadir, '=') + 1, MAX_LOG_OPTION_LENGTH - 1);
|
||||
strmake(datadir, mysqld_datadir, MAX_LOG_OPTION_LENGTH - 1);
|
||||
}
|
||||
|
||||
if (gethostname(hostname,sizeof(hostname)-1) < 0)
|
||||
@ -287,7 +315,6 @@ err:
|
||||
|
||||
int Instance_options::get_pid_filename(char *result)
|
||||
{
|
||||
const char *pid_file= mysqld_pid_file;
|
||||
char datadir[MAX_PATH_LEN];
|
||||
|
||||
if (mysqld_datadir == NULL)
|
||||
@ -297,14 +324,10 @@ int Instance_options::get_pid_filename(char *result)
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
strxnmov(datadir, MAX_PATH_LEN - 1, strchr(mysqld_datadir, '=') + 1,
|
||||
"/", NullS);
|
||||
|
||||
DBUG_ASSERT(mysqld_pid_file);
|
||||
pid_file= strchr(pid_file, '=') + 1;
|
||||
strxnmov(datadir, MAX_PATH_LEN - 1, mysqld_datadir, "/", NullS);
|
||||
|
||||
/* get the full path to the pidfile */
|
||||
my_load_path(result, pid_file, datadir);
|
||||
my_load_path(result, mysqld_pid_file, datadir);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -333,23 +356,22 @@ pid_t Instance_options::get_pid()
|
||||
}
|
||||
|
||||
|
||||
int Instance_options::complete_initialization(const char *default_path,
|
||||
uint instance_type)
|
||||
int Instance_options::complete_initialization(const char *default_path)
|
||||
{
|
||||
const char *tmp;
|
||||
char *end;
|
||||
|
||||
if (!mysqld_path && !(mysqld_path= strdup_root(&alloc, default_path)))
|
||||
if (!mysqld_path.str && !(mysqld_path.str= strdup_root(&alloc, default_path)))
|
||||
goto err;
|
||||
|
||||
// it's safe to cast this to char* since this is a buffer we are allocating
|
||||
end= convert_dirname((char*)mysqld_path, mysqld_path, NullS);
|
||||
end= convert_dirname((char*)mysqld_path.str, mysqld_path.str, NullS);
|
||||
end[-1]= 0;
|
||||
|
||||
mysqld_path_len= strlen(mysqld_path);
|
||||
mysqld_path.length= strlen(mysqld_path.str);
|
||||
|
||||
if (mysqld_port)
|
||||
mysqld_port_val= atoi(strchr(mysqld_port, '=') + 1);
|
||||
mysqld_port_val= atoi(mysqld_port);
|
||||
|
||||
if (shutdown_delay)
|
||||
shutdown_delay_val= atoi(shutdown_delay);
|
||||
@ -357,7 +379,7 @@ int Instance_options::complete_initialization(const char *default_path,
|
||||
if (!(tmp= strdup_root(&alloc, "--no-defaults")))
|
||||
goto err;
|
||||
|
||||
if (!(mysqld_pid_file))
|
||||
if (!mysqld_pid_file)
|
||||
{
|
||||
char pidfilename[MAX_PATH_LEN];
|
||||
char hostname[MAX_PATH_LEN];
|
||||
@ -366,26 +388,27 @@ int Instance_options::complete_initialization(const char *default_path,
|
||||
If we created only one istance [mysqld], because no config. files were
|
||||
found, we would like to model mysqld pid file values.
|
||||
*/
|
||||
|
||||
if (!gethostname(hostname, sizeof(hostname) - 1))
|
||||
{
|
||||
if (instance_type & DEFAULT_SINGLE_INSTANCE)
|
||||
strxnmov(pidfilename, MAX_PATH_LEN - 1, "--pid-file=", hostname,
|
||||
".pid", NullS);
|
||||
if (Instance::is_mysqld_compatible_name(&instance_name))
|
||||
strxnmov(pidfilename, MAX_PATH_LEN - 1, hostname, ".pid", NullS);
|
||||
else
|
||||
strxnmov(pidfilename, MAX_PATH_LEN - 1, "--pid-file=", instance_name,
|
||||
"-", hostname, ".pid", NullS);
|
||||
strxnmov(pidfilename, MAX_PATH_LEN - 1, instance_name.str, "-",
|
||||
hostname, ".pid", NullS);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (instance_type & DEFAULT_SINGLE_INSTANCE)
|
||||
strxnmov(pidfilename, MAX_PATH_LEN - 1, "--pid-file=", "mysql",
|
||||
".pid", NullS);
|
||||
if (Instance::is_mysqld_compatible_name(&instance_name))
|
||||
strxnmov(pidfilename, MAX_PATH_LEN - 1, "mysql", ".pid", NullS);
|
||||
else
|
||||
strxnmov(pidfilename, MAX_PATH_LEN - 1, "--pid-file=", instance_name,
|
||||
".pid", NullS);
|
||||
strxnmov(pidfilename, MAX_PATH_LEN - 1, instance_name.str, ".pid",
|
||||
NullS);
|
||||
}
|
||||
|
||||
add_option(pidfilename);
|
||||
Named_value option((char *) "pid-file", pidfilename);
|
||||
|
||||
set_option(&option);
|
||||
}
|
||||
|
||||
if (get_pid_filename(pid_file_with_path))
|
||||
@ -393,20 +416,37 @@ int Instance_options::complete_initialization(const char *default_path,
|
||||
|
||||
/* we need to reserve space for the final zero + possible default options */
|
||||
if (!(argv= (char**)
|
||||
alloc_root(&alloc, (options_array.elements + 1
|
||||
alloc_root(&alloc, (get_num_options() + 1
|
||||
+ MAX_NUMBER_OF_DEFAULT_OPTIONS) * sizeof(char*))))
|
||||
goto err;
|
||||
filled_default_options= 0;
|
||||
|
||||
/* the path must be first in the argv */
|
||||
if (add_to_argv(mysqld_path))
|
||||
if (add_to_argv(mysqld_path.str))
|
||||
goto err;
|
||||
|
||||
if (add_to_argv(tmp))
|
||||
goto err;
|
||||
|
||||
memcpy((gptr) (argv + filled_default_options), options_array.buffer,
|
||||
options_array.elements*sizeof(char*));
|
||||
argv[filled_default_options + options_array.elements]= 0;
|
||||
int arg_idx= filled_default_options;
|
||||
for (int opt_idx= 0; opt_idx < get_num_options(); ++opt_idx)
|
||||
{
|
||||
char option_str[MAX_OPTION_STR_LEN];
|
||||
Named_value option= get_option(opt_idx);
|
||||
|
||||
if (is_option_im_specific(option.get_name()))
|
||||
continue;
|
||||
|
||||
char *ptr= strxnmov(option_str, MAX_OPTION_LEN + 3, "--", option.get_name(),
|
||||
NullS);
|
||||
|
||||
if (option.get_value()[0])
|
||||
strxnmov(ptr, MAX_OPTION_LEN + 2, "=", option.get_value(), NullS);
|
||||
|
||||
argv[arg_idx++]= strdup_root(&alloc, option_str);
|
||||
}
|
||||
|
||||
argv[arg_idx]= 0;
|
||||
|
||||
if (fill_log_options() || fill_instance_version())
|
||||
goto err;
|
||||
@ -418,75 +458,91 @@ err:
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Assigns given value to the appropriate option from the class.
|
||||
|
||||
SYNOPSYS
|
||||
add_option()
|
||||
option string with the option prefixed by --
|
||||
|
||||
DESCRIPTION
|
||||
|
||||
The method is called from the option handling routine.
|
||||
|
||||
RETURN
|
||||
0 - ok
|
||||
1 - error occured
|
||||
*/
|
||||
|
||||
int Instance_options::add_option(const char* option)
|
||||
bool Instance_options::set_option(Named_value *option)
|
||||
{
|
||||
char *tmp;
|
||||
enum { SAVE_VALUE= 1, SAVE_WHOLE, SAVE_WHOLE_AND_ADD };
|
||||
struct selected_options_st
|
||||
bool err_status;
|
||||
int idx= find_option(option->get_name());
|
||||
char *option_name_str;
|
||||
char *option_value_str;
|
||||
|
||||
if (!(option_name_str= Named_value::alloc_str(option->get_name())))
|
||||
return TRUE;
|
||||
|
||||
if (!(option_value_str= Named_value::alloc_str(option->get_value())))
|
||||
{
|
||||
Named_value::free_str(&option_name_str);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
Named_value option_copy(option_name_str, option_value_str);
|
||||
|
||||
if (idx < 0)
|
||||
err_status= options.add_element(&option_copy);
|
||||
else
|
||||
err_status= options.replace_element(idx, &option_copy);
|
||||
|
||||
if (!err_status)
|
||||
update_var(option_copy.get_name(), option_copy.get_value());
|
||||
else
|
||||
option_copy.free();
|
||||
|
||||
return err_status;
|
||||
}
|
||||
|
||||
|
||||
void Instance_options::unset_option(const char *option_name)
|
||||
{
|
||||
int idx= find_option(option_name);
|
||||
|
||||
if (idx < 0)
|
||||
return; /* the option has not been set. */
|
||||
|
||||
options.remove_element(idx);
|
||||
|
||||
update_var(option_name, NULL);
|
||||
}
|
||||
|
||||
|
||||
void Instance_options::update_var(const char *option_name,
|
||||
const char *option_value)
|
||||
{
|
||||
struct options_st
|
||||
{
|
||||
const char *name;
|
||||
uint length;
|
||||
const char **value;
|
||||
uint type;
|
||||
} options[]=
|
||||
uint name_len;
|
||||
const char **var;
|
||||
} options_def[]=
|
||||
{
|
||||
{"--socket=", 9, &mysqld_socket, SAVE_WHOLE_AND_ADD},
|
||||
{"--port=", 7, &mysqld_port, SAVE_WHOLE_AND_ADD},
|
||||
{"--datadir=", 10, &mysqld_datadir, SAVE_WHOLE_AND_ADD},
|
||||
{"--bind-address=", 15, &mysqld_bind_address, SAVE_WHOLE_AND_ADD},
|
||||
{"--pid-file=", 11, &mysqld_pid_file, SAVE_WHOLE_AND_ADD},
|
||||
{"--mysqld-path=", 14, &mysqld_path, SAVE_VALUE},
|
||||
{"--nonguarded", 9, &nonguarded, SAVE_WHOLE},
|
||||
{"--shutdown_delay", 9, &shutdown_delay, SAVE_VALUE},
|
||||
{NULL, 0, NULL, 0}
|
||||
{"socket", 6, &mysqld_socket},
|
||||
{"port", 4, &mysqld_port},
|
||||
{"datadir", 7, &mysqld_datadir},
|
||||
{"pid-file", 8, &mysqld_pid_file},
|
||||
{"nonguarded", 10, &nonguarded},
|
||||
{"mysqld-path", 11, (const char **) &mysqld_path.str},
|
||||
{"shutdown-delay", 14, &shutdown_delay},
|
||||
{NULL, 0, NULL}
|
||||
};
|
||||
struct selected_options_st *selected_options;
|
||||
|
||||
if (!(tmp= strdup_root(&alloc, option)))
|
||||
goto err;
|
||||
for (options_st *opt= options_def; opt->name; ++opt)
|
||||
{
|
||||
if (!strncmp(opt->name, option_name, opt->name_len))
|
||||
{
|
||||
*(opt->var)= option_value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (selected_options= options; selected_options->name; selected_options++)
|
||||
{
|
||||
if (strncmp(tmp, selected_options->name, selected_options->length) == 0)
|
||||
switch (selected_options->type) {
|
||||
case SAVE_WHOLE_AND_ADD:
|
||||
*(selected_options->value)= tmp;
|
||||
insert_dynamic(&options_array,(gptr) &tmp);
|
||||
return 0;
|
||||
case SAVE_VALUE:
|
||||
*(selected_options->value)= strchr(tmp, '=') + 1;
|
||||
return 0;
|
||||
case SAVE_WHOLE:
|
||||
*(selected_options->value)= tmp;
|
||||
return 0;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* if we haven't returned earlier we should just save the option */
|
||||
insert_dynamic(&options_array,(gptr) &tmp);
|
||||
int Instance_options::find_option(const char *option_name)
|
||||
{
|
||||
for (int i= 0; i < get_num_options(); i++)
|
||||
{
|
||||
if (!strcmp(get_option(i).get_name(), option_name))
|
||||
return i;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
return 1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
@ -504,7 +560,10 @@ int Instance_options::add_to_argv(const char* option)
|
||||
void Instance_options::print_argv()
|
||||
{
|
||||
int i;
|
||||
printf("printing out an instance %s argv:\n", instance_name);
|
||||
|
||||
printf("printing out an instance %s argv:\n",
|
||||
(const char *) instance_name.str);
|
||||
|
||||
for (i=0; argv[i] != NULL; i++)
|
||||
printf("argv: %s\n", argv[i]);
|
||||
}
|
||||
@ -515,17 +574,17 @@ void Instance_options::print_argv()
|
||||
Return value: 0 - ok. 1 - unable to allocate memory.
|
||||
*/
|
||||
|
||||
int Instance_options::init(const char *instance_name_arg)
|
||||
int Instance_options::init(const LEX_STRING *instance_name_arg)
|
||||
{
|
||||
instance_name_len= strlen(instance_name_arg);
|
||||
instance_name.length= instance_name_arg->length;
|
||||
|
||||
init_alloc_root(&alloc, MEM_ROOT_BLOCK_SIZE, 0);
|
||||
|
||||
if (my_init_dynamic_array(&options_array, sizeof(char*), 0, 32))
|
||||
if (options.init())
|
||||
goto err;
|
||||
|
||||
if (!(instance_name= strmake_root(&alloc, (char*) instance_name_arg,
|
||||
instance_name_len)))
|
||||
if (!(instance_name.str= strmake_root(&alloc, instance_name_arg->str,
|
||||
instance_name_arg->length)))
|
||||
goto err;
|
||||
|
||||
return 0;
|
||||
@ -538,6 +597,4 @@ err:
|
||||
Instance_options::~Instance_options()
|
||||
{
|
||||
free_root(&alloc, MYF(0));
|
||||
delete_dynamic(&options_array);
|
||||
}
|
||||
|
||||
|
@ -18,8 +18,8 @@
|
||||
|
||||
#include <my_global.h>
|
||||
#include <my_sys.h>
|
||||
|
||||
#include "parse.h"
|
||||
#include "portability.h"
|
||||
|
||||
#if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE)
|
||||
#pragma interface
|
||||
@ -35,24 +35,26 @@
|
||||
don't have to synchronize between threads.
|
||||
*/
|
||||
|
||||
#define USUAL_INSTANCE 0
|
||||
#define DEFAULT_SINGLE_INSTANCE 1
|
||||
|
||||
class Instance_options
|
||||
{
|
||||
public:
|
||||
Instance_options() :
|
||||
mysqld_version(0), mysqld_socket(0), mysqld_datadir(0),
|
||||
mysqld_bind_address(0), mysqld_pid_file(0), mysqld_port(0),
|
||||
mysqld_port_val(0), mysqld_path(0), nonguarded(0), shutdown_delay(0),
|
||||
shutdown_delay_val(0), filled_default_options(0)
|
||||
{}
|
||||
/* The operation is used to check if the option is IM-specific or not. */
|
||||
static bool is_option_im_specific(const char *option_name);
|
||||
|
||||
public:
|
||||
Instance_options();
|
||||
~Instance_options();
|
||||
/* fills in argv */
|
||||
int complete_initialization(const char *default_path, uint instance_type);
|
||||
int complete_initialization(const char *default_path);
|
||||
|
||||
int add_option(const char* option);
|
||||
int init(const char *instance_name_arg);
|
||||
bool set_option(Named_value *option);
|
||||
void unset_option(const char *option_name);
|
||||
|
||||
inline int get_num_options() const;
|
||||
inline Named_value get_option(int idx) const;
|
||||
|
||||
public:
|
||||
int init(const LEX_STRING *instance_name_arg);
|
||||
pid_t get_pid();
|
||||
int get_pid_filename(char *result);
|
||||
int unlink_pidfile();
|
||||
@ -65,7 +67,6 @@ public:
|
||||
*/
|
||||
enum { MAX_PATH_LEN= 512 };
|
||||
enum { MAX_NUMBER_OF_DEFAULT_OPTIONS= 2 };
|
||||
enum { MEM_ROOT_BLOCK_SIZE= 512 };
|
||||
char pid_file_with_path[MAX_PATH_LEN];
|
||||
char **argv;
|
||||
/*
|
||||
@ -76,31 +77,44 @@ public:
|
||||
/* We need the some options, so we store them as a separate pointers */
|
||||
const char *mysqld_socket;
|
||||
const char *mysqld_datadir;
|
||||
const char *mysqld_bind_address;
|
||||
const char *mysqld_pid_file;
|
||||
const char *mysqld_port;
|
||||
uint mysqld_port_val;
|
||||
const char *instance_name;
|
||||
uint instance_name_len;
|
||||
const char *mysqld_path;
|
||||
uint mysqld_path_len;
|
||||
LEX_STRING instance_name;
|
||||
LEX_STRING mysqld_path;
|
||||
const char *nonguarded;
|
||||
const char *shutdown_delay;
|
||||
uint shutdown_delay_val;
|
||||
/* log enums are defined in parse.h */
|
||||
char *logs[3];
|
||||
|
||||
/* this value is computed and cashed here */
|
||||
DYNAMIC_ARRAY options_array;
|
||||
private:
|
||||
int fill_log_options();
|
||||
int fill_instance_version();
|
||||
int add_to_argv(const char *option);
|
||||
int get_default_option(char *result, size_t result_len,
|
||||
const char *option_name);
|
||||
|
||||
void update_var(const char *option_name, const char *option_value);
|
||||
int find_option(const char *option_name);
|
||||
|
||||
private:
|
||||
uint filled_default_options;
|
||||
MEM_ROOT alloc;
|
||||
|
||||
Named_value_arr options;
|
||||
};
|
||||
|
||||
|
||||
inline int Instance_options::get_num_options() const
|
||||
{
|
||||
return options.get_size();
|
||||
}
|
||||
|
||||
|
||||
inline Named_value Instance_options::get_option(int idx) const
|
||||
{
|
||||
return options.get_element(idx);
|
||||
}
|
||||
|
||||
#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_INSTANCE_OPTIONS_H */
|
||||
|
@ -19,21 +19,23 @@
|
||||
#endif
|
||||
|
||||
#include "listener.h"
|
||||
#include "priv.h"
|
||||
#include <m_string.h>
|
||||
|
||||
#include <my_global.h>
|
||||
#include <mysql.h>
|
||||
#include <violite.h>
|
||||
|
||||
#include <sys/stat.h>
|
||||
#ifndef __WIN__
|
||||
#include <sys/un.h>
|
||||
#endif
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "thread_registry.h"
|
||||
#include "options.h"
|
||||
#include "instance_map.h"
|
||||
#include "log.h"
|
||||
#include "mysql_connection.h"
|
||||
#include "options.h"
|
||||
#include "portability.h"
|
||||
#include "priv.h"
|
||||
#include "thread_registry.h"
|
||||
|
||||
|
||||
/*
|
||||
@ -62,8 +64,7 @@ private:
|
||||
|
||||
|
||||
Listener_thread::Listener_thread(const Listener_thread_args &args) :
|
||||
Listener_thread_args(args.thread_registry, args.options, args.user_map,
|
||||
args.instance_map)
|
||||
Listener_thread_args(args.thread_registry, args.user_map, args.instance_map)
|
||||
,total_connection_count(0)
|
||||
,thread_info(pthread_self())
|
||||
,num_sockets(0)
|
||||
@ -234,14 +235,16 @@ int Listener_thread::create_tcp_socket()
|
||||
bzero(&ip_socket_address, sizeof(ip_socket_address));
|
||||
|
||||
ulong im_bind_addr;
|
||||
if (options.bind_address != 0)
|
||||
if (Options::Main::bind_address != 0)
|
||||
{
|
||||
if ((im_bind_addr= (ulong) inet_addr(options.bind_address)) == INADDR_NONE)
|
||||
im_bind_addr= (ulong) inet_addr(Options::Main::bind_address);
|
||||
|
||||
if (im_bind_addr == INADDR_NONE)
|
||||
im_bind_addr= htonl(INADDR_ANY);
|
||||
}
|
||||
else
|
||||
im_bind_addr= htonl(INADDR_ANY);
|
||||
uint im_port= options.port_number;
|
||||
uint im_port= Options::Main::port_number;
|
||||
|
||||
ip_socket_address.sin_family= AF_INET;
|
||||
ip_socket_address.sin_addr.s_addr= im_bind_addr;
|
||||
@ -295,7 +298,7 @@ create_unix_socket(struct sockaddr_un &unix_socket_address)
|
||||
bzero(&unix_socket_address, sizeof(unix_socket_address));
|
||||
|
||||
unix_socket_address.sun_family= AF_UNIX;
|
||||
strmake(unix_socket_address.sun_path, options.socket_file_name,
|
||||
strmake(unix_socket_address.sun_path, Options::Main::socket_file_name,
|
||||
sizeof(unix_socket_address.sun_path));
|
||||
unlink(unix_socket_address.sun_path); // in case we have stale socket file
|
||||
|
||||
|
@ -27,23 +27,19 @@
|
||||
pthread_handler_t listener(void *arg);
|
||||
|
||||
class Thread_registry;
|
||||
struct Options;
|
||||
class User_map;
|
||||
class Instance_map;
|
||||
|
||||
struct Listener_thread_args
|
||||
{
|
||||
Thread_registry &thread_registry;
|
||||
const Options &options;
|
||||
const User_map &user_map;
|
||||
Instance_map &instance_map;
|
||||
|
||||
Listener_thread_args(Thread_registry &thread_registry_arg,
|
||||
const Options &options_arg,
|
||||
const User_map &user_map_arg,
|
||||
Instance_map &instance_map_arg) :
|
||||
thread_registry(thread_registry_arg)
|
||||
,options(options_arg)
|
||||
,user_map(user_map_arg)
|
||||
,instance_map(instance_map_arg)
|
||||
{}
|
||||
|
@ -14,14 +14,14 @@
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
#include <my_global.h>
|
||||
|
||||
#include "log.h"
|
||||
#include "portability.h"
|
||||
#include <stdarg.h>
|
||||
|
||||
#include <my_global.h>
|
||||
#include <m_string.h>
|
||||
#include <my_sys.h>
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
/*
|
||||
TODO:
|
||||
- add flexible header support
|
||||
@ -71,7 +71,7 @@ static inline void log(FILE *file, const char *format, va_list args)
|
||||
{
|
||||
int size= sizeof(buff_stack) * 2;
|
||||
buff_msg= (char*) my_malloc(size, MYF(0));
|
||||
while (true)
|
||||
while (TRUE)
|
||||
{
|
||||
if (buff_msg == 0)
|
||||
{
|
||||
|
@ -14,39 +14,55 @@
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
#include <my_global.h>
|
||||
#include "manager.h"
|
||||
|
||||
#include "priv.h"
|
||||
#include "thread_registry.h"
|
||||
#include "listener.h"
|
||||
#include "instance_map.h"
|
||||
#include "options.h"
|
||||
#include "user_map.h"
|
||||
#include "log.h"
|
||||
#include "guardian.h"
|
||||
|
||||
#include <my_sys.h>
|
||||
#include <my_global.h>
|
||||
#include <m_string.h>
|
||||
#include <signal.h>
|
||||
#include <my_sys.h>
|
||||
#include <thr_alarm.h>
|
||||
|
||||
#include <signal.h>
|
||||
#ifndef __WIN__
|
||||
#include <sys/wait.h>
|
||||
#endif
|
||||
|
||||
#include "exit_codes.h"
|
||||
#include "guardian.h"
|
||||
#include "instance_map.h"
|
||||
#include "listener.h"
|
||||
#include "log.h"
|
||||
#include "options.h"
|
||||
#include "priv.h"
|
||||
#include "thread_registry.h"
|
||||
#include "user_map.h"
|
||||
|
||||
|
||||
static int create_pid_file(const char *pid_file_name)
|
||||
{
|
||||
if (FILE *pid_file= my_fopen(pid_file_name,
|
||||
O_WRONLY | O_CREAT | O_BINARY, MYF(0)))
|
||||
FILE *pid_file;
|
||||
|
||||
if (!(pid_file= my_fopen(pid_file_name, O_WRONLY | O_CREAT | O_BINARY,
|
||||
MYF(0))))
|
||||
{
|
||||
fprintf(pid_file, "%d\n", (int) getpid());
|
||||
my_fclose(pid_file, MYF(0));
|
||||
return 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;
|
||||
}
|
||||
log_error("can't create pid file %s: errno=%d, %s",
|
||||
pid_file_name, errno, strerror(errno));
|
||||
return 1;
|
||||
|
||||
if (fprintf(pid_file, "%d\n", (int) getpid()) <= 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;
|
||||
}
|
||||
|
||||
#ifndef __WIN__
|
||||
@ -82,14 +98,14 @@ bool have_signal;
|
||||
|
||||
void onsignal(int signo)
|
||||
{
|
||||
have_signal= true;
|
||||
have_signal= TRUE;
|
||||
}
|
||||
|
||||
void set_signals(sigset_t *set)
|
||||
{
|
||||
signal(SIGINT, onsignal);
|
||||
signal(SIGTERM, onsignal);
|
||||
have_signal= false;
|
||||
have_signal= FALSE;
|
||||
}
|
||||
|
||||
int my_sigwait(const sigset_t *set, int *sig)
|
||||
@ -109,10 +125,15 @@ int my_sigwait(const sigset_t *set, int *sig)
|
||||
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(const Options &options)
|
||||
void manager()
|
||||
{
|
||||
int err_code;
|
||||
const char *err_msg;
|
||||
|
||||
Thread_registry thread_registry;
|
||||
/*
|
||||
All objects created in the manager() function live as long as
|
||||
@ -121,26 +142,55 @@ void manager(const Options &options)
|
||||
*/
|
||||
|
||||
User_map user_map;
|
||||
Instance_map instance_map(options.default_mysqld_path);
|
||||
Instance_map instance_map(Options::Main::default_mysqld_path);
|
||||
Guardian_thread guardian_thread(thread_registry,
|
||||
&instance_map,
|
||||
options.monitoring_interval);
|
||||
Options::Main::monitoring_interval);
|
||||
|
||||
Listener_thread_args listener_args(thread_registry, options, user_map,
|
||||
instance_map);
|
||||
Listener_thread_args listener_args(thread_registry, user_map, instance_map);
|
||||
|
||||
manager_pid= getpid();
|
||||
instance_map.guardian= &guardian_thread;
|
||||
|
||||
if (instance_map.init() || user_map.init())
|
||||
return;
|
||||
/* Initialize instance map. */
|
||||
|
||||
if (user_map.load(options.password_file_name))
|
||||
if (instance_map.init())
|
||||
{
|
||||
log_error("Error: can not initialize instance list: out of memory.");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Initialize user map and load password file. */
|
||||
|
||||
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 == ERR_PASSWORD_FILE_DOES_NOT_EXIST &&
|
||||
Options::Main::mysqld_safe_compatible)
|
||||
{
|
||||
/*
|
||||
The password file does not exist, but we are running in
|
||||
mysqld_safe-compatible mode. Continue, but complain in log.
|
||||
*/
|
||||
|
||||
log_error("Warning: password file does not exist, "
|
||||
"nobody will be able to connect to Instance Manager.");
|
||||
}
|
||||
else
|
||||
{
|
||||
log_error("Error: %s.", (const char *) err_msg);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* write pid file */
|
||||
if (create_pid_file(options.pid_file_name))
|
||||
return;
|
||||
if (create_pid_file(Options::Main::pid_file_name))
|
||||
return; /* necessary logging has been already done. */
|
||||
|
||||
sigset_t mask;
|
||||
set_signals(&mask);
|
||||
@ -198,7 +248,15 @@ void manager(const Options &options)
|
||||
|
||||
shutdown_complete= FALSE;
|
||||
|
||||
if (instance_map.flush_instances())
|
||||
instance_map.guardian->lock();
|
||||
instance_map.lock();
|
||||
|
||||
int flush_instances_status= instance_map.flush_instances();
|
||||
|
||||
instance_map.unlock();
|
||||
instance_map.guardian->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 "
|
||||
@ -240,7 +298,7 @@ void manager(const Options &options)
|
||||
{
|
||||
if (!guardian_thread.is_stopped())
|
||||
{
|
||||
bool stop_instances= true;
|
||||
bool stop_instances= TRUE;
|
||||
guardian_thread.request_shutdown(stop_instances);
|
||||
pthread_cond_signal(&guardian_thread.COND_guardian);
|
||||
}
|
||||
@ -254,7 +312,7 @@ void manager(const Options &options)
|
||||
|
||||
err:
|
||||
/* delete the pid file */
|
||||
my_delete(options.pid_file_name, MYF(0));
|
||||
my_delete(Options::Main::pid_file_name, MYF(0));
|
||||
|
||||
#ifndef __WIN__
|
||||
/* free alarm structures */
|
||||
@ -262,4 +320,3 @@ err:
|
||||
/* don't pthread_exit to kill all threads who did not shut down in time */
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -16,8 +16,6 @@
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
struct Options;
|
||||
|
||||
void manager(const Options &options);
|
||||
void manager();
|
||||
|
||||
#endif // INCLUDES_MYSQL_INSTANCE_MANAGER_MANAGER_H
|
||||
|
@ -14,15 +14,14 @@
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
#include <my_global.h>
|
||||
#include "messages.h"
|
||||
|
||||
#include <my_global.h>
|
||||
#include <mysql_com.h>
|
||||
|
||||
#include "mysqld_error.h"
|
||||
#include "mysql_manager_error.h"
|
||||
|
||||
#include <mysql_com.h>
|
||||
#include <assert.h>
|
||||
|
||||
|
||||
static const char *mysqld_error_message(unsigned sql_errno)
|
||||
{
|
||||
@ -70,6 +69,23 @@ static const char *mysqld_error_message(unsigned sql_errno)
|
||||
"in the instance options";
|
||||
case ER_ACCESS_OPTION_FILE:
|
||||
return "Cannot open the option file to edit. Check permissions";
|
||||
case ER_DROP_ACTIVE_INSTANCE:
|
||||
return "Cannot drop an active instance. You should stop it first";
|
||||
case ER_CREATE_EXISTING_INSTANCE:
|
||||
return "Instance already exists";
|
||||
case ER_INSTANCE_MISCONFIGURED:
|
||||
return "Instance is misconfigured. Cannot start it";
|
||||
case ER_MALFORMED_INSTANCE_NAME:
|
||||
return "Malformed instance name.";
|
||||
case ER_INSTANCE_IS_ACTIVE:
|
||||
return "The instance is active. Stop the instance first";
|
||||
case ER_THERE_IS_ACTIVE_INSTACE:
|
||||
return "At least one instance is active. Stop all instances first";
|
||||
case ER_INCOMPATIBLE_OPTION:
|
||||
return "Instance Manager-specific options are prohibited from being used "
|
||||
"in the configuration of mysqld-compatible instances";
|
||||
case ER_CONF_FILE_DOES_NOT_EXIST:
|
||||
return "Configuration file does not exist";
|
||||
default:
|
||||
DBUG_ASSERT(0);
|
||||
return 0;
|
||||
|
@ -20,22 +20,24 @@
|
||||
|
||||
#include "mysql_connection.h"
|
||||
|
||||
#include "priv.h"
|
||||
#include "mysql_manager_error.h"
|
||||
#include "mysqld_error.h"
|
||||
#include "thread_registry.h"
|
||||
#include "log.h"
|
||||
#include "user_map.h"
|
||||
#include "protocol.h"
|
||||
#include "messages.h"
|
||||
#include "command.h"
|
||||
#include "parse.h"
|
||||
|
||||
#include <mysql.h>
|
||||
#include <violite.h>
|
||||
#include <mysql_com.h>
|
||||
#include <m_string.h>
|
||||
#include <m_string.h>
|
||||
#include <my_global.h>
|
||||
#include <mysql_com.h>
|
||||
#include <mysql.h>
|
||||
#include <my_sys.h>
|
||||
#include <violite.h>
|
||||
|
||||
#include "command.h"
|
||||
#include "log.h"
|
||||
#include "messages.h"
|
||||
#include "mysqld_error.h"
|
||||
#include "mysql_manager_error.h"
|
||||
#include "parse.h"
|
||||
#include "priv.h"
|
||||
#include "protocol.h"
|
||||
#include "thread_registry.h"
|
||||
#include "user_map.h"
|
||||
|
||||
|
||||
Mysql_connection_thread_args::Mysql_connection_thread_args(
|
||||
@ -56,7 +58,7 @@ Mysql_connection_thread_args::Mysql_connection_thread_args(
|
||||
See also comments in mysqlmanager.cc to picture general Instance Manager
|
||||
architecture.
|
||||
We use conventional technique to work with classes without exceptions:
|
||||
class acquires all vital resource in init(); Thus if init() succeed,
|
||||
class acquires all vital resource in init(); Thus if init() succeed,
|
||||
a user must call cleanup(). All other methods are valid only between
|
||||
init() and cleanup().
|
||||
*/
|
||||
@ -190,8 +192,6 @@ void Mysql_connection_thread::run()
|
||||
int Mysql_connection_thread::check_connection()
|
||||
{
|
||||
ulong pkt_len=0; // to hold client reply length
|
||||
/* maximum size of the version string */
|
||||
enum { MAX_VERSION_LENGTH= 80 };
|
||||
|
||||
/* buffer for the first packet */ /* packet contains: */
|
||||
char buff[MAX_VERSION_LENGTH + 1 + // server version, 0-ended
|
||||
@ -202,8 +202,8 @@ int Mysql_connection_thread::check_connection()
|
||||
char *pos= buff;
|
||||
ulong server_flags;
|
||||
|
||||
memcpy(pos, mysqlmanager_version, mysqlmanager_version_length + 1);
|
||||
pos+= mysqlmanager_version_length + 1;
|
||||
memcpy(pos, mysqlmanager_version.str, mysqlmanager_version.length + 1);
|
||||
pos+= mysqlmanager_version.length + 1;
|
||||
|
||||
int4store((uchar*) pos, connection_id);
|
||||
pos+= 4;
|
||||
@ -271,12 +271,14 @@ int Mysql_connection_thread::check_connection()
|
||||
const char *user= pos;
|
||||
const char *password= strend(user)+1;
|
||||
ulong password_len= *password++;
|
||||
LEX_STRING user_name= { (char *) user, password - user - 2 };
|
||||
|
||||
if (password_len != SCRAMBLE_LENGTH)
|
||||
{
|
||||
net_send_error(&net, ER_ACCESS_DENIED_ERROR);
|
||||
return 1;
|
||||
}
|
||||
if (user_map.authenticate(user, password-user-2, password, scramble))
|
||||
if (user_map.authenticate(&user_name, password, scramble))
|
||||
{
|
||||
net_send_error(&net, ER_ACCESS_DENIED_ERROR);
|
||||
return 1;
|
||||
@ -312,7 +314,7 @@ int Mysql_connection_thread::do_command()
|
||||
packet= (char*) net.read_pos;
|
||||
enum enum_server_command command= (enum enum_server_command)
|
||||
(uchar) *packet;
|
||||
log_info("connection %d: packet_length=%d, command=%d",
|
||||
log_info("connection %d: packet_length=%d, command=%d",
|
||||
connection_id, packet_length, command);
|
||||
return dispatch_command(command, packet + 1, packet_length - 1);
|
||||
}
|
||||
@ -336,7 +338,7 @@ int Mysql_connection_thread::dispatch_command(enum enum_server_command command,
|
||||
if (Command *command= parse_command(&instance_map, packet))
|
||||
{
|
||||
int res= 0;
|
||||
log_info("query for connection %d successefully parsed",connection_id);
|
||||
log_info("query for connection %d successfully parsed",connection_id);
|
||||
res= command->execute(&net, connection_id);
|
||||
delete command;
|
||||
if (!res)
|
||||
@ -380,5 +382,5 @@ pthread_handler_t mysql_connection(void *arg)
|
||||
}
|
||||
|
||||
/*
|
||||
vim: fdm=marker
|
||||
vim: fdm=marker
|
||||
*/
|
||||
|
@ -29,5 +29,13 @@
|
||||
#define ER_ACCESS_OPTION_FILE 3008
|
||||
#define ER_OFFSET_ERROR 3009
|
||||
#define ER_READ_FILE 3010
|
||||
#define ER_DROP_ACTIVE_INSTANCE 3011
|
||||
#define ER_CREATE_EXISTING_INSTANCE 3012
|
||||
#define ER_INSTANCE_MISCONFIGURED 3013
|
||||
#define ER_MALFORMED_INSTANCE_NAME 3014
|
||||
#define ER_INSTANCE_IS_ACTIVE 3015
|
||||
#define ER_THERE_IS_ACTIVE_INSTACE 3016
|
||||
#define ER_INCOMPATIBLE_OPTION 3017
|
||||
#define ER_CONF_FILE_DOES_NOT_EXIST 3018
|
||||
|
||||
#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_MYSQL_MANAGER_ERROR_H */
|
||||
|
@ -15,25 +15,29 @@
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
#include <my_global.h>
|
||||
#include "manager.h"
|
||||
|
||||
#include "options.h"
|
||||
#include "log.h"
|
||||
|
||||
#include <my_sys.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#ifndef __WIN__
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
#include <sys/wait.h>
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "log.h"
|
||||
#include "manager.h"
|
||||
#include "options.h"
|
||||
#include "user_management_commands.h"
|
||||
|
||||
#ifdef __WIN__
|
||||
#include "windowsservice.h"
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
Few notes about Instance Manager architecture:
|
||||
Instance Manager consisits of two processes: the angel process, and the
|
||||
@ -59,13 +63,12 @@
|
||||
*/
|
||||
|
||||
static void init_environment(char *progname);
|
||||
|
||||
#ifndef __WIN__
|
||||
static void daemonize(const char *log_file_name);
|
||||
static void angel(const Options &options);
|
||||
static void angel();
|
||||
static struct passwd *check_user(const char *user);
|
||||
static int set_user(const char *user, struct passwd *user_info);
|
||||
#else
|
||||
int HandleServiceOptions(Options options);
|
||||
#endif
|
||||
|
||||
|
||||
@ -81,41 +84,61 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
int return_value= 1;
|
||||
init_environment(argv[0]);
|
||||
Options options;
|
||||
|
||||
if (options.load(argc, argv))
|
||||
goto err;
|
||||
if ((return_value= Options::load(argc, argv)))
|
||||
goto main_end;
|
||||
|
||||
if (Options::User_management::cmd)
|
||||
{
|
||||
return_value= Options::User_management::cmd->execute();
|
||||
|
||||
goto main_end;
|
||||
}
|
||||
|
||||
#ifndef __WIN__
|
||||
|
||||
struct passwd *user_info;
|
||||
|
||||
if ((user_info= check_user(options.user)))
|
||||
if ((user_info= check_user(Options::Daemon::user)))
|
||||
{
|
||||
if (set_user(options.user, user_info))
|
||||
goto err;
|
||||
if (set_user(Options::Daemon::user, user_info))
|
||||
{
|
||||
return_value= 1;
|
||||
goto main_end;
|
||||
}
|
||||
}
|
||||
|
||||
if (options.run_as_service)
|
||||
if (Options::Daemon::run_as_service)
|
||||
{
|
||||
/* forks, and returns only in child */
|
||||
daemonize(options.log_file_name);
|
||||
daemonize(Options::Daemon::log_file_name);
|
||||
/* forks again, and returns only in child: parent becomes angel */
|
||||
angel(options);
|
||||
angel();
|
||||
}
|
||||
|
||||
manager();
|
||||
|
||||
#else
|
||||
if (!options.stand_alone)
|
||||
|
||||
if (!Options::Service::stand_alone)
|
||||
{
|
||||
if (HandleServiceOptions(options))
|
||||
goto err;
|
||||
if (HandleServiceOptions())
|
||||
{
|
||||
return_value= 1;
|
||||
goto main_end;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
manager();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
manager(options);
|
||||
return_value= 0;
|
||||
|
||||
err:
|
||||
options.cleanup();
|
||||
main_end:
|
||||
Options::cleanup();
|
||||
my_end(0);
|
||||
return return_value;
|
||||
}
|
||||
@ -200,7 +223,7 @@ static void init_environment(char *progname)
|
||||
MY_INIT(progname);
|
||||
log_init();
|
||||
umask(0117);
|
||||
srand(time(0));
|
||||
srand((unsigned int) time(0));
|
||||
}
|
||||
|
||||
|
||||
@ -298,7 +321,7 @@ void terminate(int signo)
|
||||
Angel process will exit silently if mysqlmanager exits normally.
|
||||
*/
|
||||
|
||||
static void angel(const Options &options)
|
||||
static void angel()
|
||||
{
|
||||
/* install signal handlers */
|
||||
sigset_t zeromask; // to sigsuspend in parent
|
||||
|
@ -20,45 +20,88 @@
|
||||
|
||||
#include "options.h"
|
||||
|
||||
#include "priv.h"
|
||||
#include "portability.h"
|
||||
#include <my_global.h>
|
||||
#include <my_sys.h>
|
||||
#include <my_getopt.h>
|
||||
#include <m_string.h>
|
||||
#include <mysql_com.h>
|
||||
|
||||
#include "exit_codes.h"
|
||||
#include "log.h"
|
||||
#include "portability.h"
|
||||
#include "priv.h"
|
||||
#include "user_management_commands.h"
|
||||
|
||||
#define QUOTE2(x) #x
|
||||
#define QUOTE(x) QUOTE2(x)
|
||||
|
||||
#ifdef __WIN__
|
||||
char Options::install_as_service;
|
||||
char Options::remove_service;
|
||||
char Options::stand_alone;
|
||||
char windows_config_file[FN_REFLEN];
|
||||
char default_password_file_name[FN_REFLEN];
|
||||
char default_log_file_name[FN_REFLEN];
|
||||
const char *Options::config_file= windows_config_file;
|
||||
#else
|
||||
char Options::run_as_service;
|
||||
const char *Options::user= 0; /* No default value */
|
||||
const char *default_password_file_name= QUOTE(DEFAULT_PASSWORD_FILE_NAME);
|
||||
const char *default_log_file_name= QUOTE(DEFAULT_LOG_FILE_NAME);
|
||||
const char *Options::config_file= QUOTE(DEFAULT_CONFIG_FILE);
|
||||
|
||||
/* Define holders for default values. */
|
||||
|
||||
static char win_dflt_config_file_name[FN_REFLEN];
|
||||
static char win_dflt_password_file_name[FN_REFLEN];
|
||||
static char win_dflt_pid_file_name[FN_REFLEN];
|
||||
static char win_dflt_socket_file_name[FN_REFLEN];
|
||||
|
||||
static char win_dflt_mysqld_path[FN_REFLEN];
|
||||
|
||||
/* Define and initialize Windows-specific options. */
|
||||
|
||||
my_bool Options::Service::install_as_service;
|
||||
my_bool Options::Service::remove_service;
|
||||
my_bool Options::Service::stand_alone;
|
||||
|
||||
const char *Options::Main::config_file= win_dflt_config_file_name;
|
||||
const char *Options::Main::password_file_name= win_dflt_password_file_name;
|
||||
const char *Options::Main::pid_file_name= win_dflt_pid_file_name;
|
||||
const char *Options::Main::socket_file_name= win_dflt_socket_file_name;
|
||||
|
||||
const char *Options::Main::default_mysqld_path= win_dflt_mysqld_path;
|
||||
|
||||
static int setup_windows_defaults();
|
||||
|
||||
#else /* UNIX */
|
||||
|
||||
/* Define and initialize UNIX-specific options. */
|
||||
|
||||
my_bool Options::Daemon::run_as_service= FALSE;
|
||||
const char *Options::Daemon::log_file_name= QUOTE(DEFAULT_LOG_FILE_NAME);
|
||||
const char *Options::Daemon::user= NULL; /* No default value */
|
||||
|
||||
const char *Options::Main::config_file= QUOTE(DEFAULT_CONFIG_FILE);
|
||||
const char *
|
||||
Options::Main::password_file_name= QUOTE(DEFAULT_PASSWORD_FILE_NAME);
|
||||
const char *Options::Main::pid_file_name= QUOTE(DEFAULT_PID_FILE_NAME);
|
||||
const char *Options::Main::socket_file_name= QUOTE(DEFAULT_SOCKET_FILE_NAME);
|
||||
|
||||
const char *Options::Main::default_mysqld_path= QUOTE(DEFAULT_MYSQLD_PATH);
|
||||
|
||||
#endif
|
||||
const char *Options::log_file_name= default_log_file_name;
|
||||
const char *Options::pid_file_name= QUOTE(DEFAULT_PID_FILE_NAME);
|
||||
const char *Options::socket_file_name= QUOTE(DEFAULT_SOCKET_FILE_NAME);
|
||||
const char *Options::password_file_name= default_password_file_name;
|
||||
const char *Options::default_mysqld_path= QUOTE(DEFAULT_MYSQLD_PATH);
|
||||
const char *Options::bind_address= 0; /* No default value */
|
||||
uint Options::monitoring_interval= DEFAULT_MONITORING_INTERVAL;
|
||||
uint Options::port_number= DEFAULT_PORT;
|
||||
/* just to declare */
|
||||
|
||||
/* Remember if the config file was forced. */
|
||||
|
||||
bool Options::Main::is_forced_default_file= FALSE;
|
||||
|
||||
/* Define and initialize common options. */
|
||||
|
||||
const char *Options::Main::bind_address= NULL; /* No default value */
|
||||
uint Options::Main::monitoring_interval= DEFAULT_MONITORING_INTERVAL;
|
||||
uint Options::Main::port_number= DEFAULT_PORT;
|
||||
my_bool Options::Main::mysqld_safe_compatible= FALSE;
|
||||
|
||||
/* Options::User_management */
|
||||
|
||||
char *Options::User_management::user_name= NULL;
|
||||
char *Options::User_management::password= NULL;
|
||||
|
||||
User_management_cmd *Options::User_management::cmd= NULL;
|
||||
|
||||
/* Private members. */
|
||||
|
||||
char **Options::saved_argv= NULL;
|
||||
/* Remember if the config file was forced */
|
||||
bool Options::is_forced_default_file= 0;
|
||||
|
||||
#ifndef DBUG_OFF
|
||||
const char *Options::default_dbug_option= "d:t:i:O,im.trace";
|
||||
const char *Options::Debug::config_str= "d:t:i:O,im.trace";
|
||||
#endif
|
||||
|
||||
/*
|
||||
@ -67,23 +110,33 @@ const char *Options::default_dbug_option= "d:t:i:O,im.trace";
|
||||
*/
|
||||
|
||||
enum options {
|
||||
OPT_PASSWD= 'P',
|
||||
OPT_USERNAME= 'u',
|
||||
OPT_PASSWORD= 'p',
|
||||
OPT_LOG= 256,
|
||||
OPT_PID_FILE,
|
||||
OPT_SOCKET,
|
||||
OPT_PASSWORD_FILE,
|
||||
OPT_MYSQLD_PATH,
|
||||
#ifndef __WIN__
|
||||
OPT_RUN_AS_SERVICE,
|
||||
OPT_USER,
|
||||
#else
|
||||
#ifdef __WIN__
|
||||
OPT_INSTALL_SERVICE,
|
||||
OPT_REMOVE_SERVICE,
|
||||
OPT_STAND_ALONE,
|
||||
#else
|
||||
OPT_RUN_AS_SERVICE,
|
||||
OPT_USER,
|
||||
#endif
|
||||
OPT_MONITORING_INTERVAL,
|
||||
OPT_PORT,
|
||||
OPT_WAIT_TIMEOUT,
|
||||
OPT_BIND_ADDRESS
|
||||
OPT_BIND_ADDRESS,
|
||||
OPT_ADD_USER,
|
||||
OPT_DROP_USER,
|
||||
OPT_EDIT_USER,
|
||||
OPT_CLEAN_PASSWORD_FILE,
|
||||
OPT_CHECK_PASSWORD_FILE,
|
||||
OPT_LIST_USERS,
|
||||
OPT_MYSQLD_SAFE_COMPATIBLE
|
||||
};
|
||||
|
||||
static struct my_option my_long_options[] =
|
||||
@ -91,94 +144,151 @@ static struct my_option my_long_options[] =
|
||||
{ "help", '?', "Display this help and exit.",
|
||||
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 },
|
||||
|
||||
{ "add-user", OPT_ADD_USER,
|
||||
"Add a user to the password file",
|
||||
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 },
|
||||
|
||||
{ "bind-address", OPT_BIND_ADDRESS, "Bind address to use for connection.",
|
||||
(gptr *) &Options::bind_address, (gptr *) &Options::bind_address,
|
||||
(gptr *) &Options::Main::bind_address,
|
||||
(gptr *) &Options::Main::bind_address,
|
||||
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
|
||||
|
||||
{ "check-password-file", OPT_CHECK_PASSWORD_FILE,
|
||||
"Check the password file for consistency",
|
||||
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 },
|
||||
|
||||
{ "clean-password-file", OPT_CLEAN_PASSWORD_FILE,
|
||||
"Clean the password file",
|
||||
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 },
|
||||
|
||||
#ifndef DBUG_OFF
|
||||
{"debug", '#', "Debug log.",
|
||||
(gptr*) &Options::default_dbug_option, (gptr*) &Options::default_dbug_option,
|
||||
(gptr *) &Options::Debug::config_str,
|
||||
(gptr *) &Options::Debug::config_str,
|
||||
0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
|
||||
#endif
|
||||
|
||||
{ "default-mysqld-path", OPT_MYSQLD_PATH, "Where to look for MySQL"
|
||||
" Server binary.",
|
||||
(gptr *) &Options::default_mysqld_path,
|
||||
(gptr *) &Options::default_mysqld_path,
|
||||
(gptr *) &Options::Main::default_mysqld_path,
|
||||
(gptr *) &Options::Main::default_mysqld_path,
|
||||
0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0 },
|
||||
|
||||
{ "drop-user", OPT_DROP_USER,
|
||||
"Drop existing user from the password file",
|
||||
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 },
|
||||
|
||||
{ "edit-user", OPT_EDIT_USER,
|
||||
"Edit existing user in the password file",
|
||||
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 },
|
||||
|
||||
#ifdef __WIN__
|
||||
{ "install", OPT_INSTALL_SERVICE, "Install as system service.",
|
||||
(gptr *) &Options::install_as_service, (gptr*) &Options::install_as_service,
|
||||
(gptr *) &Options::Service::install_as_service,
|
||||
(gptr *) &Options::Service::install_as_service,
|
||||
0, GET_BOOL, NO_ARG, 0, 0, 1, 0, 0, 0 },
|
||||
#endif
|
||||
|
||||
{ "list-users", OPT_LIST_USERS,
|
||||
"Print out a list of registered users",
|
||||
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 },
|
||||
|
||||
#ifndef __WIN__
|
||||
{ "log", OPT_LOG, "Path to log file. Used only with --run-as-service.",
|
||||
(gptr *) &Options::log_file_name, (gptr *) &Options::log_file_name,
|
||||
(gptr *) &Options::Daemon::log_file_name,
|
||||
(gptr *) &Options::Daemon::log_file_name,
|
||||
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
|
||||
#endif
|
||||
|
||||
{ "monitoring-interval", OPT_MONITORING_INTERVAL, "Interval to monitor"
|
||||
" instances in seconds.",
|
||||
(gptr *) &Options::monitoring_interval,
|
||||
(gptr *) &Options::monitoring_interval,
|
||||
(gptr *) &Options::Main::monitoring_interval,
|
||||
(gptr *) &Options::Main::monitoring_interval,
|
||||
0, GET_UINT, REQUIRED_ARG, DEFAULT_MONITORING_INTERVAL,
|
||||
0, 0, 0, 0, 0 },
|
||||
|
||||
{ "passwd", 'P', "Prepare entry for passwd file and exit.", 0, 0, 0,
|
||||
GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 },
|
||||
{ "mysqld-safe-compatible", OPT_MYSQLD_SAFE_COMPATIBLE,
|
||||
"Start Instance Manager in mysqld_safe compatible manner",
|
||||
(gptr *) &Options::Main::mysqld_safe_compatible,
|
||||
(gptr *) &Options::Main::mysqld_safe_compatible,
|
||||
0, GET_BOOL, NO_ARG, 0, 0, 1, 0, 0, 0 },
|
||||
|
||||
{ "password-file", OPT_PASSWORD_FILE, "Look for Instance Manager users"
|
||||
" and passwords here.",
|
||||
(gptr *) &Options::password_file_name,
|
||||
(gptr *) &Options::password_file_name,
|
||||
{ "passwd", OPT_PASSWD,
|
||||
"Prepare an entry for the password file and exit.",
|
||||
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 },
|
||||
|
||||
{ "password", OPT_PASSWORD, "Password to update the password file",
|
||||
(gptr *) &Options::User_management::password,
|
||||
(gptr *) &Options::User_management::password,
|
||||
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
|
||||
|
||||
{ "password-file", OPT_PASSWORD_FILE,
|
||||
"Look for Instance Manager users and passwords here.",
|
||||
(gptr *) &Options::Main::password_file_name,
|
||||
(gptr *) &Options::Main::password_file_name,
|
||||
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
|
||||
|
||||
{ "pid-file", OPT_PID_FILE, "Pid file to use.",
|
||||
(gptr *) &Options::pid_file_name, (gptr *) &Options::pid_file_name,
|
||||
(gptr *) &Options::Main::pid_file_name,
|
||||
(gptr *) &Options::Main::pid_file_name,
|
||||
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
|
||||
|
||||
{ "port", OPT_PORT, "Port number to use for connections",
|
||||
(gptr *) &Options::port_number, (gptr *) &Options::port_number,
|
||||
(gptr *) &Options::Main::port_number,
|
||||
(gptr *) &Options::Main::port_number,
|
||||
0, GET_UINT, REQUIRED_ARG, DEFAULT_PORT, 0, 0, 0, 0, 0 },
|
||||
|
||||
#ifdef __WIN__
|
||||
{ "remove", OPT_REMOVE_SERVICE, "Remove system service.",
|
||||
(gptr *)&Options::remove_service, (gptr*) &Options::remove_service,
|
||||
(gptr *) &Options::Service::remove_service,
|
||||
(gptr *) &Options::Service::remove_service,
|
||||
0, GET_BOOL, NO_ARG, 0, 0, 1, 0, 0, 0},
|
||||
#else
|
||||
{ "run-as-service", OPT_RUN_AS_SERVICE,
|
||||
"Daemonize and start angel process.", (gptr *) &Options::run_as_service,
|
||||
"Daemonize and start angel process.",
|
||||
(gptr *) &Options::Daemon::run_as_service,
|
||||
0, 0, GET_BOOL, NO_ARG, 0, 0, 1, 0, 0, 0 },
|
||||
#endif
|
||||
|
||||
{ "socket", OPT_SOCKET, "Socket file to use for connection.",
|
||||
(gptr *) &Options::socket_file_name, (gptr *) &Options::socket_file_name,
|
||||
(gptr *) &Options::Main::socket_file_name,
|
||||
(gptr *) &Options::Main::socket_file_name,
|
||||
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
|
||||
|
||||
#ifdef __WIN__
|
||||
{ "standalone", OPT_STAND_ALONE, "Run the application in stand alone mode.",
|
||||
(gptr *)&Options::stand_alone, (gptr*) &Options::stand_alone,
|
||||
(gptr *) &Options::Service::stand_alone,
|
||||
(gptr *) &Options::Service::stand_alone,
|
||||
0, GET_BOOL, NO_ARG, 0, 0, 1, 0, 0, 0},
|
||||
#else
|
||||
{ "user", OPT_USER, "Username to start mysqlmanager",
|
||||
(gptr *) &Options::user,
|
||||
(gptr *) &Options::user,
|
||||
(gptr *) &Options::Daemon::user,
|
||||
(gptr *) &Options::Daemon::user,
|
||||
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
|
||||
#endif
|
||||
|
||||
{ "username", OPT_USERNAME,
|
||||
"Username to update the password file",
|
||||
(gptr *) &Options::User_management::user_name,
|
||||
(gptr *) &Options::User_management::user_name,
|
||||
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
|
||||
|
||||
{ "version", 'V', "Output version information and exit.", 0, 0, 0,
|
||||
GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 },
|
||||
|
||||
{ "wait-timeout", OPT_WAIT_TIMEOUT, "The number of seconds IM waits "
|
||||
"for activity on a connection before closing it.",
|
||||
(gptr *) &net_read_timeout, (gptr *) &net_read_timeout, 0, GET_ULONG,
|
||||
REQUIRED_ARG, NET_WAIT_TIMEOUT, 1, LONG_TIMEOUT, 0, 1, 0 },
|
||||
(gptr *) &net_read_timeout,
|
||||
(gptr *) &net_read_timeout,
|
||||
0, GET_ULONG, REQUIRED_ARG, NET_WAIT_TIMEOUT, 1, LONG_TIMEOUT, 0, 1, 0 },
|
||||
|
||||
{ 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
static void version()
|
||||
{
|
||||
printf("%s Ver %s for %s on %s\n", my_progname, mysqlmanager_version,
|
||||
printf("%s Ver %s for %s on %s\n", my_progname,
|
||||
(const char *) mysqlmanager_version.str,
|
||||
SYSTEM_TYPE, MACHINE_TYPE);
|
||||
}
|
||||
|
||||
@ -206,37 +316,6 @@ static void usage()
|
||||
}
|
||||
|
||||
|
||||
static void passwd()
|
||||
{
|
||||
char user[1024], *p;
|
||||
const char *pw1, *pw2;
|
||||
char pw1msg[]= "Enter password: ";
|
||||
char pw2msg[]= "Re-type password: ";
|
||||
char crypted_pw[SCRAMBLED_PASSWORD_CHAR_LENGTH + 1];
|
||||
|
||||
fprintf(stderr, "Creating record for new user.\n");
|
||||
fprintf(stderr, "Enter user name: ");
|
||||
if (!fgets(user, sizeof(user), stdin))
|
||||
{
|
||||
fprintf(stderr, "Unable to read user.\n");
|
||||
return;
|
||||
}
|
||||
if ((p= strchr(user, '\n'))) *p= 0;
|
||||
|
||||
pw1= get_tty_password(pw1msg);
|
||||
pw2= get_tty_password(pw2msg);
|
||||
|
||||
if (strcmp(pw1, pw2))
|
||||
{
|
||||
fprintf(stderr, "Sorry, passwords do not match.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
make_scrambled_password(crypted_pw, pw1);
|
||||
printf("%s:%s\n", user, crypted_pw);
|
||||
}
|
||||
|
||||
|
||||
C_MODE_START
|
||||
|
||||
static my_bool
|
||||
@ -248,16 +327,52 @@ get_one_option(int optid,
|
||||
case 'V':
|
||||
version();
|
||||
exit(0);
|
||||
case 'P':
|
||||
passwd();
|
||||
exit(0);
|
||||
case OPT_PASSWD:
|
||||
case OPT_ADD_USER:
|
||||
case OPT_DROP_USER:
|
||||
case OPT_EDIT_USER:
|
||||
case OPT_CLEAN_PASSWORD_FILE:
|
||||
case OPT_CHECK_PASSWORD_FILE:
|
||||
case OPT_LIST_USERS:
|
||||
if (Options::User_management::cmd)
|
||||
{
|
||||
fprintf(stderr, "Error: only one password-management command "
|
||||
"can be specified at a time.\n");
|
||||
exit(ERR_INVALID_USAGE);
|
||||
}
|
||||
|
||||
switch (optid) {
|
||||
case OPT_PASSWD:
|
||||
Options::User_management::cmd= new Passwd_cmd();
|
||||
break;
|
||||
case OPT_ADD_USER:
|
||||
Options::User_management::cmd= new Add_user_cmd();
|
||||
break;
|
||||
case OPT_DROP_USER:
|
||||
Options::User_management::cmd= new Drop_user_cmd();
|
||||
break;
|
||||
case OPT_EDIT_USER:
|
||||
Options::User_management::cmd= new Edit_user_cmd();
|
||||
break;
|
||||
case OPT_CLEAN_PASSWORD_FILE:
|
||||
Options::User_management::cmd= new Clean_db_cmd();
|
||||
break;
|
||||
case OPT_CHECK_PASSWORD_FILE:
|
||||
Options::User_management::cmd= new Check_db_cmd();
|
||||
break;
|
||||
case OPT_LIST_USERS:
|
||||
Options::User_management::cmd= new List_users_cmd();
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
case '?':
|
||||
usage();
|
||||
exit(0);
|
||||
case '#':
|
||||
#ifndef DBUG_OFF
|
||||
DBUG_SET(argument ? argument : Options::default_dbug_option);
|
||||
DBUG_SET_INITIAL(argument ? argument : Options::default_dbug_option);
|
||||
DBUG_SET(argument ? argument : Options::Debug::config_str);
|
||||
DBUG_SET_INITIAL(argument ? argument : Options::Debug::config_str);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
@ -283,8 +398,8 @@ int Options::load(int argc, char **argv)
|
||||
{
|
||||
if (is_prefix(argv[1], "--defaults-file="))
|
||||
{
|
||||
Options::config_file= strchr(argv[1], '=') + 1;
|
||||
Options::is_forced_default_file= 1;
|
||||
Main::config_file= strchr(argv[1], '=') + 1;
|
||||
Main::is_forced_default_file= TRUE;
|
||||
}
|
||||
if (is_prefix(argv[1], "--defaults-extra-file=") ||
|
||||
is_prefix(argv[1], "--no-defaults"))
|
||||
@ -293,59 +408,92 @@ int Options::load(int argc, char **argv)
|
||||
fprintf(stderr, "The --defaults-extra-file and --no-defaults options"
|
||||
" are not supported by\n"
|
||||
"Instance Manager. Program aborted.\n");
|
||||
goto err;
|
||||
return ERR_INVALID_USAGE;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __WIN__
|
||||
if (setup_windows_defaults())
|
||||
goto err;
|
||||
{
|
||||
fprintf(stderr, "Internal error: could not setup default values.\n");
|
||||
return ERR_OUT_OF_MEMORY;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* load_defaults will reset saved_argv with a new allocated list */
|
||||
saved_argv= argv;
|
||||
|
||||
/* config-file options are prepended to command-line ones */
|
||||
load_defaults(config_file, default_groups, &argc,
|
||||
&saved_argv);
|
||||
|
||||
if ((handle_options(&argc, &saved_argv, my_long_options,
|
||||
get_one_option)) != 0)
|
||||
goto err;
|
||||
log_info("Loading config file '%s'...",
|
||||
(const char *) Main::config_file);
|
||||
|
||||
load_defaults(Main::config_file, default_groups, &argc, &saved_argv);
|
||||
|
||||
if ((handle_options(&argc, &saved_argv, my_long_options, get_one_option)))
|
||||
return ERR_INVALID_USAGE;
|
||||
|
||||
if (!User_management::cmd &&
|
||||
(User_management::user_name || User_management::password))
|
||||
{
|
||||
fprintf(stderr,
|
||||
"--username and/or --password options have been specified, "
|
||||
"but no password-management command has been given.\n");
|
||||
return ERR_INVALID_USAGE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
return 1;
|
||||
}
|
||||
|
||||
void Options::cleanup()
|
||||
{
|
||||
/* free_defaults returns nothing */
|
||||
if (Options::saved_argv != NULL)
|
||||
free_defaults(Options::saved_argv);
|
||||
if (saved_argv)
|
||||
free_defaults(saved_argv);
|
||||
|
||||
delete User_management::cmd;
|
||||
}
|
||||
|
||||
#ifdef __WIN__
|
||||
|
||||
int Options::setup_windows_defaults()
|
||||
static int setup_windows_defaults()
|
||||
{
|
||||
if (!GetModuleFileName(NULL, default_password_file_name,
|
||||
sizeof(default_password_file_name)))
|
||||
return 1;
|
||||
char *filename= strstr(default_password_file_name, ".exe");
|
||||
strcpy(filename, ".passwd");
|
||||
|
||||
if (!GetModuleFileName(NULL, default_log_file_name,
|
||||
sizeof(default_log_file_name)))
|
||||
return 1;
|
||||
filename= strstr(default_log_file_name, ".exe");
|
||||
strcpy(filename, ".log");
|
||||
char module_full_name[FN_REFLEN];
|
||||
char dir_name[FN_REFLEN];
|
||||
char base_name[FN_REFLEN];
|
||||
char im_name[FN_REFLEN];
|
||||
char *base_name_ptr;
|
||||
char *ptr;
|
||||
|
||||
if (!GetModuleFileName(NULL, windows_config_file,
|
||||
sizeof(windows_config_file)))
|
||||
/* Determine dirname and basename. */
|
||||
|
||||
if (!GetModuleFileName(NULL, module_full_name, sizeof (module_full_name)) ||
|
||||
!GetFullPathName(module_full_name, sizeof (dir_name), dir_name,
|
||||
&base_name_ptr))
|
||||
{
|
||||
return 1;
|
||||
char *slash= strrchr(windows_config_file, '\\');
|
||||
strcpy(slash, "\\my.ini");
|
||||
}
|
||||
|
||||
strmake(base_name, base_name_ptr, FN_REFLEN);
|
||||
*base_name_ptr= 0;
|
||||
|
||||
strmake(im_name, base_name, FN_REFLEN);
|
||||
ptr= strrchr(im_name, '.');
|
||||
|
||||
if (!ptr)
|
||||
return 1;
|
||||
|
||||
*ptr= 0;
|
||||
|
||||
/* Initialize the defaults. */
|
||||
|
||||
strxmov(win_dflt_config_file_name, dir_name, DFLT_CONFIG_FILE_NAME, NullS);
|
||||
strxmov(win_dflt_mysqld_path, dir_name, DFLT_MYSQLD_PATH, NullS);
|
||||
strxmov(win_dflt_password_file_name, dir_name, im_name, DFLT_PASSWD_FILE_EXT,
|
||||
NullS);
|
||||
strxmov(win_dflt_pid_file_name, dir_name, im_name, DFLT_PID_FILE_EXT, NullS);
|
||||
strxmov(win_dflt_socket_file_name, dir_name, im_name, DFLT_SOCKET_FILE_EXT,
|
||||
NullS);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -17,49 +17,86 @@
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
/*
|
||||
Options - all possible options for the instance manager grouped in one
|
||||
struct.
|
||||
Options - all possible command-line options for the Instance Manager grouped
|
||||
in one struct.
|
||||
*/
|
||||
|
||||
#include <my_global.h>
|
||||
|
||||
#if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE)
|
||||
#pragma interface
|
||||
#endif
|
||||
|
||||
class User_management_cmd;
|
||||
|
||||
struct Options
|
||||
{
|
||||
#ifdef __WIN__
|
||||
static char install_as_service;
|
||||
static char remove_service;
|
||||
static char stand_alone;
|
||||
#else
|
||||
static char run_as_service; /* handle_options doesn't support bool */
|
||||
static const char *user;
|
||||
#endif
|
||||
static bool is_forced_default_file;
|
||||
static const char *log_file_name;
|
||||
static const char *pid_file_name;
|
||||
static const char *socket_file_name;
|
||||
static const char *password_file_name;
|
||||
static const char *default_mysqld_path;
|
||||
/* the option which should be passed to process_default_option_files */
|
||||
static uint monitoring_interval;
|
||||
static uint port_number;
|
||||
static const char *bind_address;
|
||||
static const char *config_file;
|
||||
/*
|
||||
NOTE: handle_options() expects value of my_bool type for GET_BOOL
|
||||
accessor (i.e. bool must not be used).
|
||||
*/
|
||||
|
||||
/* argv pointer returned by load_defaults() to be used by free_defaults() */
|
||||
static char **saved_argv;
|
||||
struct User_management
|
||||
{
|
||||
static User_management_cmd *cmd;
|
||||
|
||||
static char *user_name;
|
||||
static char *password;
|
||||
};
|
||||
|
||||
struct Main
|
||||
{
|
||||
/* this is not an option parsed by handle_options(). */
|
||||
static bool is_forced_default_file;
|
||||
|
||||
static const char *pid_file_name;
|
||||
static const char *socket_file_name;
|
||||
static const char *password_file_name;
|
||||
static const char *default_mysqld_path;
|
||||
static uint monitoring_interval;
|
||||
static uint port_number;
|
||||
static const char *bind_address;
|
||||
static const char *config_file;
|
||||
static my_bool mysqld_safe_compatible;
|
||||
};
|
||||
|
||||
#ifndef DBUG_OFF
|
||||
static const char *default_dbug_option;
|
||||
struct Debug
|
||||
{
|
||||
static const char *config_str;
|
||||
};
|
||||
#endif
|
||||
|
||||
int load(int argc, char **argv);
|
||||
void cleanup();
|
||||
#ifdef __WIN__
|
||||
int setup_windows_defaults();
|
||||
#ifndef __WIN__
|
||||
|
||||
struct Daemon
|
||||
{
|
||||
static my_bool run_as_service;
|
||||
static const char *log_file_name;
|
||||
static const char *user;
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
struct Service
|
||||
{
|
||||
static my_bool install_as_service;
|
||||
static my_bool remove_service;
|
||||
static my_bool stand_alone;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
public:
|
||||
static int load(int argc, char **argv);
|
||||
static void cleanup();
|
||||
|
||||
private:
|
||||
Options(); /* Deny instantiation of this class. */
|
||||
|
||||
private:
|
||||
/* argv pointer returned by load_defaults() to be used by free_defaults() */
|
||||
static char **saved_argv;
|
||||
};
|
||||
|
||||
#endif // INCLUDES_MYSQL_INSTANCE_MANAGER_OPTIONS_H
|
||||
|
@ -17,12 +17,12 @@
|
||||
#include "parse.h"
|
||||
#include "commands.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
|
||||
enum Token
|
||||
{
|
||||
TOK_ERROR= 0, /* Encodes the "ERROR" word, it doesn't indicate error. */
|
||||
TOK_CREATE= 0,
|
||||
TOK_DROP,
|
||||
TOK_ERROR, /* Encodes the "ERROR" word, it doesn't indicate error. */
|
||||
TOK_FILES,
|
||||
TOK_FLUSH,
|
||||
TOK_GENERAL,
|
||||
@ -50,6 +50,8 @@ struct tokens_st
|
||||
|
||||
|
||||
static struct tokens_st tokens[]= {
|
||||
{6, "CREATE"},
|
||||
{4, "DROP"},
|
||||
{5, "ERROR"},
|
||||
{5, "FILES"},
|
||||
{5, "FLUSH"},
|
||||
@ -67,6 +69,37 @@ static struct tokens_st tokens[]= {
|
||||
{5, "UNSET"}
|
||||
};
|
||||
|
||||
/************************************************************************/
|
||||
|
||||
Named_value_arr::Named_value_arr() :
|
||||
initialized(FALSE)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool Named_value_arr::init()
|
||||
{
|
||||
if (my_init_dynamic_array(&arr, sizeof(Named_value), 0, 32))
|
||||
return TRUE;
|
||||
|
||||
initialized= TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
Named_value_arr::~Named_value_arr()
|
||||
{
|
||||
if (!initialized)
|
||||
return;
|
||||
|
||||
for (int i= 0; i < get_size(); ++i)
|
||||
get_element(i).free();
|
||||
|
||||
delete_dynamic(&arr);
|
||||
}
|
||||
|
||||
/************************************************************************/
|
||||
|
||||
/*
|
||||
Returns token no if word corresponds to some token, otherwise returns
|
||||
@ -104,53 +137,200 @@ Token shift_token(const char **text, uint *word_len)
|
||||
}
|
||||
|
||||
|
||||
int get_text_id(const char **text, uint *word_len, const char **id)
|
||||
int get_text_id(const char **text, LEX_STRING *token)
|
||||
{
|
||||
get_word(text, word_len);
|
||||
if (*word_len == 0)
|
||||
get_word(text, &token->length);
|
||||
if (token->length == 0)
|
||||
return 1;
|
||||
*id= *text;
|
||||
token->str= (char *) *text;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static bool parse_long(const LEX_STRING *token, long *value)
|
||||
{
|
||||
int err_code;
|
||||
char *end_ptr= token->str + token->length;
|
||||
|
||||
*value= my_strtoll10(token->str, &end_ptr, &err_code);
|
||||
|
||||
return err_code != 0;
|
||||
}
|
||||
|
||||
|
||||
bool parse_option_value(const char *text, uint *text_len, char **value)
|
||||
{
|
||||
char beginning_quote;
|
||||
const char *text_start_ptr;
|
||||
char *v;
|
||||
bool escape_mode= FALSE;
|
||||
|
||||
if (!*text || (*text != '\'' && *text != '"'))
|
||||
return TRUE; /* syntax error: string expected. */
|
||||
|
||||
beginning_quote= *text;
|
||||
|
||||
++text; /* skip the beginning quote. */
|
||||
|
||||
text_start_ptr= text;
|
||||
|
||||
if (!(v= Named_value::alloc_str(text)))
|
||||
return TRUE;
|
||||
|
||||
*value= v;
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
if (!*text)
|
||||
{
|
||||
Named_value::free_str(value);
|
||||
return TRUE; /* syntax error: missing terminating ' character. */
|
||||
}
|
||||
|
||||
if (*text == '\n' || *text == '\r')
|
||||
{
|
||||
Named_value::free_str(value);
|
||||
return TRUE; /* syntax error: option value should be a single line. */
|
||||
}
|
||||
|
||||
if (!escape_mode && *text == beginning_quote)
|
||||
break;
|
||||
|
||||
if (escape_mode)
|
||||
{
|
||||
switch (*text)
|
||||
{
|
||||
case 'b': /* \b -- backspace */
|
||||
if (v > *value)
|
||||
--v;
|
||||
break;
|
||||
|
||||
case 't': /* \t -- tab */
|
||||
*v= '\t';
|
||||
++v;
|
||||
break;
|
||||
|
||||
case 'n': /* \n -- newline */
|
||||
*v= '\n';
|
||||
++v;
|
||||
break;
|
||||
|
||||
case 'r': /* \r -- carriage return */
|
||||
*v= '\r';
|
||||
++v;
|
||||
break;
|
||||
|
||||
case '\\': /* \\ -- back slash */
|
||||
*v= '\\';
|
||||
++v;
|
||||
break;
|
||||
|
||||
case 's': /* \s -- space */
|
||||
*v= ' ';
|
||||
++v;
|
||||
break;
|
||||
|
||||
default: /* Unknown escape sequence. Treat as error. */
|
||||
Named_value::free_str(value);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
escape_mode= FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (*text == '\\')
|
||||
{
|
||||
escape_mode= TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
*v= *text;
|
||||
++v;
|
||||
}
|
||||
}
|
||||
|
||||
++text;
|
||||
}
|
||||
|
||||
*v= 0;
|
||||
|
||||
/* "2" below stands for beginning and ending quotes. */
|
||||
*text_len= text - text_start_ptr + 2;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
void skip_spaces(const char **text)
|
||||
{
|
||||
while (**text && my_isspace(default_charset_info, **text))
|
||||
++(*text);
|
||||
}
|
||||
|
||||
|
||||
Command *parse_command(Instance_map *map, const char *text)
|
||||
{
|
||||
uint word_len;
|
||||
const char *instance_name;
|
||||
uint instance_name_len;
|
||||
const char *option;
|
||||
uint option_len;
|
||||
const char *option_value;
|
||||
uint option_value_len;
|
||||
const char *log_size;
|
||||
LEX_STRING instance_name;
|
||||
Command *command;
|
||||
const char *saved_text= text;
|
||||
bool skip= false;
|
||||
const char *tmp;
|
||||
|
||||
Token tok1= shift_token(&text, &word_len);
|
||||
|
||||
switch (tok1) {
|
||||
case TOK_START: // fallthrough
|
||||
case TOK_STOP:
|
||||
case TOK_CREATE:
|
||||
case TOK_DROP:
|
||||
if (shift_token(&text, &word_len) != TOK_INSTANCE)
|
||||
goto syntax_error;
|
||||
get_word(&text, &word_len);
|
||||
if (word_len == 0)
|
||||
goto syntax_error;
|
||||
instance_name= text;
|
||||
instance_name_len= word_len;
|
||||
instance_name.str= (char *) text;
|
||||
instance_name.length= word_len;
|
||||
text+= word_len;
|
||||
/* it should be the end of command */
|
||||
get_word(&text, &word_len, NONSPACE);
|
||||
if (word_len)
|
||||
goto syntax_error;
|
||||
|
||||
if (tok1 == TOK_START)
|
||||
command= new Start_instance(map, instance_name, instance_name_len);
|
||||
if (tok1 == TOK_CREATE)
|
||||
{
|
||||
Create_instance *cmd= new Create_instance(map, &instance_name);
|
||||
|
||||
if (!cmd)
|
||||
return NULL; /* Report ER_OUT_OF_RESOURCES. */
|
||||
|
||||
if (cmd->init(&text))
|
||||
{
|
||||
delete cmd;
|
||||
goto syntax_error;
|
||||
}
|
||||
|
||||
command= cmd;
|
||||
}
|
||||
else
|
||||
command= new Stop_instance(map, instance_name, instance_name_len);
|
||||
{
|
||||
/* it should be the end of command */
|
||||
get_word(&text, &word_len, NONSPACE);
|
||||
if (word_len)
|
||||
goto syntax_error;
|
||||
}
|
||||
|
||||
switch (tok1) {
|
||||
case TOK_START:
|
||||
command= new Start_instance(map, &instance_name);
|
||||
break;
|
||||
case TOK_STOP:
|
||||
command= new Stop_instance(map, &instance_name);
|
||||
break;
|
||||
case TOK_CREATE:
|
||||
; /* command already initialized. */
|
||||
break;
|
||||
case TOK_DROP:
|
||||
command= new Drop_instance(map, &instance_name);
|
||||
break;
|
||||
default: /* this is impossible, but nevertheless... */
|
||||
DBUG_ASSERT(0);
|
||||
}
|
||||
break;
|
||||
case TOK_FLUSH:
|
||||
if (shift_token(&text, &word_len) != TOK_INSTANCES)
|
||||
@ -163,53 +343,28 @@ Command *parse_command(Instance_map *map, const char *text)
|
||||
command= new Flush_instances(map);
|
||||
break;
|
||||
case TOK_UNSET:
|
||||
skip= true;
|
||||
case TOK_SET:
|
||||
|
||||
if (get_text_id(&text, &instance_name_len, &instance_name))
|
||||
goto syntax_error;
|
||||
text+= instance_name_len;
|
||||
|
||||
/* the next token should be a dot */
|
||||
get_word(&text, &word_len);
|
||||
if (*text != '.')
|
||||
goto syntax_error;
|
||||
text++;
|
||||
|
||||
get_word(&text, &option_len, NONSPACE);
|
||||
option= text;
|
||||
if ((tmp= strchr(text, '=')) != NULL)
|
||||
option_len= tmp - text;
|
||||
text+= option_len;
|
||||
|
||||
get_word(&text, &word_len);
|
||||
if (*text == '=')
|
||||
{
|
||||
text++; /* skip '=' */
|
||||
get_word(&text, &option_value_len, NONSPACE);
|
||||
option_value= text;
|
||||
text+= option_value_len;
|
||||
}
|
||||
else
|
||||
{
|
||||
option_value= "";
|
||||
option_value_len= 0;
|
||||
}
|
||||
Abstract_option_cmd *cmd;
|
||||
|
||||
/* should be empty */
|
||||
get_word(&text, &word_len, NONSPACE);
|
||||
if (word_len)
|
||||
goto syntax_error;
|
||||
if (tok1 == TOK_SET)
|
||||
cmd= new Set_option(map);
|
||||
else
|
||||
cmd= new Unset_option(map);
|
||||
|
||||
if (skip)
|
||||
command= new Unset_option(map, instance_name, instance_name_len,
|
||||
option, option_len, option_value,
|
||||
option_value_len);
|
||||
else
|
||||
command= new Set_option(map, instance_name, instance_name_len,
|
||||
option, option_len, option_value,
|
||||
option_value_len);
|
||||
break;
|
||||
if (!cmd)
|
||||
return NULL; /* Report ER_OUT_OF_RESOURCES. */
|
||||
|
||||
if (cmd->init(&text))
|
||||
{
|
||||
delete cmd;
|
||||
goto syntax_error;
|
||||
}
|
||||
|
||||
command= cmd;
|
||||
|
||||
break;
|
||||
}
|
||||
case TOK_SHOW:
|
||||
switch (shift_token(&text, &word_len)) {
|
||||
case TOK_INSTANCES:
|
||||
@ -222,30 +377,35 @@ Command *parse_command(Instance_map *map, const char *text)
|
||||
switch (Token tok2= shift_token(&text, &word_len)) {
|
||||
case TOK_OPTIONS:
|
||||
case TOK_STATUS:
|
||||
if (get_text_id(&text, &instance_name_len, &instance_name))
|
||||
if (get_text_id(&text, &instance_name))
|
||||
goto syntax_error;
|
||||
text+= instance_name_len;
|
||||
text+= instance_name.length;
|
||||
/* check that this is the end of the command */
|
||||
get_word(&text, &word_len, NONSPACE);
|
||||
if (word_len)
|
||||
goto syntax_error;
|
||||
if (tok2 == TOK_STATUS)
|
||||
command= new Show_instance_status(map, instance_name,
|
||||
instance_name_len);
|
||||
command= new Show_instance_status(map, &instance_name);
|
||||
else
|
||||
command= new Show_instance_options(map, instance_name,
|
||||
instance_name_len);
|
||||
command= new Show_instance_options(map, &instance_name);
|
||||
break;
|
||||
default:
|
||||
goto syntax_error;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
instance_name= text - word_len;
|
||||
instance_name_len= word_len;
|
||||
if (instance_name_len)
|
||||
instance_name.str= (char *) text - word_len;
|
||||
instance_name.length= word_len;
|
||||
if (instance_name.length)
|
||||
{
|
||||
Log_type log_type;
|
||||
|
||||
long log_size;
|
||||
LEX_STRING log_size_str;
|
||||
|
||||
long log_offset= 0;
|
||||
LEX_STRING log_offset_str= { NULL, 0 };
|
||||
|
||||
switch (shift_token(&text, &word_len)) {
|
||||
case TOK_LOG:
|
||||
switch (Token tok3= shift_token(&text, &word_len)) {
|
||||
@ -254,8 +414,7 @@ Command *parse_command(Instance_map *map, const char *text)
|
||||
/* check that this is the end of the command */
|
||||
if (word_len)
|
||||
goto syntax_error;
|
||||
command= new Show_instance_log_files(map, instance_name,
|
||||
instance_name_len);
|
||||
command= new Show_instance_log_files(map, &instance_name);
|
||||
break;
|
||||
case TOK_ERROR:
|
||||
case TOK_GENERAL:
|
||||
@ -275,12 +434,14 @@ Command *parse_command(Instance_map *map, const char *text)
|
||||
goto syntax_error;
|
||||
}
|
||||
/* get the size of the log we want to retrieve */
|
||||
if (get_text_id(&text, &word_len, &log_size))
|
||||
if (get_text_id(&text, &log_size_str))
|
||||
goto syntax_error;
|
||||
text+= word_len;
|
||||
text+= log_size_str.length;
|
||||
|
||||
/* this parameter is required */
|
||||
if (!word_len)
|
||||
if (!log_size_str.length)
|
||||
goto syntax_error;
|
||||
|
||||
/* the next token should be comma, or nothing */
|
||||
get_word(&text, &word_len);
|
||||
switch (*text) {
|
||||
@ -290,23 +451,41 @@ Command *parse_command(Instance_map *map, const char *text)
|
||||
get_word(&text, &word_len);
|
||||
if (!word_len)
|
||||
goto syntax_error;
|
||||
log_offset_str.str= (char *) text;
|
||||
log_offset_str.length= word_len;
|
||||
text+= word_len;
|
||||
command= new Show_instance_log(map, instance_name,
|
||||
instance_name_len, log_type,
|
||||
log_size, text);
|
||||
get_word(&text, &word_len, NONSPACE);
|
||||
/* check that this is the end of the command */
|
||||
if (word_len)
|
||||
goto syntax_error;
|
||||
break;
|
||||
case '\0':
|
||||
command= new Show_instance_log(map, instance_name,
|
||||
instance_name_len, log_type,
|
||||
log_size, NULL);
|
||||
break; /* this is ok */
|
||||
default:
|
||||
goto syntax_error;
|
||||
goto syntax_error;
|
||||
}
|
||||
|
||||
/* Parse size parameter. */
|
||||
|
||||
if (parse_long(&log_size_str, &log_size))
|
||||
goto syntax_error;
|
||||
|
||||
if (log_size <= 0)
|
||||
goto syntax_error;
|
||||
|
||||
/* Parse offset parameter (if specified). */
|
||||
|
||||
if (log_offset_str.length)
|
||||
{
|
||||
if (parse_long(&log_offset_str, &log_offset))
|
||||
goto syntax_error;
|
||||
|
||||
if (log_offset <= 0)
|
||||
goto syntax_error;
|
||||
}
|
||||
|
||||
command= new Show_instance_log(map, &instance_name,
|
||||
log_type, log_size, log_offset);
|
||||
break;
|
||||
default:
|
||||
goto syntax_error;
|
||||
|
@ -18,6 +18,7 @@
|
||||
|
||||
#include <my_global.h>
|
||||
#include <my_sys.h>
|
||||
#include <m_string.h>
|
||||
|
||||
class Command;
|
||||
class Instance_map;
|
||||
@ -29,10 +30,148 @@ enum Log_type
|
||||
IM_LOG_SLOW
|
||||
};
|
||||
|
||||
Command *parse_command(Instance_map *instance_map, const char *text);
|
||||
Command *parse_command(Instance_map *map, const char *text);
|
||||
|
||||
bool parse_option_value(const char *text, uint *text_len, char **value);
|
||||
|
||||
void skip_spaces(const char **text);
|
||||
|
||||
/* define kinds of the word seek method */
|
||||
enum { ALPHANUM= 1, NONSPACE };
|
||||
enum enum_seek_method { ALPHANUM= 1, NONSPACE, OPTION_NAME };
|
||||
|
||||
/************************************************************************/
|
||||
|
||||
class Named_value
|
||||
{
|
||||
public:
|
||||
/*
|
||||
The purpose of these methods is just to have one method for
|
||||
allocating/deallocating memory for strings for Named_value.
|
||||
*/
|
||||
|
||||
static inline char *alloc_str(const LEX_STRING *str);
|
||||
static inline char *alloc_str(const char *str);
|
||||
static inline void free_str(char **str);
|
||||
|
||||
public:
|
||||
inline Named_value();
|
||||
inline Named_value(char *name_arg, char *value_arg);
|
||||
|
||||
inline char *get_name();
|
||||
inline char *get_value();
|
||||
|
||||
inline void free();
|
||||
|
||||
private:
|
||||
char *name;
|
||||
char *value;
|
||||
};
|
||||
|
||||
inline char *Named_value::alloc_str(const LEX_STRING *str)
|
||||
{
|
||||
return my_strndup((const byte *) str->str, str->length, MYF(0));
|
||||
}
|
||||
|
||||
inline char *Named_value::alloc_str(const char *str)
|
||||
{
|
||||
return my_strdup(str, MYF(0));
|
||||
}
|
||||
|
||||
inline void Named_value::free_str(char **str)
|
||||
{
|
||||
my_free(*str, MYF(MY_ALLOW_ZERO_PTR));
|
||||
*str= NULL;
|
||||
}
|
||||
|
||||
inline Named_value::Named_value()
|
||||
:name(NULL), value(NULL)
|
||||
{ }
|
||||
|
||||
inline Named_value::Named_value(char *name_arg, char *value_arg)
|
||||
:name(name_arg), value(value_arg)
|
||||
{ }
|
||||
|
||||
inline char *Named_value::get_name()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
inline char *Named_value::get_value()
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
void Named_value::free()
|
||||
{
|
||||
free_str(&name);
|
||||
free_str(&value);
|
||||
}
|
||||
|
||||
/************************************************************************/
|
||||
|
||||
class Named_value_arr
|
||||
{
|
||||
public:
|
||||
Named_value_arr();
|
||||
~Named_value_arr();
|
||||
|
||||
bool init();
|
||||
|
||||
inline int get_size() const;
|
||||
inline Named_value get_element(int idx) const;
|
||||
inline void remove_element(int idx);
|
||||
inline bool add_element(Named_value *option);
|
||||
inline bool replace_element(int idx, Named_value *option);
|
||||
|
||||
private:
|
||||
bool initialized;
|
||||
DYNAMIC_ARRAY arr;
|
||||
};
|
||||
|
||||
|
||||
inline int Named_value_arr::get_size() const
|
||||
{
|
||||
return arr.elements;
|
||||
}
|
||||
|
||||
|
||||
inline Named_value Named_value_arr::get_element(int idx) const
|
||||
{
|
||||
DBUG_ASSERT(0 <= idx && (uint) idx < arr.elements);
|
||||
|
||||
Named_value option;
|
||||
get_dynamic((DYNAMIC_ARRAY *) &arr, (gptr) &option, idx);
|
||||
|
||||
return option;
|
||||
}
|
||||
|
||||
|
||||
inline void Named_value_arr::remove_element(int idx)
|
||||
{
|
||||
DBUG_ASSERT(0 <= idx && (uint) idx < arr.elements);
|
||||
|
||||
get_element(idx).free();
|
||||
|
||||
delete_dynamic_element(&arr, idx);
|
||||
}
|
||||
|
||||
|
||||
inline bool Named_value_arr::add_element(Named_value *option)
|
||||
{
|
||||
return insert_dynamic(&arr, (gptr) option);
|
||||
}
|
||||
|
||||
|
||||
inline bool Named_value_arr::replace_element(int idx, Named_value *option)
|
||||
{
|
||||
DBUG_ASSERT(0 <= idx && (uint) idx < arr.elements);
|
||||
|
||||
get_element(idx).free();
|
||||
|
||||
return set_dynamic(&arr, (gptr) option, idx);
|
||||
}
|
||||
|
||||
/************************************************************************/
|
||||
|
||||
/*
|
||||
tries to find next word in the text
|
||||
@ -41,7 +180,7 @@ enum { ALPHANUM= 1, NONSPACE };
|
||||
*/
|
||||
|
||||
inline void get_word(const char **text, uint *word_len,
|
||||
int seek_method= ALPHANUM)
|
||||
enum_seek_method seek_method= ALPHANUM)
|
||||
{
|
||||
const char *word_end;
|
||||
|
||||
@ -51,13 +190,23 @@ inline void get_word(const char **text, uint *word_len,
|
||||
|
||||
word_end= *text;
|
||||
|
||||
if (seek_method == ALPHANUM)
|
||||
switch (seek_method) {
|
||||
case ALPHANUM:
|
||||
while (my_isalnum(default_charset_info, *word_end))
|
||||
++word_end;
|
||||
else
|
||||
break;
|
||||
case NONSPACE:
|
||||
while (!my_isspace(default_charset_info, *word_end) &&
|
||||
(*word_end != '\0'))
|
||||
++word_end;
|
||||
break;
|
||||
case OPTION_NAME:
|
||||
while (my_isalnum(default_charset_info, *word_end) ||
|
||||
*word_end == '-' ||
|
||||
*word_end == '_')
|
||||
++word_end;
|
||||
break;
|
||||
}
|
||||
|
||||
*word_len= word_end - *text;
|
||||
}
|
||||
|
@ -14,13 +14,15 @@
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
#include <my_global.h>
|
||||
#include "parse.h"
|
||||
#include "parse_output.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <my_global.h>
|
||||
#include <my_sys.h>
|
||||
#include <m_string.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "parse.h"
|
||||
#include "portability.h"
|
||||
|
||||
|
||||
|
@ -16,6 +16,8 @@
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
#include <my_global.h>
|
||||
|
||||
#define GET_VALUE 1
|
||||
#define GET_LINE 2
|
||||
|
||||
|
@ -16,11 +16,25 @@
|
||||
/*TODO: fix this */
|
||||
#define PROTOCOL_VERSION 10
|
||||
|
||||
#define DFLT_CONFIG_FILE_NAME "my.ini"
|
||||
#define DFLT_MYSQLD_PATH "mysqld"
|
||||
#define DFLT_PASSWD_FILE_EXT ".passwd"
|
||||
#define DFLT_PID_FILE_EXT ".pid"
|
||||
#define DFLT_SOCKET_FILE_EXT ".sock"
|
||||
|
||||
typedef int pid_t;
|
||||
|
||||
#undef popen
|
||||
#define popen(A,B) _popen(A,B)
|
||||
|
||||
#define NEWLINE "\r\n"
|
||||
#define NEWLINE_LEN 2
|
||||
|
||||
#else /* ! __WIN__ */
|
||||
|
||||
#define NEWLINE "\n"
|
||||
#define NEWLINE_LEN 1
|
||||
|
||||
#endif /* __WIN__ */
|
||||
|
||||
#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_PORTABILITY_H */
|
||||
|
@ -14,10 +14,10 @@
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
#include "priv.h"
|
||||
|
||||
#include <my_global.h>
|
||||
#include <mysql_com.h>
|
||||
#include "priv.h"
|
||||
#include "portability.h"
|
||||
|
||||
#if defined(__ia64__) || defined(__ia64)
|
||||
/*
|
||||
@ -43,9 +43,7 @@ bool linuxthreads;
|
||||
The following string must be less then 80 characters, as
|
||||
mysql_connection.cc relies on it
|
||||
*/
|
||||
const char mysqlmanager_version[] = "0.2-alpha";
|
||||
|
||||
const int mysqlmanager_version_length= sizeof(mysqlmanager_version) - 1;
|
||||
const LEX_STRING mysqlmanager_version= { C_STRING_WITH_SIZE("1.0-beta") };
|
||||
|
||||
const unsigned char protocol_version= PROTOCOL_VERSION;
|
||||
|
||||
|
@ -16,13 +16,17 @@
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
#include <my_global.h>
|
||||
#include <m_string.h>
|
||||
#include <my_pthread.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#ifdef __WIN__
|
||||
#include "portability.h"
|
||||
#else
|
||||
|
||||
#ifndef __WIN__
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include "my_pthread.h"
|
||||
|
||||
#include "portability.h"
|
||||
|
||||
/* IM-wide platform-independent defines */
|
||||
#define SERVER_DEFAULT_PORT 3306
|
||||
@ -31,6 +35,21 @@
|
||||
/* three-week timeout should be enough */
|
||||
#define LONG_TIMEOUT ((ulong) 3600L*24L*21L)
|
||||
|
||||
const int MEM_ROOT_BLOCK_SIZE= 512;
|
||||
|
||||
/* The maximal length of option name and option value. */
|
||||
const int MAX_OPTION_LEN= 1024;
|
||||
|
||||
/*
|
||||
The maximal length of whole option string:
|
||||
--<option name>=<option value>
|
||||
*/
|
||||
const int MAX_OPTION_STR_LEN= 2 + MAX_OPTION_LEN + 1 + MAX_OPTION_LEN + 1;
|
||||
|
||||
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;
|
||||
|
||||
@ -42,8 +61,7 @@ extern pid_t manager_pid;
|
||||
extern bool linuxthreads;
|
||||
#endif
|
||||
|
||||
extern const char mysqlmanager_version[];
|
||||
extern const int mysqlmanager_version_length;
|
||||
extern const LEX_STRING mysqlmanager_version;
|
||||
|
||||
/* MySQL client-server protocol version: substituted from configure */
|
||||
extern const unsigned char protocol_version;
|
||||
|
@ -163,7 +163,7 @@ int send_fields(struct st_net *net, LIST *fields)
|
||||
Buffer send_buff;
|
||||
char small_buff[4];
|
||||
uint position= 0;
|
||||
NAME_WITH_LENGTH *field;
|
||||
LEX_STRING *field;
|
||||
|
||||
/* send the number of fileds */
|
||||
net_store_length(small_buff, (uint) list_length(fields));
|
||||
@ -173,7 +173,7 @@ int send_fields(struct st_net *net, LIST *fields)
|
||||
while (tmp)
|
||||
{
|
||||
position= 0;
|
||||
field= (NAME_WITH_LENGTH *) tmp->data;
|
||||
field= (LEX_STRING *) tmp->data;
|
||||
|
||||
store_to_protocol_packet(&send_buff,
|
||||
(char*) "", &position); /* catalog name */
|
||||
@ -184,9 +184,9 @@ int send_fields(struct st_net *net, LIST *fields)
|
||||
store_to_protocol_packet(&send_buff,
|
||||
(char*) "", &position); /* table name alias */
|
||||
store_to_protocol_packet(&send_buff,
|
||||
field->name, &position); /* column name */
|
||||
field->str, &position); /* column name */
|
||||
store_to_protocol_packet(&send_buff,
|
||||
field->name, &position); /* column name alias */
|
||||
field->str, &position); /* column name alias */
|
||||
send_buff.reserve(position, 12);
|
||||
if (send_buff.is_error())
|
||||
goto err;
|
||||
|
@ -20,11 +20,6 @@
|
||||
|
||||
#include <my_list.h>
|
||||
|
||||
typedef struct field {
|
||||
char *name;
|
||||
uint length;
|
||||
} NAME_WITH_LENGTH;
|
||||
|
||||
/* default field length to be used in various field-realted functions */
|
||||
enum { DEFAULT_FIELD_LENGTH= 20 };
|
||||
|
||||
|
@ -20,12 +20,13 @@
|
||||
|
||||
#include "thread_registry.h"
|
||||
|
||||
#include "log.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <signal.h>
|
||||
#include <my_global.h>
|
||||
#include <thr_alarm.h>
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
#include "log.h"
|
||||
|
||||
|
||||
#ifndef __WIN__
|
||||
/* Kick-off signal handler */
|
||||
@ -52,7 +53,7 @@ Thread_info::Thread_info(pthread_t thread_id_arg) :
|
||||
*/
|
||||
|
||||
Thread_registry::Thread_registry() :
|
||||
shutdown_in_progress(false)
|
||||
shutdown_in_progress(FALSE)
|
||||
,sigwait_thread_pid(pthread_self())
|
||||
{
|
||||
pthread_mutex_init(&LOCK_thread_registry, 0);
|
||||
@ -186,7 +187,7 @@ void Thread_registry::deliver_shutdown()
|
||||
set_timespec(shutdown_time, 1);
|
||||
|
||||
pthread_mutex_lock(&LOCK_thread_registry);
|
||||
shutdown_in_progress= true;
|
||||
shutdown_in_progress= TRUE;
|
||||
|
||||
#ifndef __WIN__
|
||||
/* to stop reading from the network we need to flush alarm queue */
|
||||
|
408
server-tools/instance-manager/user_management_commands.cc
Normal file
408
server-tools/instance-manager/user_management_commands.cc
Normal file
@ -0,0 +1,408 @@
|
||||
#if defined(__GNUC__) && defined(USE_PRAGMA_IMPLEMENTATION)
|
||||
#pragma implementation
|
||||
#endif
|
||||
|
||||
#include "user_management_commands.h"
|
||||
|
||||
#include "exit_codes.h"
|
||||
#include "options.h"
|
||||
#include "user_map.h"
|
||||
|
||||
/*************************************************************************
|
||||
Module-specific (internal) functions.
|
||||
*************************************************************************/
|
||||
|
||||
/*
|
||||
The function returns user name. The user name is retrieved from command-line
|
||||
options (if specified) or from console.
|
||||
|
||||
NOTE
|
||||
This function must not be used in user-management command implementations.
|
||||
Use get_user_name() instead.
|
||||
|
||||
SYNOPSYS
|
||||
get_user_name_impl()
|
||||
|
||||
RETURN
|
||||
NULL on error
|
||||
valid pointer on success
|
||||
*/
|
||||
|
||||
static char *get_user_name_impl()
|
||||
{
|
||||
static char user_name_buf[1024];
|
||||
char *ptr;
|
||||
|
||||
if (Options::User_management::user_name)
|
||||
return Options::User_management::user_name;
|
||||
|
||||
printf("Enter user name: ");
|
||||
fflush(stdout);
|
||||
|
||||
if (!fgets(user_name_buf, sizeof (user_name_buf), stdin))
|
||||
return NULL;
|
||||
|
||||
if ((ptr= strchr(user_name_buf, '\n')))
|
||||
*ptr= 0;
|
||||
|
||||
if ((ptr= strchr(user_name_buf, '\r')))
|
||||
*ptr= 0;
|
||||
|
||||
return user_name_buf;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
The function is intended to provide user name for user-management
|
||||
operations. It also checks that length of the specified user name is correct
|
||||
(not empty, not exceeds USERNAME_LENGTH). Report to stderr if something is
|
||||
wrong.
|
||||
|
||||
SYNOPSYS
|
||||
get_user_name()
|
||||
user_name [OUT] on success contains user name
|
||||
|
||||
RETURN
|
||||
TRUE on error
|
||||
FALSE on success
|
||||
*/
|
||||
|
||||
static bool get_user_name(LEX_STRING *user_name)
|
||||
{
|
||||
char *user_name_str= get_user_name_impl();
|
||||
|
||||
if (!user_name_str)
|
||||
{
|
||||
fprintf(stderr, "Error: unable to read user name from stdin.\n");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
user_name->str= user_name_str;
|
||||
user_name->length= strlen(user_name->str);
|
||||
|
||||
if (user_name->length == 0)
|
||||
{
|
||||
fprintf(stderr, "Error: user name can not be empty.\n");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (user_name->length > USERNAME_LENGTH)
|
||||
{
|
||||
fprintf(stderr, "Error: user name must not exceed %d characters.\n",
|
||||
(int) USERNAME_LENGTH);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
The function is intended to provide password for user-management operations.
|
||||
The password is retrieved from command-line options (if specified) or from
|
||||
console.
|
||||
|
||||
SYNOPSYS
|
||||
get_password()
|
||||
|
||||
RETURN
|
||||
NULL on error
|
||||
valid pointer on success
|
||||
*/
|
||||
|
||||
static const char *get_password()
|
||||
{
|
||||
if (Options::User_management::password)
|
||||
return Options::User_management::password;
|
||||
|
||||
const char *passwd1= get_tty_password("Enter password: ");
|
||||
const char *passwd2= get_tty_password("Re-type password: ");
|
||||
|
||||
if (strcmp(passwd1, passwd2))
|
||||
{
|
||||
fprintf(stderr, "Error: passwords do not match.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return passwd1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Load password file into user map.
|
||||
|
||||
SYNOPSYS
|
||||
load_password_file()
|
||||
user_map target user map
|
||||
|
||||
RETURN
|
||||
See exit_codes.h for possible values.
|
||||
*/
|
||||
|
||||
static int load_password_file(User_map *user_map)
|
||||
{
|
||||
int err_code;
|
||||
const char *err_msg;
|
||||
|
||||
if (user_map->init())
|
||||
{
|
||||
fprintf(stderr, "Error: can not initialize user map.\n");
|
||||
return ERR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
if ((err_code= user_map->load(Options::Main::password_file_name, &err_msg)))
|
||||
fprintf(stderr, "Error: %s.\n", (const char *) err_msg);
|
||||
|
||||
return err_code;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Save user map into password file.
|
||||
|
||||
SYNOPSYS
|
||||
save_password_file()
|
||||
user_map user map
|
||||
|
||||
RETURN
|
||||
See exit_codes.h for possible values.
|
||||
*/
|
||||
|
||||
static int save_password_file(User_map *user_map)
|
||||
{
|
||||
int err_code;
|
||||
const char *err_msg;
|
||||
|
||||
if ((err_code= user_map->save(Options::Main::password_file_name, &err_msg)))
|
||||
fprintf(stderr, "Error: %s.\n", (const char *) err_msg);
|
||||
|
||||
return err_code;
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
Passwd_cmd
|
||||
*************************************************************************/
|
||||
|
||||
int Passwd_cmd::execute()
|
||||
{
|
||||
LEX_STRING user_name;
|
||||
const char *password;
|
||||
|
||||
printf("Creating record for new user.\n");
|
||||
|
||||
if (get_user_name(&user_name))
|
||||
return ERR_CAN_NOT_READ_USER_NAME;
|
||||
|
||||
if (!(password= get_password()))
|
||||
return ERR_CAN_NOT_READ_PASSWORD;
|
||||
|
||||
{
|
||||
User user(&user_name, password);
|
||||
|
||||
printf("%s:%s\n",
|
||||
(const char *) user.user,
|
||||
(const char *) user.scrambled_password);
|
||||
}
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
Add_user_cmd
|
||||
*************************************************************************/
|
||||
|
||||
int Add_user_cmd::execute()
|
||||
{
|
||||
LEX_STRING user_name;
|
||||
const char *password;
|
||||
char scrambled_password_buf[SCRAMBLED_PASSWORD_CHAR_LENGTH + 1];
|
||||
|
||||
User_map user_map;
|
||||
User *new_user;
|
||||
|
||||
int err_code;
|
||||
|
||||
if (get_user_name(&user_name))
|
||||
return ERR_CAN_NOT_READ_USER_NAME;
|
||||
|
||||
/* Load the password file. */
|
||||
|
||||
if ((err_code= load_password_file(&user_map)) != ERR_OK)
|
||||
return err_code;
|
||||
|
||||
/* Check that the user does not exist. */
|
||||
|
||||
if (user_map.find_user(&user_name))
|
||||
{
|
||||
fprintf(stderr, "Error: user '%s' already exists.\n",
|
||||
(const char *) user_name.str);
|
||||
return ERR_USER_ALREADY_EXISTS;
|
||||
}
|
||||
|
||||
/* Add the user. */
|
||||
|
||||
if (!(password= get_password()))
|
||||
return ERR_CAN_NOT_READ_PASSWORD;
|
||||
|
||||
if (!(new_user= new User(&user_name, password)))
|
||||
return ERR_OUT_OF_MEMORY;
|
||||
|
||||
if (user_map.add_user(new_user))
|
||||
{
|
||||
delete new_user;
|
||||
return ERR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
/* Save the password file. */
|
||||
|
||||
return save_password_file(&user_map);
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
Drop_user_cmd
|
||||
*************************************************************************/
|
||||
|
||||
int Drop_user_cmd::execute()
|
||||
{
|
||||
LEX_STRING user_name;
|
||||
|
||||
User_map user_map;
|
||||
User *user;
|
||||
|
||||
int err_code;
|
||||
|
||||
if (get_user_name(&user_name))
|
||||
return ERR_CAN_NOT_READ_USER_NAME;
|
||||
|
||||
/* Load the password file. */
|
||||
|
||||
if ((err_code= load_password_file(&user_map)) != ERR_OK)
|
||||
return err_code;
|
||||
|
||||
/* Find the user. */
|
||||
|
||||
user= user_map.find_user(&user_name);
|
||||
|
||||
if (!user)
|
||||
{
|
||||
fprintf(stderr, "Error: user '%s' does not exist.\n",
|
||||
(const char *) user_name.str);
|
||||
return ERR_USER_NOT_FOUND;
|
||||
}
|
||||
|
||||
/* Remove the user (ignore possible errors). */
|
||||
|
||||
user_map.remove_user(user);
|
||||
|
||||
/* Save the password file. */
|
||||
|
||||
return save_password_file(&user_map);
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
Edit_user_cmd
|
||||
*************************************************************************/
|
||||
|
||||
int Edit_user_cmd::execute()
|
||||
{
|
||||
LEX_STRING user_name;
|
||||
const char *password;
|
||||
char scrambled_password_buf[SCRAMBLED_PASSWORD_CHAR_LENGTH + 1];
|
||||
|
||||
User_map user_map;
|
||||
User *user;
|
||||
|
||||
int err_code;
|
||||
|
||||
if (get_user_name(&user_name))
|
||||
return ERR_CAN_NOT_READ_USER_NAME;
|
||||
|
||||
/* Load the password file. */
|
||||
|
||||
if ((err_code= load_password_file(&user_map)) != ERR_OK)
|
||||
return err_code;
|
||||
|
||||
/* Find the user. */
|
||||
|
||||
user= user_map.find_user(&user_name);
|
||||
|
||||
if (!user)
|
||||
{
|
||||
fprintf(stderr, "Error: user '%s' does not exist.\n",
|
||||
(const char *) user_name.str);
|
||||
return ERR_USER_NOT_FOUND;
|
||||
}
|
||||
|
||||
/* Modify user's password. */
|
||||
|
||||
if (!(password= get_password()))
|
||||
return ERR_CAN_NOT_READ_PASSWORD;
|
||||
|
||||
user->set_password(password);
|
||||
|
||||
/* Save the password file. */
|
||||
|
||||
return save_password_file(&user_map);
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
Clean_db_cmd
|
||||
*************************************************************************/
|
||||
|
||||
int Clean_db_cmd::execute()
|
||||
{
|
||||
User_map user_map;
|
||||
|
||||
if (user_map.init())
|
||||
{
|
||||
fprintf(stderr, "Error: can not initialize user map.\n");
|
||||
return ERR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
return save_password_file(&user_map);
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
Check_db_cmd
|
||||
*************************************************************************/
|
||||
|
||||
int Check_db_cmd::execute()
|
||||
{
|
||||
User_map user_map;
|
||||
|
||||
return load_password_file(&user_map);
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
List_users_cmd
|
||||
*************************************************************************/
|
||||
|
||||
int List_users_cmd::execute()
|
||||
{
|
||||
User_map user_map;
|
||||
|
||||
int err_code;
|
||||
|
||||
/* Load the password file. */
|
||||
|
||||
if ((err_code= load_password_file(&user_map)))
|
||||
return err_code;
|
||||
|
||||
/* Print out registered users. */
|
||||
|
||||
{
|
||||
User_map::Iterator it(&user_map);
|
||||
User *user;
|
||||
|
||||
while ((user= it.next()))
|
||||
fprintf(stderr, "%s\n", (const char *) user->user);
|
||||
}
|
||||
|
||||
return ERR_OK;
|
||||
}
|
167
server-tools/instance-manager/user_management_commands.h
Normal file
167
server-tools/instance-manager/user_management_commands.h
Normal file
@ -0,0 +1,167 @@
|
||||
#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_USER_MANAGEMENT_CMD_H
|
||||
#define INCLUDES_MYSQL_INSTANCE_MANAGER_USER_MANAGEMENT_CMD_H
|
||||
|
||||
/*
|
||||
Copyright (C) 2006 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
This header contains declarations of classes inteded to support
|
||||
user-management commands (such as add user, get list of users, etc).
|
||||
|
||||
The general idea is to have one interface (pure abstract class) for such a
|
||||
command. Each concrete user-management command is implemented in concrete
|
||||
class, derived from the common interface.
|
||||
*/
|
||||
|
||||
#if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE)
|
||||
#pragma interface
|
||||
#endif
|
||||
|
||||
/*************************************************************************
|
||||
User_management_cmd -- base class for User-management commands.
|
||||
*************************************************************************/
|
||||
|
||||
class User_management_cmd
|
||||
{
|
||||
public:
|
||||
User_management_cmd()
|
||||
{ }
|
||||
|
||||
virtual ~User_management_cmd()
|
||||
{ }
|
||||
|
||||
public:
|
||||
/*
|
||||
Executes user-management command.
|
||||
|
||||
SYNOPSYS
|
||||
execute()
|
||||
|
||||
RETURN
|
||||
See exit_codes.h for possible values.
|
||||
*/
|
||||
|
||||
virtual int execute() = 0;
|
||||
};
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
Passwd_cmd: support for --passwd command-line option.
|
||||
*************************************************************************/
|
||||
|
||||
class Passwd_cmd : public User_management_cmd
|
||||
{
|
||||
public:
|
||||
Passwd_cmd()
|
||||
{ }
|
||||
|
||||
public:
|
||||
virtual int execute();
|
||||
};
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
Add_user_cmd: support for --add-user command-line option.
|
||||
*************************************************************************/
|
||||
|
||||
class Add_user_cmd : public User_management_cmd
|
||||
{
|
||||
public:
|
||||
Add_user_cmd()
|
||||
{ }
|
||||
|
||||
public:
|
||||
virtual int execute();
|
||||
};
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
Drop_user_cmd: support for --drop-user command-line option.
|
||||
*************************************************************************/
|
||||
|
||||
class Drop_user_cmd : public User_management_cmd
|
||||
{
|
||||
public:
|
||||
Drop_user_cmd()
|
||||
{ }
|
||||
|
||||
public:
|
||||
virtual int execute();
|
||||
};
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
Edit_user_cmd: support for --edit-user command-line option.
|
||||
*************************************************************************/
|
||||
|
||||
class Edit_user_cmd : public User_management_cmd
|
||||
{
|
||||
public:
|
||||
Edit_user_cmd()
|
||||
{ }
|
||||
|
||||
public:
|
||||
virtual int execute();
|
||||
};
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
Clean_db_cmd: support for --clean-db command-line option.
|
||||
*************************************************************************/
|
||||
|
||||
class Clean_db_cmd : public User_management_cmd
|
||||
{
|
||||
public:
|
||||
Clean_db_cmd()
|
||||
{ }
|
||||
|
||||
public:
|
||||
virtual int execute();
|
||||
};
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
Check_db_cmd: support for --check-db command-line option.
|
||||
*************************************************************************/
|
||||
|
||||
class Check_db_cmd : public User_management_cmd
|
||||
{
|
||||
public:
|
||||
Check_db_cmd()
|
||||
{ }
|
||||
|
||||
public:
|
||||
virtual int execute();
|
||||
};
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
List_users_cmd: support for --list-users command-line option.
|
||||
*************************************************************************/
|
||||
|
||||
class List_users_cmd : public User_management_cmd
|
||||
{
|
||||
public:
|
||||
List_users_cmd()
|
||||
{ }
|
||||
|
||||
public:
|
||||
virtual int execute();
|
||||
};
|
||||
|
||||
#endif // INCLUDES_MYSQL_INSTANCE_MANAGER_USER_MANAGEMENT_CMD_H
|
@ -19,32 +19,31 @@
|
||||
#endif
|
||||
|
||||
#include "user_map.h"
|
||||
|
||||
#include <mysql_com.h>
|
||||
#include <m_string.h>
|
||||
|
||||
#include "exit_codes.h"
|
||||
#include "log.h"
|
||||
|
||||
struct User
|
||||
User::User(const LEX_STRING *user_name_arg, const char *password)
|
||||
{
|
||||
char user[USERNAME_LENGTH + 1];
|
||||
uint8 user_length;
|
||||
uint8 salt[SCRAMBLE_LENGTH];
|
||||
int init(const char *line);
|
||||
};
|
||||
user_length= strmake(user, user_name_arg->str, USERNAME_LENGTH + 1) - user;
|
||||
|
||||
set_password(password);
|
||||
}
|
||||
|
||||
int User::init(const char *line)
|
||||
{
|
||||
const char *name_begin, *name_end, *password;
|
||||
int line_ending_len= 1;
|
||||
int password_length;
|
||||
|
||||
if (line[0] == '\'' || line[0] == '"')
|
||||
{
|
||||
name_begin= line + 1;
|
||||
name_end= strchr(name_begin, line[0]);
|
||||
if (name_end == 0 || name_end[1] != ':')
|
||||
goto err;
|
||||
{
|
||||
log_info("Error: invalid format (unmatched quote) of user line (%s).",
|
||||
(const char *) line);
|
||||
return 1;
|
||||
}
|
||||
password= name_end + 2;
|
||||
}
|
||||
else
|
||||
@ -52,33 +51,47 @@ int User::init(const char *line)
|
||||
name_begin= line;
|
||||
name_end= strchr(name_begin, ':');
|
||||
if (name_end == 0)
|
||||
goto err;
|
||||
{
|
||||
log_info("Error: invalid format (no delimiter) of user line (%s).",
|
||||
(const char *) line);
|
||||
return 1;
|
||||
}
|
||||
password= name_end + 1;
|
||||
}
|
||||
|
||||
user_length= name_end - name_begin;
|
||||
if (user_length > USERNAME_LENGTH)
|
||||
goto err;
|
||||
{
|
||||
log_info("Error: user name is too long (%d). Max length: %d. "
|
||||
"User line: '%s'.",
|
||||
(int) user_length,
|
||||
(int) USERNAME_LENGTH,
|
||||
(const char *) line);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
assume that newline characater is present
|
||||
we support reading password files that end in \n or \r\n on
|
||||
either platform.
|
||||
*/
|
||||
if (password[strlen(password)-2] == '\r')
|
||||
line_ending_len= 2;
|
||||
if (strlen(password) != (uint) (SCRAMBLED_PASSWORD_CHAR_LENGTH +
|
||||
line_ending_len))
|
||||
goto err;
|
||||
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);
|
||||
return 1;
|
||||
}
|
||||
|
||||
memcpy(user, name_begin, user_length);
|
||||
user[user_length]= 0;
|
||||
|
||||
memcpy(scrambled_password, password, password_length);
|
||||
scrambled_password[password_length]= 0;
|
||||
|
||||
get_salt_from_password(salt, password);
|
||||
log_info("loaded user %s", user);
|
||||
|
||||
log_info("loaded user '%s'.", user);
|
||||
|
||||
return 0;
|
||||
err:
|
||||
log_error("error parsing user and password at line %s", line);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@ -101,30 +114,70 @@ static void delete_user(void *u)
|
||||
C_MODE_END
|
||||
|
||||
|
||||
void User_map::Iterator::reset()
|
||||
{
|
||||
cur_idx= 0;
|
||||
}
|
||||
|
||||
|
||||
User *User_map::Iterator::next()
|
||||
{
|
||||
if (cur_idx < user_map->hash.records)
|
||||
return (User *) hash_element(&user_map->hash, cur_idx++);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
int User_map::init()
|
||||
{
|
||||
enum { START_HASH_SIZE= 16 };
|
||||
if (hash_init(&hash, default_charset_info, START_HASH_SIZE, 0, 0,
|
||||
get_user_key, delete_user, 0))
|
||||
return 1;
|
||||
|
||||
initialized= TRUE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
User_map::User_map()
|
||||
:initialized(FALSE)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
User_map::~User_map()
|
||||
{
|
||||
hash_free(&hash);
|
||||
if (initialized)
|
||||
hash_free(&hash);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Load all users from the password file. Must be called once right after
|
||||
construction.
|
||||
In case of failure, puts error message to the log file and returns 1
|
||||
Load password database.
|
||||
|
||||
SYNOPSYS
|
||||
load()
|
||||
password_file_name [IN] password file path
|
||||
err_msg [OUT] error message
|
||||
|
||||
DESCRIPTION
|
||||
Load all users from the password file. Must be called once right after
|
||||
construction. In case of failure, puts error message to the log file and
|
||||
returns specific error code.
|
||||
|
||||
RETURN
|
||||
0 on success
|
||||
!0 on error
|
||||
*/
|
||||
|
||||
int User_map::load(const char *password_file_name)
|
||||
int User_map::load(const char *password_file_name, const char **err_msg)
|
||||
{
|
||||
static const int ERR_MSG_BUF_SIZE = 255;
|
||||
static char err_msg_buf[ERR_MSG_BUF_SIZE];
|
||||
|
||||
FILE *file;
|
||||
char line[USERNAME_LENGTH + SCRAMBLED_PASSWORD_CHAR_LENGTH +
|
||||
2 + /* for possible quotes */
|
||||
@ -134,33 +187,172 @@ int User_map::load(const char *password_file_name)
|
||||
User *user;
|
||||
int rc= 1;
|
||||
|
||||
if (my_access(password_file_name, F_OK) != 0)
|
||||
{
|
||||
if (err_msg)
|
||||
{
|
||||
snprintf(err_msg_buf, ERR_MSG_BUF_SIZE,
|
||||
"password file (%s) does not exist",
|
||||
(const char *) password_file_name);
|
||||
*err_msg= err_msg_buf;
|
||||
}
|
||||
|
||||
return ERR_PASSWORD_FILE_DOES_NOT_EXIST;
|
||||
}
|
||||
|
||||
if ((file= my_fopen(password_file_name, O_RDONLY | O_BINARY, MYF(0))) == 0)
|
||||
{
|
||||
/* Probably the password file wasn't specified. Try to leave without it */
|
||||
log_info("[WARNING] can't open password file %s: errno=%d, %s", password_file_name,
|
||||
errno, strerror(errno));
|
||||
return 0;
|
||||
if (err_msg)
|
||||
{
|
||||
snprintf(err_msg_buf, ERR_MSG_BUF_SIZE,
|
||||
"can not open password file (%s): %s",
|
||||
(const char *) password_file_name,
|
||||
(const char *) strerror(errno));
|
||||
*err_msg= err_msg_buf;
|
||||
}
|
||||
|
||||
return ERR_IO_ERROR;
|
||||
}
|
||||
|
||||
log_info("loading the password database...");
|
||||
|
||||
while (fgets(line, sizeof(line), file))
|
||||
{
|
||||
char *user_line= line;
|
||||
|
||||
/*
|
||||
We need to skip EOL-symbols also from the beginning of the line, because
|
||||
if the previous line was ended by \n\r sequence, we get \r in our line.
|
||||
*/
|
||||
|
||||
while (user_line[0] == '\r' || user_line[0] == '\n')
|
||||
++user_line;
|
||||
|
||||
/* Skip EOL-symbols in the end of the line. */
|
||||
|
||||
{
|
||||
char *ptr;
|
||||
|
||||
if ((ptr= strchr(user_line, '\n')))
|
||||
*ptr= 0;
|
||||
|
||||
if ((ptr= strchr(user_line, '\r')))
|
||||
*ptr= 0;
|
||||
}
|
||||
|
||||
/* skip comments and empty lines */
|
||||
if (line[0] == '#' || line[0] == '\n' &&
|
||||
(line[1] == '\0' || line[1] == '\r'))
|
||||
if (!user_line[0] || user_line[0] == '#')
|
||||
continue;
|
||||
|
||||
if ((user= new User) == 0)
|
||||
goto done;
|
||||
if (user->init(line) || my_hash_insert(&hash, (byte *) user))
|
||||
goto err_init_user;
|
||||
{
|
||||
my_fclose(file, MYF(0));
|
||||
|
||||
if (err_msg)
|
||||
{
|
||||
snprintf(err_msg_buf, ERR_MSG_BUF_SIZE,
|
||||
"out of memory while parsing password file (%s)",
|
||||
(const char *) password_file_name);
|
||||
*err_msg= err_msg_buf;
|
||||
}
|
||||
|
||||
return ERR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
if (user->init(user_line))
|
||||
{
|
||||
delete user;
|
||||
my_fclose(file, MYF(0));
|
||||
|
||||
if (err_msg)
|
||||
{
|
||||
snprintf(err_msg_buf, ERR_MSG_BUF_SIZE,
|
||||
"password file (%s) corrupted",
|
||||
(const char *) password_file_name);
|
||||
*err_msg= err_msg_buf;
|
||||
}
|
||||
|
||||
return ERR_PASSWORD_FILE_CORRUPTED;
|
||||
}
|
||||
|
||||
if (my_hash_insert(&hash, (byte *) user))
|
||||
{
|
||||
delete user;
|
||||
my_fclose(file, MYF(0));
|
||||
|
||||
if (err_msg)
|
||||
{
|
||||
snprintf(err_msg_buf, ERR_MSG_BUF_SIZE,
|
||||
"out of memory while parsing password file (%s)",
|
||||
(const char *) password_file_name);
|
||||
*err_msg= err_msg_buf;
|
||||
}
|
||||
|
||||
return ERR_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
if (feof(file))
|
||||
rc= 0;
|
||||
goto done;
|
||||
err_init_user:
|
||||
delete user;
|
||||
done:
|
||||
|
||||
log_info("the password database loaded successfully.");
|
||||
|
||||
my_fclose(file, MYF(0));
|
||||
return rc;
|
||||
|
||||
if (err_msg)
|
||||
*err_msg= NULL;
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
|
||||
int User_map::save(const char *password_file_name, const char **err_msg)
|
||||
{
|
||||
static const int ERR_MSG_BUF_SIZE = 255;
|
||||
static char err_msg_buf[ERR_MSG_BUF_SIZE];
|
||||
|
||||
FILE *file;
|
||||
|
||||
if ((file= my_fopen(password_file_name, O_WRONLY | O_TRUNC | O_BINARY,
|
||||
MYF(0))) == 0)
|
||||
{
|
||||
if (err_msg)
|
||||
{
|
||||
snprintf(err_msg_buf, ERR_MSG_BUF_SIZE,
|
||||
"can not open password file (%s) for writing: %s",
|
||||
(const char *) password_file_name,
|
||||
(const char *) strerror(errno));
|
||||
*err_msg= err_msg_buf;
|
||||
}
|
||||
|
||||
return ERR_IO_ERROR;
|
||||
}
|
||||
|
||||
{
|
||||
User_map::Iterator it(this);
|
||||
User *user;
|
||||
|
||||
while ((user= it.next()))
|
||||
{
|
||||
if (fprintf(file, "%s:%s\n", (const char *) user->user,
|
||||
(const char *) user->scrambled_password) < 0)
|
||||
{
|
||||
if (err_msg)
|
||||
{
|
||||
snprintf(err_msg_buf, ERR_MSG_BUF_SIZE,
|
||||
"can not write to password file (%s): %s",
|
||||
(const char *) password_file_name,
|
||||
(const char *) strerror(errno));
|
||||
*err_msg= err_msg_buf;
|
||||
}
|
||||
|
||||
my_fclose(file, MYF(0));
|
||||
|
||||
return ERR_IO_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
my_fclose(file, MYF(0));
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
|
||||
@ -172,13 +364,33 @@ done:
|
||||
2 - user not found
|
||||
*/
|
||||
|
||||
int User_map::authenticate(const char *user_name, uint length,
|
||||
int User_map::authenticate(const LEX_STRING *user_name,
|
||||
const char *scrambled_password,
|
||||
const char *scramble) const
|
||||
{
|
||||
const User *user= (const User *) hash_search((HASH *) &hash,
|
||||
(byte *) user_name, length);
|
||||
if (user)
|
||||
return check_scramble(scrambled_password, scramble, user->salt);
|
||||
return 2;
|
||||
const User *user= find_user(user_name);
|
||||
return user ? check_scramble(scrambled_password, scramble, user->salt) : 2;
|
||||
}
|
||||
|
||||
|
||||
User *User_map::find_user(const LEX_STRING *user_name)
|
||||
{
|
||||
return (User*) hash_search(&hash, (byte*) user_name->str, user_name->length);
|
||||
}
|
||||
|
||||
const User *User_map::find_user(const LEX_STRING *user_name) const
|
||||
{
|
||||
return const_cast<User_map *> (this)->find_user(user_name);
|
||||
}
|
||||
|
||||
|
||||
bool User_map::add_user(User *user)
|
||||
{
|
||||
return my_hash_insert(&hash, (byte*) user) == 0 ? FALSE : TRUE;
|
||||
}
|
||||
|
||||
|
||||
bool User_map::remove_user(User *user)
|
||||
{
|
||||
return hash_delete(&hash, (byte*) user) == 0 ? FALSE : TRUE;
|
||||
}
|
||||
|
@ -18,14 +18,35 @@
|
||||
|
||||
|
||||
#include <my_global.h>
|
||||
|
||||
#include <my_sys.h>
|
||||
#include <mysql_com.h>
|
||||
#include <m_string.h>
|
||||
#include <hash.h>
|
||||
|
||||
#if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE)
|
||||
#pragma interface
|
||||
#endif
|
||||
|
||||
struct User
|
||||
{
|
||||
User()
|
||||
{}
|
||||
|
||||
User(const LEX_STRING *user_name_arg, const char *password);
|
||||
|
||||
int init(const char *line);
|
||||
|
||||
inline void set_password(const char *password)
|
||||
{
|
||||
make_scrambled_password(scrambled_password, password);
|
||||
}
|
||||
|
||||
char user[USERNAME_LENGTH + 1];
|
||||
char scrambled_password[SCRAMBLED_PASSWORD_CHAR_LENGTH + 1];
|
||||
uint8 user_length;
|
||||
uint8 salt[SCRAMBLE_LENGTH];
|
||||
};
|
||||
|
||||
/*
|
||||
User_map -- all users and passwords
|
||||
*/
|
||||
@ -33,15 +54,51 @@
|
||||
class User_map
|
||||
{
|
||||
public:
|
||||
/* User_map iterator */
|
||||
|
||||
class Iterator
|
||||
{
|
||||
public:
|
||||
Iterator(User_map *user_map_arg) :
|
||||
cur_idx(0), user_map(user_map_arg)
|
||||
{ }
|
||||
|
||||
public:
|
||||
void reset();
|
||||
|
||||
User *next();
|
||||
|
||||
private:
|
||||
User_map *user_map;
|
||||
uint cur_idx;
|
||||
};
|
||||
|
||||
public:
|
||||
User_map();
|
||||
~User_map();
|
||||
|
||||
int init();
|
||||
int load(const char *password_file_name);
|
||||
int authenticate(const char *user_name, uint length,
|
||||
int load(const char *password_file_name, const char **err_msg);
|
||||
int save(const char *password_file_name, const char **err_msg);
|
||||
int authenticate(const LEX_STRING *user_name,
|
||||
const char *scrambled_password,
|
||||
const char *scramble) const;
|
||||
|
||||
const User *find_user(const LEX_STRING *user_name) const;
|
||||
User *find_user(const LEX_STRING *user_name);
|
||||
|
||||
bool add_user(User *user);
|
||||
bool remove_user(User *user);
|
||||
|
||||
private:
|
||||
User_map(const User_map &);
|
||||
User_map &operator =(const User_map &);
|
||||
|
||||
private:
|
||||
HASH hash;
|
||||
bool initialized;
|
||||
|
||||
friend class Iterator;
|
||||
};
|
||||
|
||||
#endif // INCLUDES_MYSQL_INSTANCE_MANAGER_USER_MAP_H
|
||||
|
10
sql/sp.cc
10
sql/sp.cc
@ -409,15 +409,13 @@ db_load_routine(THD *thd, int type, sp_name *name, sp_head **sphp,
|
||||
ulong old_sql_mode= thd->variables.sql_mode;
|
||||
ha_rows old_select_limit= thd->variables.select_limit;
|
||||
sp_rcontext *old_spcont= thd->spcont;
|
||||
|
||||
|
||||
char definer_user_name_holder[USERNAME_LENGTH + 1];
|
||||
LEX_STRING_WITH_INIT definer_user_name(definer_user_name_holder,
|
||||
USERNAME_LENGTH);
|
||||
LEX_STRING definer_user_name= { definer_user_name_holder, USERNAME_LENGTH };
|
||||
|
||||
char definer_host_name_holder[HOSTNAME_LENGTH + 1];
|
||||
LEX_STRING_WITH_INIT definer_host_name(definer_host_name_holder,
|
||||
HOSTNAME_LENGTH);
|
||||
|
||||
LEX_STRING definer_host_name= { definer_host_name_holder, HOSTNAME_LENGTH };
|
||||
|
||||
int ret;
|
||||
|
||||
thd->variables.sql_mode= sql_mode;
|
||||
|
@ -1850,10 +1850,10 @@ void
|
||||
sp_head::set_definer(const char *definer, uint definerlen)
|
||||
{
|
||||
char user_name_holder[USERNAME_LENGTH + 1];
|
||||
LEX_STRING_WITH_INIT user_name(user_name_holder, USERNAME_LENGTH);
|
||||
LEX_STRING user_name= { user_name_holder, USERNAME_LENGTH };
|
||||
|
||||
char host_name_holder[HOSTNAME_LENGTH + 1];
|
||||
LEX_STRING_WITH_INIT host_name(host_name_holder, HOSTNAME_LENGTH);
|
||||
LEX_STRING host_name= { host_name_holder, HOSTNAME_LENGTH };
|
||||
|
||||
parse_user(definer, definerlen, user_name.str, &user_name.length,
|
||||
host_name.str, &host_name.length);
|
||||
|
@ -34,8 +34,11 @@ static Geometry::Class_info **ci_collection_end=
|
||||
|
||||
Geometry::Class_info::Class_info(const char *name, int type_id,
|
||||
void(*create_func)(void *)):
|
||||
m_name(name, strlen(name)), m_type_id(type_id), m_create_func(create_func)
|
||||
m_type_id(type_id), m_create_func(create_func)
|
||||
{
|
||||
m_name.str= (char *) name;
|
||||
m_name.length= strlen(name);
|
||||
|
||||
ci_collection[type_id]= this;
|
||||
}
|
||||
|
||||
|
@ -200,7 +200,7 @@ public:
|
||||
class Class_info
|
||||
{
|
||||
public:
|
||||
LEX_STRING_WITH_INIT m_name;
|
||||
LEX_STRING m_name;
|
||||
int m_type_id;
|
||||
void (*m_create_func)(void *);
|
||||
Class_info(const char *name, int type_id, void(*create_func)(void *));
|
||||
|
@ -24,8 +24,6 @@
|
||||
#define NOT_FIXED_DEC 31
|
||||
#endif
|
||||
|
||||
#define STRING_WITH_LEN(X) ((const char*) X), ((uint) (sizeof(X) - 1))
|
||||
|
||||
class String;
|
||||
int sortcmp(const String *a,const String *b, CHARSET_INFO *cs);
|
||||
String *copy_if_not_alloced(String *a,String *b,uint32 arg_length);
|
||||
|
@ -1412,8 +1412,8 @@ bool Table_triggers_list::change_table_name(THD *thd, const char *db,
|
||||
}
|
||||
if (table.triggers)
|
||||
{
|
||||
LEX_STRING_WITH_INIT old_table_name(old_table, strlen(old_table));
|
||||
LEX_STRING_WITH_INIT new_table_name(new_table, strlen(new_table));
|
||||
LEX_STRING old_table_name= { (char *) STRING_WITH_LEN(old_table) };
|
||||
LEX_STRING new_table_name= { (char *) STRING_WITH_LEN(new_table) };
|
||||
/*
|
||||
Since triggers should be in the same schema as their subject tables
|
||||
moving table with them between two schemas raises too many questions.
|
||||
|
@ -20,22 +20,6 @@
|
||||
struct st_table;
|
||||
class Field;
|
||||
|
||||
typedef struct st_lex_string
|
||||
{
|
||||
char *str;
|
||||
uint length;
|
||||
} LEX_STRING;
|
||||
|
||||
typedef struct st_lex_string_with_init :public st_lex_string
|
||||
{
|
||||
st_lex_string_with_init(const char *str_arg, uint length_arg)
|
||||
{
|
||||
str= (char*) str_arg;
|
||||
length= length_arg;
|
||||
}
|
||||
} LEX_STRING_WITH_INIT;
|
||||
|
||||
|
||||
typedef struct st_date_time_format {
|
||||
uchar positions[8];
|
||||
char time_separator; /* Separator between hour and minute */
|
||||
|
@ -265,7 +265,10 @@ case "$mode" in
|
||||
then
|
||||
# Give extra arguments to mysqld with the my.cnf file. This script may
|
||||
# be overwritten at next upgrade.
|
||||
$manager --user=$user --pid-file=$pid_file >/dev/null 2>&1 &
|
||||
"$manager" \
|
||||
--mysqld-safe-compatible \
|
||||
--user="$user" \
|
||||
--pid-file="$pid_file" >/dev/null 2>&1 &
|
||||
wait_for_pid created
|
||||
|
||||
# Make lock for RedHat / SuSE
|
||||
|
Loading…
x
Reference in New Issue
Block a user