Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
M
mariadb
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
mariadb
Commits
451de5db
Commit
451de5db
authored
Feb 19, 2005
by
petr@mysql.com
Browse files
Options
Browse Files
Download
Plain Diff
merge
parents
32a3c163
27e614dc
Changes
34
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
34 changed files
with
1197 additions
and
733 deletions
+1197
-733
include/my_sys.h
include/my_sys.h
+4
-4
mysys/default.c
mysys/default.c
+4
-38
server-tools/instance-manager/Makefile.am
server-tools/instance-manager/Makefile.am
+6
-6
server-tools/instance-manager/buffer.cc
server-tools/instance-manager/buffer.cc
+18
-6
server-tools/instance-manager/buffer.h
server-tools/instance-manager/buffer.h
+12
-3
server-tools/instance-manager/client_func.c
server-tools/instance-manager/client_func.c
+0
-32
server-tools/instance-manager/commands.cc
server-tools/instance-manager/commands.cc
+13
-31
server-tools/instance-manager/guardian.cc
server-tools/instance-manager/guardian.cc
+257
-50
server-tools/instance-manager/guardian.h
server-tools/instance-manager/guardian.h
+27
-9
server-tools/instance-manager/instance.cc
server-tools/instance-manager/instance.cc
+186
-49
server-tools/instance-manager/instance.h
server-tools/instance-manager/instance.h
+14
-10
server-tools/instance-manager/instance_map.cc
server-tools/instance-manager/instance_map.cc
+55
-48
server-tools/instance-manager/instance_map.h
server-tools/instance-manager/instance_map.h
+3
-7
server-tools/instance-manager/instance_options.cc
server-tools/instance-manager/instance_options.cc
+156
-21
server-tools/instance-manager/instance_options.h
server-tools/instance-manager/instance_options.h
+19
-9
server-tools/instance-manager/listener.cc
server-tools/instance-manager/listener.cc
+33
-16
server-tools/instance-manager/log.cc
server-tools/instance-manager/log.cc
+2
-2
server-tools/instance-manager/log.h
server-tools/instance-manager/log.h
+2
-2
server-tools/instance-manager/manager.cc
server-tools/instance-manager/manager.cc
+53
-21
server-tools/instance-manager/messages.cc
server-tools/instance-manager/messages.cc
+2
-2
server-tools/instance-manager/mysql_connection.cc
server-tools/instance-manager/mysql_connection.cc
+0
-7
server-tools/instance-manager/mysqlmanager.cc
server-tools/instance-manager/mysqlmanager.cc
+91
-1
server-tools/instance-manager/options.cc
server-tools/instance-manager/options.cc
+72
-24
server-tools/instance-manager/options.h
server-tools/instance-manager/options.h
+7
-3
server-tools/instance-manager/parse.cc
server-tools/instance-manager/parse.cc
+0
-23
server-tools/instance-manager/parse.h
server-tools/instance-manager/parse.h
+30
-0
server-tools/instance-manager/parse_output.cc
server-tools/instance-manager/parse_output.cc
+101
-0
server-tools/instance-manager/parse_output.h
server-tools/instance-manager/parse_output.h
+19
-0
server-tools/instance-manager/protocol.cc
server-tools/instance-manager/protocol.cc
+2
-1
server-tools/instance-manager/thread_registry.cc
server-tools/instance-manager/thread_registry.cc
+1
-0
server-tools/instance-manager/thread_repository.cc
server-tools/instance-manager/thread_repository.cc
+0
-185
server-tools/instance-manager/thread_repository.h
server-tools/instance-manager/thread_repository.h
+0
-113
server-tools/instance-manager/user_map.cc
server-tools/instance-manager/user_map.cc
+4
-3
support-files/mysql.spec.sh
support-files/mysql.spec.sh
+4
-7
No files found.
include/my_sys.h
View file @
451de5db
...
@@ -531,7 +531,7 @@ typedef uint32 ha_checksum;
...
@@ -531,7 +531,7 @@ typedef uint32 ha_checksum;
/* Define the type of function to be passed to process_default_option_files */
/* Define the type of function to be passed to process_default_option_files */
typedef
int
(
*
Process_option_func
)(
void
*
ctx
,
const
char
*
group_name
,
typedef
int
(
*
Process_option_func
)(
void
*
ctx
,
const
char
*
group_name
,
const
char
*
option
);
const
char
*
option
);
#include <my_alloc.h>
#include <my_alloc.h>
...
@@ -776,9 +776,9 @@ extern void get_defaults_files(int argc, char **argv,
...
@@ -776,9 +776,9 @@ extern void get_defaults_files(int argc, char **argv,
char
**
defaults
,
char
**
extra_defaults
);
char
**
defaults
,
char
**
extra_defaults
);
extern
int
load_defaults
(
const
char
*
conf_file
,
const
char
**
groups
,
extern
int
load_defaults
(
const
char
*
conf_file
,
const
char
**
groups
,
int
*
argc
,
char
***
argv
);
int
*
argc
,
char
***
argv
);
extern
int
process_default_option_files
(
const
char
*
conf_file
,
extern
int
my_search_option_files
(
const
char
*
conf_file
,
int
*
argc
,
Process_option_func
func
,
char
***
argv
,
uint
*
args_used
,
void
*
func_ctx
);
Process_option_func
func
,
void
*
func_ctx
);
extern
void
free_defaults
(
char
**
argv
);
extern
void
free_defaults
(
char
**
argv
);
extern
void
print_defaults
(
const
char
*
conf_file
,
const
char
**
groups
);
extern
void
print_defaults
(
const
char
*
conf_file
,
const
char
**
groups
);
extern
my_bool
my_compress
(
byte
*
,
ulong
*
,
ulong
*
);
extern
my_bool
my_compress
(
byte
*
,
ulong
*
,
ulong
*
);
...
...
mysys/default.c
View file @
451de5db
...
@@ -83,7 +83,7 @@ static char *remove_end_comment(char *ptr);
...
@@ -83,7 +83,7 @@ static char *remove_end_comment(char *ptr);
Process config files in default directories.
Process config files in default directories.
SYNOPSIS
SYNOPSIS
search
_files()
my_search_option
_files()
conf_file Basename for configuration file to search for.
conf_file Basename for configuration file to search for.
If this is a path, then only this file is read.
If this is a path, then only this file is read.
argc Pointer to argc of original program
argc Pointer to argc of original program
...
@@ -103,13 +103,13 @@ static char *remove_end_comment(char *ptr);
...
@@ -103,13 +103,13 @@ static char *remove_end_comment(char *ptr);
1 given cinf_file doesn't exist
1 given cinf_file doesn't exist
*/
*/
static
int
search
_files
(
const
char
*
conf_file
,
int
*
argc
,
char
***
argv
,
int
my_search_option
_files
(
const
char
*
conf_file
,
int
*
argc
,
char
***
argv
,
uint
*
args_used
,
Process_option_func
func
,
uint
*
args_used
,
Process_option_func
func
,
void
*
func_ctx
)
void
*
func_ctx
)
{
{
const
char
**
dirs
,
*
forced_default_file
;
const
char
**
dirs
,
*
forced_default_file
;
int
error
=
0
;
int
error
=
0
;
DBUG_ENTER
(
"
search
_files"
);
DBUG_ENTER
(
"
my_search_option
_files"
);
/* Check if we want to force the use a specific default file */
/* Check if we want to force the use a specific default file */
get_defaults_files
(
*
argc
,
*
argv
,
get_defaults_files
(
*
argc
,
*
argv
,
...
@@ -180,40 +180,6 @@ err:
...
@@ -180,40 +180,6 @@ err:
}
}
/*
Simplified version of search_files (no argv, argc to process).
SYNOPSIS
process_default_option_files()
conf_file Basename for configuration file to search for.
If this is a path, then only this file is read.
func Pointer to the function to process options
func_ctx It's context. Usually it is the structure to
store additional options.
DESCRIPTION
Often we want only to get options from default config files. In this case we
don't want to provide any argc and argv parameters. This function is a
simplified variant of search_files which allows us to forget about
argc, argv.
RETURN
0 ok
1 given cinf_file doesn't exist
*/
int
process_default_option_files
(
const
char
*
conf_file
,
Process_option_func
func
,
void
*
func_ctx
)
{
int
argc
=
1
;
/* this is a dummy variable for search_files() */
uint
args_used
;
return
search_files
(
conf_file
,
&
argc
,
NULL
,
&
args_used
,
func
,
func_ctx
);
}
/*
/*
The option handler for load_defaults.
The option handler for load_defaults.
...
@@ -363,7 +329,7 @@ int load_defaults(const char *conf_file, const char **groups,
...
@@ -363,7 +329,7 @@ int load_defaults(const char *conf_file, const char **groups,
ctx
.
args
=
&
args
;
ctx
.
args
=
&
args
;
ctx
.
group
=
&
group
;
ctx
.
group
=
&
group
;
error
=
search
_files
(
conf_file
,
argc
,
argv
,
&
args_used
,
error
=
my_search_option
_files
(
conf_file
,
argc
,
argv
,
&
args_used
,
handle_default_option
,
(
void
*
)
&
ctx
);
handle_default_option
,
(
void
*
)
&
ctx
);
/*
/*
Here error contains <> 0 only if we have a fully specified conf_file
Here error contains <> 0 only if we have a fully specified conf_file
...
...
server-tools/instance-manager/Makefile.am
View file @
451de5db
...
@@ -30,14 +30,13 @@ liboptions_a_CPPFLAGS= $(CPPFLAGS) \
...
@@ -30,14 +30,13 @@ liboptions_a_CPPFLAGS= $(CPPFLAGS) \
-DDEFAULT_LOG_FILE_NAME
=
"
$(localstatedir)
/mysqlmanager.log"
\
-DDEFAULT_LOG_FILE_NAME
=
"
$(localstatedir)
/mysqlmanager.log"
\
-DDEFAULT_SOCKET_FILE_NAME
=
"
$(localstatedir)
/mysqlmanager.sock"
\
-DDEFAULT_SOCKET_FILE_NAME
=
"
$(localstatedir)
/mysqlmanager.sock"
\
-DDEFAULT_PASSWORD_FILE_NAME
=
"
$(sysconfdir)
/mysqlmanager.passwd"
\
-DDEFAULT_PASSWORD_FILE_NAME
=
"
$(sysconfdir)
/mysqlmanager.passwd"
\
-DDEFAULT_MYSQLD_PATH
=
"
$(bindir)
/mysqld
$(EXEEXT)
"
\
-DDEFAULT_MYSQLD_PATH
=
"
$(libexecdir)
/mysqld
$(EXEEXT)
"
\
-DDEFAULT_USER
=
"root"
\
-DDEFAULT_MONITORING_INTERVAL
=
"20"
\
-DDEFAULT_PASSWORD
=
""
\
-DDEFAULT_MONITORING_INTERVAL
=
"5"
\
-DDEFAULT_PORT
=
"2273"
\
-DDEFAULT_PORT
=
"2273"
\
-DPROTOCOL_VERSION
=
@PROTOCOL_VERSION@
-DPROTOCOL_VERSION
=
@PROTOCOL_VERSION@
liboptions_a_SOURCES
=
options.h options.cc priv.h priv.cc
liboptions_a_SOURCES
=
options.h options.cc priv.h priv.cc
liboptions_a_LIBADD
=
$(top_builddir)
/libmysql/get_password.
$(OBJEXT)
# MySQL sometimes uses symlinks to reuse code
# MySQL sometimes uses symlinks to reuse code
# All symlinked files are grouped in libnet.a
# All symlinked files are grouped in libnet.a
...
@@ -59,7 +58,7 @@ client_settings.h: Makefile
...
@@ -59,7 +58,7 @@ client_settings.h: Makefile
rm
-f
$(srcdir)
/client_settings.h
rm
-f
$(srcdir)
/client_settings.h
@
LN_CP_F@
$(top_srcdir)
/sql/client_settings.h
$(srcdir)
/client_settings.h
@
LN_CP_F@
$(top_srcdir)
/sql/client_settings.h
$(srcdir)
/client_settings.h
bin
_PROGRAMS
=
mysqlmanager
libexec
_PROGRAMS
=
mysqlmanager
mysqlmanager_SOURCES
=
command.cc command.h mysqlmanager.cc
\
mysqlmanager_SOURCES
=
command.cc command.h mysqlmanager.cc
\
manager.h manager.cc log.h log.cc
\
manager.h manager.cc log.h log.cc
\
...
@@ -75,7 +74,8 @@ mysqlmanager_SOURCES= command.cc command.h mysqlmanager.cc \
...
@@ -75,7 +74,8 @@ mysqlmanager_SOURCES= command.cc command.h mysqlmanager.cc \
instance_options.h instance_options.cc
\
instance_options.h instance_options.cc
\
buffer.h buffer.cc parse.cc parse.h
\
buffer.h buffer.cc parse.cc parse.h
\
guardian.cc guardian.h
\
guardian.cc guardian.h
\
mysql_manager_error.h client_func.c
parse_output.cc parse_output.h
\
mysql_manager_error.h
mysqlmanager_LDADD
=
liboptions.a
\
mysqlmanager_LDADD
=
liboptions.a
\
libnet.a
\
libnet.a
\
...
...
server-tools/instance-manager/buffer.cc
View file @
451de5db
...
@@ -40,7 +40,7 @@
...
@@ -40,7 +40,7 @@
RETURN
RETURN
0 - ok
0 - ok
1 -
The buffer came to 16Mb barrier
1 -
got an error in reserve()
*/
*/
int
Buffer
::
append
(
uint
position
,
const
char
*
string
,
uint
len_arg
)
int
Buffer
::
append
(
uint
position
,
const
char
*
string
,
uint
len_arg
)
...
@@ -71,7 +71,7 @@ int Buffer::append(uint position, const char *string, uint len_arg)
...
@@ -71,7 +71,7 @@ int Buffer::append(uint position, const char *string, uint len_arg)
RETURN
RETURN
0 - ok
0 - ok
1 -
The buffer came to
16Mb barrier
1 -
realloc error or we have come to the
16Mb barrier
*/
*/
int
Buffer
::
reserve
(
uint
position
,
uint
len_arg
)
int
Buffer
::
reserve
(
uint
position
,
uint
len_arg
)
...
@@ -81,10 +81,10 @@ int Buffer::reserve(uint position, uint len_arg)
...
@@ -81,10 +81,10 @@ int Buffer::reserve(uint position, uint len_arg)
if
(
position
+
len_arg
>=
buffer_size
)
if
(
position
+
len_arg
>=
buffer_size
)
{
{
buffer
=
(
char
*
)
realloc
(
buffer
,
buffer
=
(
char
*
)
my_
realloc
(
buffer
,
min
(
MAX_BUFFER_SIZE
,
min
(
MAX_BUFFER_SIZE
,
max
((
uint
)
(
buffer_size
*
1.5
),
max
((
uint
)
(
buffer_size
*
1.5
),
position
+
len_arg
)
));
position
+
len_arg
)),
MYF
(
0
));
if
(
buffer
==
NULL
)
if
(
buffer
==
NULL
)
goto
err
;
goto
err
;
buffer_size
=
(
uint
)
(
buffer_size
*
1.5
);
buffer_size
=
(
uint
)
(
buffer_size
*
1.5
);
...
@@ -92,6 +92,18 @@ int Buffer::reserve(uint position, uint len_arg)
...
@@ -92,6 +92,18 @@ int Buffer::reserve(uint position, uint len_arg)
return
0
;
return
0
;
err:
err:
error
=
1
;
return
1
;
return
1
;
}
}
int
Buffer
::
get_size
()
{
return
buffer_size
;
}
int
Buffer
::
is_error
()
{
return
error
;
}
server-tools/instance-manager/buffer.h
View file @
451de5db
...
@@ -17,6 +17,7 @@
...
@@ -17,6 +17,7 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include <my_global.h>
#include <my_global.h>
#include <my_sys.h>
#ifdef __GNUC__
#ifdef __GNUC__
#pragma interface
#pragma interface
...
@@ -36,11 +37,17 @@ private:
...
@@ -36,11 +37,17 @@ private:
/* maximum buffer size is 16Mb */
/* maximum buffer size is 16Mb */
enum
{
MAX_BUFFER_SIZE
=
16777216
};
enum
{
MAX_BUFFER_SIZE
=
16777216
};
size_t
buffer_size
;
size_t
buffer_size
;
/* Error flag. Triggered if we get an error of some kind */
int
error
;
public:
public:
Buffer
()
Buffer
(
size_t
buffer_size_arg
=
BUFFER_INITIAL_SIZE
)
:
buffer_size
(
BUFFER_INITIAL_SIZE
),
error
(
0
)
{
{
buffer
=
(
char
*
)
malloc
(
BUFFER_INITIAL_SIZE
);
/*
buffer_size
=
BUFFER_INITIAL_SIZE
;
As append() will invokes realloc() anyway, it's ok if malloc returns 0
*/
if
(
!
(
buffer
=
(
char
*
)
my_malloc
(
buffer_size
,
MYF
(
0
))))
buffer_size
=
0
;
}
}
~
Buffer
()
~
Buffer
()
...
@@ -50,6 +57,8 @@ public:
...
@@ -50,6 +57,8 @@ public:
public:
public:
char
*
buffer
;
char
*
buffer
;
int
get_size
();
int
is_error
();
int
append
(
uint
position
,
const
char
*
string
,
uint
len_arg
);
int
append
(
uint
position
,
const
char
*
string
,
uint
len_arg
);
int
reserve
(
uint
position
,
uint
len_arg
);
int
reserve
(
uint
position
,
uint
len_arg
);
};
};
...
...
server-tools/instance-manager/client_func.c
deleted
100644 → 0
View file @
32a3c163
#include <my_global.h>
#include <my_sys.h>
#include <mysql.h>
/*
Currently we cannot use libmysqlclient directly becouse of the linking
issues. Here we provide needed libmysqlclient functions.
TODO: to think how to use libmysqlclient code instead of copy&paste.
The other possible solution is to use simple_command directly.
*/
const
char
*
STDCALL
mysql_get_server_info
(
MYSQL
*
mysql
)
{
return
((
char
*
)
mysql
->
server_version
);
}
int
STDCALL
mysql_ping
(
MYSQL
*
mysql
)
{
DBUG_ENTER
(
"mysql_ping"
);
DBUG_RETURN
(
simple_command
(
mysql
,
COM_PING
,
0
,
0
,
0
));
}
int
STDCALL
mysql_shutdown
(
MYSQL
*
mysql
,
enum
mysql_enum_shutdown_level
shutdown_level
)
{
uchar
level
[
1
];
DBUG_ENTER
(
"mysql_shutdown"
);
level
[
0
]
=
(
uchar
)
shutdown_level
;
DBUG_RETURN
(
simple_command
(
mysql
,
COM_SHUTDOWN
,
(
char
*
)
level
,
1
,
0
));
}
server-tools/instance-manager/commands.cc
View file @
451de5db
...
@@ -175,7 +175,7 @@ int Show_instance_status::do_command(struct st_net *net,
...
@@ -175,7 +175,7 @@ int Show_instance_status::do_command(struct st_net *net,
if
(
instance
->
is_running
())
if
(
instance
->
is_running
())
{
{
store_to_string
(
&
send_buff
,
(
char
*
)
"online"
,
&
position
);
store_to_string
(
&
send_buff
,
(
char
*
)
"online"
,
&
position
);
store_to_string
(
&
send_buff
,
mysql_get_server_info
(
&
(
instance
->
mysql
))
,
&
position
);
store_to_string
(
&
send_buff
,
"unknown"
,
&
position
);
}
}
else
else
{
{
...
@@ -184,7 +184,8 @@ int Show_instance_status::do_command(struct st_net *net,
...
@@ -184,7 +184,8 @@ int Show_instance_status::do_command(struct st_net *net,
}
}
if
(
my_net_write
(
net
,
send_buff
.
buffer
,
(
uint
)
position
))
if
(
send_buff
.
is_error
()
||
my_net_write
(
net
,
send_buff
.
buffer
,
(
uint
)
position
))
goto
err
;
goto
err
;
}
}
...
@@ -270,38 +271,18 @@ int Show_instance_options::do_command(struct st_net *net,
...
@@ -270,38 +271,18 @@ int Show_instance_options::do_command(struct st_net *net,
store_to_string
(
&
send_buff
,
store_to_string
(
&
send_buff
,
(
char
*
)
instance
->
options
.
mysqld_path
,
(
char
*
)
instance
->
options
.
mysqld_path
,
&
position
);
&
position
);
if
(
my_net_write
(
net
,
send_buff
.
buffer
,
(
uint
)
position
))
if
(
send_buff
.
is_error
()
||
my_net_write
(
net
,
send_buff
.
buffer
,
(
uint
)
position
))
goto
err
;
goto
err
;
}
}
if
(
instance
->
options
.
is_
guarded
!=
NULL
)
if
(
instance
->
options
.
non
guarded
!=
NULL
)
{
{
position
=
0
;
position
=
0
;
store_to_string
(
&
send_buff
,
(
char
*
)
"guarded"
,
&
position
);
store_to_string
(
&
send_buff
,
(
char
*
)
"
non
guarded"
,
&
position
);
store_to_string
(
&
send_buff
,
""
,
&
position
);
store_to_string
(
&
send_buff
,
""
,
&
position
);
if
(
my_net_write
(
net
,
send_buff
.
buffer
,
(
uint
)
position
))
if
(
send_buff
.
is_error
()
||
goto
err
;
my_net_write
(
net
,
send_buff
.
buffer
,
(
uint
)
position
))
}
if
(
instance
->
options
.
mysqld_user
!=
NULL
)
{
position
=
0
;
store_to_string
(
&
send_buff
,
(
char
*
)
"admin-user"
,
&
position
);
store_to_string
(
&
send_buff
,
(
char
*
)
instance
->
options
.
mysqld_user
,
&
position
);
if
(
my_net_write
(
net
,
send_buff
.
buffer
,
(
uint
)
position
))
goto
err
;
}
if
(
instance
->
options
.
mysqld_password
!=
NULL
)
{
position
=
0
;
store_to_string
(
&
send_buff
,
(
char
*
)
"admin-password"
,
&
position
);
store_to_string
(
&
send_buff
,
(
char
*
)
instance
->
options
.
mysqld_password
,
&
position
);
if
(
my_net_write
(
net
,
send_buff
.
buffer
,
(
uint
)
position
))
goto
err
;
goto
err
;
}
}
...
@@ -318,7 +299,8 @@ int Show_instance_options::do_command(struct st_net *net,
...
@@ -318,7 +299,8 @@ int Show_instance_options::do_command(struct st_net *net,
store_to_string
(
&
send_buff
,
option_value
+
1
,
&
position
);
store_to_string
(
&
send_buff
,
option_value
+
1
,
&
position
);
/* join name and the value into the same option again */
/* join name and the value into the same option again */
*
option_value
=
'='
;
*
option_value
=
'='
;
if
(
my_net_write
(
net
,
send_buff
.
buffer
,
(
uint
)
position
))
if
(
send_buff
.
is_error
()
||
my_net_write
(
net
,
send_buff
.
buffer
,
(
uint
)
position
))
goto
err
;
goto
err
;
}
}
}
}
...
@@ -372,7 +354,7 @@ int Start_instance::execute(struct st_net *net, ulong connection_id)
...
@@ -372,7 +354,7 @@ int Start_instance::execute(struct st_net *net, ulong connection_id)
if
(
err_code
=
instance
->
start
())
if
(
err_code
=
instance
->
start
())
return
err_code
;
return
err_code
;
if
(
instance
->
options
.
is_guarded
!
=
NULL
)
if
(
instance
->
options
.
nonguarded
=
=
NULL
)
instance_map
->
guardian
->
guard
(
instance
);
instance_map
->
guardian
->
guard
(
instance
);
net_send_ok
(
net
,
connection_id
);
net_send_ok
(
net
,
connection_id
);
...
@@ -403,7 +385,7 @@ int Stop_instance::execute(struct st_net *net, ulong connection_id)
...
@@ -403,7 +385,7 @@ int Stop_instance::execute(struct st_net *net, ulong connection_id)
}
}
else
else
{
{
if
(
instance
->
options
.
is_guarded
!
=
NULL
)
if
(
instance
->
options
.
nonguarded
=
=
NULL
)
instance_map
->
guardian
->
instance_map
->
guardian
->
stop_guard
(
instance
);
stop_guard
(
instance
);
if
((
err_code
=
instance
->
stop
()))
if
((
err_code
=
instance
->
stop
()))
...
...
server-tools/instance-manager/guardian.cc
View file @
451de5db
This diff is collapsed.
Click to expand it.
server-tools/instance-manager/guardian.h
View file @
451de5db
...
@@ -19,15 +19,16 @@
...
@@ -19,15 +19,16 @@
#include <my_global.h>
#include <my_global.h>
#include <my_sys.h>
#include <my_sys.h>
#include <my_list.h>
#include <my_list.h>
#include "thread_registry.h"
#ifdef __GNUC__
#ifdef __GNUC__
#pragma interface
#pragma interface
#endif
#endif
class
Instance
;
class
Instance_map
;
class
Instance_map
;
class
Thread_registry
;
#include "thread_registry.h"
struct
GUARD_NODE
;
#include "instance.h"
C_MODE_START
C_MODE_START
...
@@ -35,12 +36,11 @@ pthread_handler_decl(guardian, arg);
...
@@ -35,12 +36,11 @@ pthread_handler_decl(guardian, arg);
C_MODE_END
C_MODE_END
struct
Guardian_thread_args
struct
Guardian_thread_args
{
{
Thread_registry
&
thread_registry
;
Thread_registry
&
thread_registry
;
Instance_map
*
instance_map
;
Instance_map
*
instance_map
;
u
int
monitoring_interval
;
int
monitoring_interval
;
Guardian_thread_args
(
Thread_registry
&
thread_registry_arg
,
Guardian_thread_args
(
Thread_registry
&
thread_registry_arg
,
Instance_map
*
instance_map_arg
,
Instance_map
*
instance_map_arg
,
...
@@ -64,23 +64,41 @@ public:
...
@@ -64,23 +64,41 @@ public:
Instance_map
*
instance_map_arg
,
Instance_map
*
instance_map_arg
,
uint
monitoring_interval_arg
);
uint
monitoring_interval_arg
);
~
Guardian_thread
();
~
Guardian_thread
();
/* Main funtion of the thread */
void
run
();
void
run
();
/* Initialize list of guarded instances */
int
init
();
int
init
();
int
start
();
/* Request guardian shutdown. Stop instances if needed */
void
request_shutdown
(
bool
stop_instances
);
/* Start instance protection */
int
guard
(
Instance
*
instance
);
int
guard
(
Instance
*
instance
);
/* Stop instance protection */
int
stop_guard
(
Instance
*
instance
);
int
stop_guard
(
Instance
*
instance
);
/* Returns true if guardian thread is stopped */
int
is_stopped
();
public:
pthread_cond_t
COND_guardian
;
private:
private:
int
add_instance_to_list
(
Instance
*
instance
,
LIST
**
list
);
/* Prepares Guardian shutdown. Stops instances is needed */
void
move_to_list
(
LIST
**
from
,
LIST
**
to
);
int
stop_instances
(
bool
stop_instances_arg
);
/* check instance state and act accordingly */
void
process_instance
(
Instance
*
instance
,
GUARD_NODE
*
current_node
,
LIST
**
guarded_instances
,
LIST
*
elem
);
int
stopped
;
private:
private:
/* states of an instance */
enum
{
NOT_STARTED
=
1
,
STARTING
,
STARTED
,
JUST_CRASHED
,
CRASHED
,
CRASHED_AND_ABANDONED
,
STOPPING
};
pthread_mutex_t
LOCK_guardian
;
pthread_mutex_t
LOCK_guardian
;
Thread_info
thread_info
;
Thread_info
thread_info
;
LIST
*
guarded_instances
;
LIST
*
guarded_instances
;
LIST
*
starting_instances
;
MEM_ROOT
alloc
;
MEM_ROOT
alloc
;
enum
{
MEM_ROOT_BLOCK_SIZE
=
512
};
enum
{
MEM_ROOT_BLOCK_SIZE
=
512
};
/* this variable is set to TRUE when we want to stop Guardian thread */
bool
shutdown_requested
;
};
};
#endif
/* INCLUDES_MYSQL_INSTANCE_MANAGER_GUARDIAN_H */
#endif
/* INCLUDES_MYSQL_INSTANCE_MANAGER_GUARDIAN_H */
server-tools/instance-manager/instance.cc
View file @
451de5db
...
@@ -21,11 +21,25 @@
...
@@ -21,11 +21,25 @@
#include "instance.h"
#include "instance.h"
#include "mysql_manager_error.h"
#include "mysql_manager_error.h"
#include "log.h"
#include "log.h"
#include "instance_map.h"
#include <my_sys.h>
#include <my_sys.h>
#include <signal.h>
#include <signal.h>
#include <m_string.h>
#include <m_string.h>
#include <sys/wait.h>
#include <sys/wait.h>
C_MODE_START
pthread_handler_decl
(
proxy
,
arg
)
{
Instance
*
instance
=
(
Instance
*
)
arg
;
instance
->
fork_and_monitor
();
return
0
;
}
C_MODE_END
/*
/*
The method starts an instance.
The method starts an instance.
...
@@ -43,53 +57,115 @@ int Instance::start()
...
@@ -43,53 +57,115 @@ int Instance::start()
{
{
pid_t
pid
;
pid_t
pid
;
/* clear crash flag */
pthread_mutex_lock
(
&
LOCK_instance
);
crashed
=
0
;
pthread_mutex_unlock
(
&
LOCK_instance
);
if
(
!
is_running
())
if
(
!
is_running
())
{
{
log_info
(
"trying to start instance %s"
,
options
.
instance_name
);
if
((
pid
=
options
.
get_pid
())
!=
0
)
/* check the pidfile */
switch
(
pid
=
fork
())
{
if
(
options
.
unlink_pidfile
())
/* remove stalled pidfile */
case
0
:
log_error
(
"cannot remove pidfile for instance %i, this might be \
if
(
fork
())
/* zombie protection */
since IM lacks permmissions or hasn't found the pidifle"
,
exit
(
0
);
/* parent goes bye-bye */
options
.
instance_name
);
else
{
/*
execv
(
options
.
mysqld_path
,
options
.
argv
);
No need to monitor this thread in the Thread_registry, as all
exit
(
1
);
instances are to be stopped during shutdown.
}
*/
case
-
1
:
pthread_t
proxy_thd_id
;
pthread_attr_t
proxy_thd_attr
;
int
rc
;
pthread_attr_init
(
&
proxy_thd_attr
);
pthread_attr_setdetachstate
(
&
proxy_thd_attr
,
PTHREAD_CREATE_DETACHED
);
rc
=
pthread_create
(
&
proxy_thd_id
,
&
proxy_thd_attr
,
proxy
,
this
);
pthread_attr_destroy
(
&
proxy_thd_attr
);
if
(
rc
)
{
log_error
(
"Instance::start(): pthread_create(proxy) failed"
);
return
ER_CANNOT_START_INSTANCE
;
return
ER_CANNOT_START_INSTANCE
;
default:
waitpid
(
pid
,
NULL
,
0
);
return
0
;
}
}
return
0
;
}
}
/* the instance is started already */
/* the instance is started already */
return
ER_INSTANCE_ALREADY_STARTED
;
return
ER_INSTANCE_ALREADY_STARTED
;
}
}
int
Instance
::
cleanup
()
void
Instance
::
fork_and_monitor
()
{
{
/*
pid_t
pid
;
We cannot close connection in destructor, as mysql_close needs alarm
log_info
(
"starting instance %s"
,
options
.
instance_name
);
services which are definitely unavailaible at the time of destructor
switch
(
pid
=
fork
())
{
call.
case
0
:
*/
execv
(
options
.
mysqld_path
,
options
.
argv
);
if
(
is_connected
)
/* exec never returns */
mysql_close
(
&
mysql
);
exit
(
1
);
return
0
;
case
-
1
:
log_info
(
"cannot fork() to start instance %s"
,
options
.
instance_name
);
return
;
default:
wait
(
NULL
);
/* set instance state to crashed */
pthread_mutex_lock
(
&
LOCK_instance
);
crashed
=
1
;
pthread_mutex_unlock
(
&
LOCK_instance
);
/*
Wake connection threads waiting for an instance to stop. This
is needed if a user issued command to stop an instance via
mysql connection. This is not the case if Guardian stop the thread.
*/
pthread_cond_signal
(
&
COND_instance_restarted
);
/* wake guardian */
pthread_cond_signal
(
&
instance_map
->
guardian
->
COND_guardian
);
/* thread exits */
return
;
}
/* we should never end up here */
DBUG_ASSERT
(
0
);
}
Instance
::
Instance
()
:
crashed
(
0
)
{
pthread_mutex_init
(
&
LOCK_instance
,
0
);
pthread_cond_init
(
&
COND_instance_restarted
,
0
);
}
}
Instance
::~
Instance
()
Instance
::~
Instance
()
{
{
pthread_mutex_destroy
(
&
LOCK_instance
);
pthread_mutex_destroy
(
&
LOCK_instance
);
pthread_cond_destroy
(
&
COND_instance_restarted
);
}
int
Instance
::
is_crashed
()
{
int
val
;
pthread_mutex_lock
(
&
LOCK_instance
);
val
=
crashed
;
pthread_mutex_unlock
(
&
LOCK_instance
);
return
val
;
}
}
bool
Instance
::
is_running
()
bool
Instance
::
is_running
()
{
{
MYSQL
mysql
;
uint
port
=
0
;
uint
port
=
0
;
const
char
*
socket
=
NULL
;
const
char
*
socket
=
NULL
;
const
char
*
password
=
"321rarepassword213"
;
const
char
*
username
=
"645rareusername945"
;
const
char
*
access_denied_message
=
"Access denied for user"
;
bool
return_val
;
if
(
options
.
mysqld_port
)
if
(
options
.
mysqld_port
)
port
=
atoi
(
strchr
(
options
.
mysqld_port
,
'='
)
+
1
);
port
=
atoi
(
strchr
(
options
.
mysqld_port
,
'='
)
+
1
);
...
@@ -98,30 +174,39 @@ bool Instance::is_running()
...
@@ -98,30 +174,39 @@ bool Instance::is_running()
socket
=
strchr
(
options
.
mysqld_socket
,
'='
)
+
1
;
socket
=
strchr
(
options
.
mysqld_socket
,
'='
)
+
1
;
pthread_mutex_lock
(
&
LOCK_instance
);
pthread_mutex_lock
(
&
LOCK_instance
);
if
(
!
is_connected
)
mysql_init
(
&
mysql
);
/* try to connect to a server with a fake username/password pair */
if
(
mysql_real_connect
(
&
mysql
,
LOCAL_HOST
,
username
,
password
,
NullS
,
port
,
socket
,
0
))
{
{
mysql_init
(
&
mysql
);
/*
if
(
mysql_real_connect
(
&
mysql
,
LOCAL_HOST
,
options
.
mysqld_user
,
We have successfully connected to the server using fake
options
.
mysqld_password
,
username/password. Write a warning to the logfile.
NullS
,
port
,
*/
socket
,
0
))
log_info
(
"The Instance Manager was able to log into you server \
{
with faked compiled-in password while checking server status. \
mysql
.
reconnect
=
1
;
Looks like something is wrong."
);
is_connected
=
TRUE
;
pthread_mutex_unlock
(
&
LOCK_instance
);
return
TRUE
;
}
mysql_close
(
&
mysql
);
pthread_mutex_unlock
(
&
LOCK_instance
);
pthread_mutex_unlock
(
&
LOCK_instance
);
return
FALSE
;
return
_val
=
TRUE
;
/* server is alive */
}
}
else
if
(
!
mysql_ping
(
&
mysql
))
else
{
{
pthread_mutex_unlock
(
&
LOCK_instance
);
if
(
!
strncmp
(
access_denied_message
,
mysql_error
(
&
mysql
),
return
TRUE
;
sizeof
(
access_denied_message
)
-
1
))
{
return_val
=
TRUE
;
}
else
return_val
=
FALSE
;
}
}
mysql_close
(
&
mysql
);
pthread_mutex_unlock
(
&
LOCK_instance
);
pthread_mutex_unlock
(
&
LOCK_instance
);
return
FALSE
;
return
return_val
;
}
}
...
@@ -139,22 +224,67 @@ bool Instance::is_running()
...
@@ -139,22 +224,67 @@ bool Instance::is_running()
int
Instance
::
stop
()
int
Instance
::
stop
()
{
{
if
(
is_running
())
pid_t
pid
;
struct
timespec
timeout
;
int
waitchild
=
DEFAULT_SHUTDOWN_DELAY
;
if
(
options
.
shutdown_delay
!=
NULL
)
waitchild
=
atoi
(
options
.
shutdown_delay
);
kill_instance
(
SIGTERM
);
/* sleep on condition to wait for SIGCHLD */
timeout
.
tv_sec
=
time
(
NULL
)
+
waitchild
;
timeout
.
tv_nsec
=
0
;
if
(
pthread_mutex_lock
(
&
LOCK_instance
))
goto
err
;
while
(
options
.
get_pid
()
!=
0
)
/* while server isn't stopped */
{
{
if
(
mysql_shutdown
(
&
mysql
,
SHUTDOWN_DEFAULT
))
int
status
;
goto
err
;
mysql_close
(
&
mysql
);
status
=
pthread_cond_timedwait
(
&
COND_instance_restarted
,
is_connected
=
FALSE
;
&
LOCK_instance
,
return
0
;
&
timeout
);
if
(
status
==
ETIMEDOUT
)
break
;
}
}
pthread_mutex_unlock
(
&
LOCK_instance
);
kill_instance
(
SIGKILL
);
return
0
;
return
ER_INSTANCE_IS_NOT_STARTED
;
return
ER_INSTANCE_IS_NOT_STARTED
;
err:
err:
return
ER_STOP_INSTANCE
;
return
ER_STOP_INSTANCE
;
}
}
void
Instance
::
kill_instance
(
int
signum
)
{
pid_t
pid
;
/* if there are no pid, everything seems to be fine */
if
((
pid
=
options
.
get_pid
())
!=
0
)
/* get pid from pidfile */
{
/*
If we cannot kill mysqld, then it has propably crashed.
Let us try to remove staled pidfile and return successfully
as mysqld is probably stopped.
*/
if
(
!
kill
(
pid
,
signum
))
options
.
unlink_pidfile
();
else
if
(
signum
==
SIGKILL
)
/* really killed instance with SIGKILL */
log_error
(
"The instance %s is being stopped forsibly. Normally \
it should not happed. Probably the instance has been \
hanging. You should also check your IM setup"
,
options
.
instance_name
);
}
return
;
}
/*
/*
We execute this function to initialize instance parameters.
We execute this function to initialize instance parameters.
Return value: 0 - ok. 1 - unable to init DYNAMIC_ARRAY.
Return value: 0 - ok. 1 - unable to init DYNAMIC_ARRAY.
...
@@ -162,7 +292,14 @@ err:
...
@@ -162,7 +292,14 @@ err:
int
Instance
::
init
(
const
char
*
name_arg
)
int
Instance
::
init
(
const
char
*
name_arg
)
{
{
pthread_mutex_init
(
&
LOCK_instance
,
0
);
return
options
.
init
(
name_arg
);
return
options
.
init
(
name_arg
);
}
}
int
Instance
::
complete_initialization
(
Instance_map
*
instance_map_arg
,
const
char
*
mysqld_path
,
int
only_instance
)
{
instance_map
=
instance_map_arg
;
return
options
.
complete_initialization
(
mysqld_path
,
only_instance
);
}
server-tools/instance-manager/instance.h
View file @
451de5db
...
@@ -25,36 +25,40 @@
...
@@ -25,36 +25,40 @@
#pragma interface
#pragma interface
#endif
#endif
class
Instance_map
;
class
Instance
class
Instance
{
{
public:
public:
Instance
()
:
is_connected
(
FALSE
)
Instance
();
{}
~
Instance
();
~
Instance
();
int
init
(
const
char
*
name
);
int
init
(
const
char
*
name
);
int
complete_initialization
(
Instance_map
*
instance_map_arg
,
const
char
*
mysqld_path
,
int
only_instance
=
0
);
/* check if the instance is running and set up mysql connection if yes */
bool
is_running
();
bool
is_running
();
int
start
();
int
start
();
int
stop
();
int
stop
();
int
cleanup
();
/* send a signal to the instance */
void
kill_instance
(
int
signo
);
int
is_crashed
();
void
fork_and_monitor
();
public:
public:
enum
{
DEFAULT_SHUTDOWN_DELAY
=
35
};
Instance_options
options
;
Instance_options
options
;
/* connection to the instance */
MYSQL
mysql
;
private:
private:
/*
/*
Mutex protecting the instance. Currently we use it to avoid the
Mutex protecting the instance. Currently we use it to avoid the
double start of the instance. This happens when the instance is starting
double start of the instance. This happens when the instance is starting
and we issue the start command once more.
and we issue the start command once more.
*/
*/
int
crashed
;
pthread_mutex_t
LOCK_instance
;
pthread_mutex_t
LOCK_instance
;
/* Here we store the state of the following connection */
pthread_cond_t
COND_instance_restarted
;
bool
is_connected
;
Instance_map
*
instance_map
;
};
};
#endif
/* INCLUDES_MYSQL_INSTANCE_MANAGER_INSTANCE_H */
#endif
/* INCLUDES_MYSQL_INSTANCE_MANAGER_INSTANCE_H */
server-tools/instance-manager/instance_map.cc
View file @
451de5db
...
@@ -74,7 +74,7 @@ static void delete_instance(void *u)
...
@@ -74,7 +74,7 @@ static void delete_instance(void *u)
1 - error occured
1 - error occured
*/
*/
static
int
process_option
(
void
*
ctx
,
const
char
*
group
,
const
char
*
option
)
static
int
process_option
(
void
*
ctx
,
const
char
*
group
,
const
char
*
option
)
{
{
Instance_map
*
map
=
NULL
;
Instance_map
*
map
=
NULL
;
Instance
*
instance
=
NULL
;
Instance
*
instance
=
NULL
;
...
@@ -82,7 +82,8 @@ static int process_option(void * ctx, const char *group, const char *option)
...
@@ -82,7 +82,8 @@ static int process_option(void * ctx, const char *group, const char *option)
map
=
(
Instance_map
*
)
ctx
;
map
=
(
Instance_map
*
)
ctx
;
if
(
strncmp
(
group
,
prefix
,
sizeof
prefix
)
==
0
&&
if
(
strncmp
(
group
,
prefix
,
sizeof
prefix
)
==
0
&&
(
my_isdigit
(
default_charset_info
,
group
[
sizeof
prefix
])))
((
my_isdigit
(
default_charset_info
,
group
[
sizeof
prefix
]))
||
group
[
sizeof
(
prefix
)]
==
'\0'
))
{
{
if
((
instance
=
map
->
find
(
group
,
strlen
(
group
)))
==
NULL
)
if
((
instance
=
map
->
find
(
group
,
strlen
(
group
)))
==
NULL
)
{
{
...
@@ -110,13 +111,9 @@ C_MODE_END
...
@@ -110,13 +111,9 @@ C_MODE_END
Instance_map
::
Instance_map
(
const
char
*
default_mysqld_path_arg
,
Instance_map
::
Instance_map
(
const
char
*
default_mysqld_path_arg
,
const
char
*
default_admin_user_arg
,
const
char
*
first_option_arg
)
:
const
char
*
default_admin_password
_arg
)
mysqld_path
(
default_mysqld_path_arg
),
first_option
(
first_option
_arg
)
{
{
mysqld_path
=
default_mysqld_path_arg
;
user
=
default_admin_user_arg
;
password
=
default_admin_password_arg
;
pthread_mutex_init
(
&
LOCK_instance_map
,
0
);
pthread_mutex_init
(
&
LOCK_instance_map
,
0
);
}
}
...
@@ -181,48 +178,42 @@ Instance_map::find(const char *name, uint name_len)
...
@@ -181,48 +178,42 @@ Instance_map::find(const char *name, uint name_len)
}
}
void
Instance_map
::
complete_initialization
()
int
Instance_map
::
complete_initialization
()
{
{
Instance
*
instance
;
Instance
*
instance
;
uint
i
=
0
;
uint
i
=
0
;
while
(
i
<
hash
.
records
)
if
(
hash
.
records
==
0
)
/* no instances found */
{
{
instance
=
(
Instance
*
)
hash_element
(
&
hash
,
i
);
if
((
instance
=
new
Instance
)
==
0
)
instance
->
options
.
complete_initialization
(
mysqld_path
,
user
,
password
);
goto
err
;
i
++
;
if
(
instance
->
init
(
"mysqld"
)
||
add_instance
(
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
,
1
))
goto
err
;
}
}
}
else
while
(
i
<
hash
.
records
)
{
int
Instance_map
::
cleanup
()
instance
=
(
Instance
*
)
hash_element
(
&
hash
,
i
);
{
if
(
instance
->
complete_initialization
(
this
,
mysqld_path
))
Instance
*
instance
;
goto
err
;
uint
i
=
0
;
i
++
;
}
while
(
i
<
hash
.
records
)
{
instance
=
(
Instance
*
)
hash_element
(
&
hash
,
i
);
if
(
instance
->
cleanup
())
return
1
;
i
++
;
}
return
0
;
}
Instance
*
Instance_map
::
find
(
uint
instance_number
)
{
Instance
*
instance
;
char
name
[
80
];
sprintf
(
name
,
"mysqld%i"
,
instance_number
);
return
0
;
pthread_mutex_lock
(
&
LOCK_instance_map
);
err:
instance
=
(
Instance
*
)
hash_search
(
&
hash
,
(
byte
*
)
name
,
strlen
(
name
));
return
1
;
pthread_mutex_unlock
(
&
LOCK_instance_map
);
err_instance:
return
instance
;
delete
instance
;
return
1
;
}
}
...
@@ -230,13 +221,29 @@ Instance_map::find(uint instance_number)
...
@@ -230,13 +221,29 @@ Instance_map::find(uint instance_number)
int
Instance_map
::
load
()
int
Instance_map
::
load
()
{
{
int
error
;
int
argc
=
1
;
/* this is a dummy variable for search_option_files() */
error
=
process_default_option_files
(
"my"
,
process_option
,
(
void
*
)
this
);
uint
args_used
=
0
;
const
char
*
argv_options
[
3
];
char
**
argv
=
(
char
**
)
&
argv_options
;
/* the name of the program may be orbitrary here in fact */
argv_options
[
0
]
=
"mysqlmanager"
;
if
(
first_option
!=
NULL
)
{
argc
=
2
;
argv_options
[
1
]
=
first_option
;
argv_options
[
2
]
=
'\0'
;
}
else
argv_options
[
1
]
=
'\0'
;
complete_initialization
();
if
(
my_search_option_files
(
"my"
,
&
argc
,
(
char
***
)
&
argv
,
&
args_used
,
process_option
,
(
void
*
)
this
)
||
complete_initialization
())
return
1
;
return
error
;
return
0
;
}
}
...
...
server-tools/instance-manager/instance_map.h
View file @
451de5db
...
@@ -60,14 +60,12 @@ public:
...
@@ -60,14 +60,12 @@ public:
Instance
*
find
(
uint
instance_number
);
Instance
*
find
(
uint
instance_number
);
int
flush_instances
();
int
flush_instances
();
int
cleanup
();
int
lock
();
int
lock
();
int
unlock
();
int
unlock
();
int
init
();
int
init
();
Instance_map
(
const
char
*
default_mysqld_path_arg
,
Instance_map
(
const
char
*
default_mysqld_path_arg
,
const
char
*
default_admin_user_arg
,
const
char
*
first_option_arg
);
const
char
*
default_admin_password_arg
);
~
Instance_map
();
~
Instance_map
();
/* loads options from config files */
/* loads options from config files */
...
@@ -75,16 +73,14 @@ public:
...
@@ -75,16 +73,14 @@ public:
/* adds instance to internal hash */
/* adds instance to internal hash */
int
add_instance
(
Instance
*
instance
);
int
add_instance
(
Instance
*
instance
);
/* inits instances argv's after all options have been loaded */
/* inits instances argv's after all options have been loaded */
void
complete_initialization
();
int
complete_initialization
();
public:
public:
const
char
*
mysqld_path
;
const
char
*
mysqld_path
;
/* user an password to shutdown MySQL */
const
char
*
user
;
const
char
*
password
;
Guardian_thread
*
guardian
;
Guardian_thread
*
guardian
;
private:
private:
const
char
*
first_option
;
enum
{
START_HASH_SIZE
=
16
};
enum
{
START_HASH_SIZE
=
16
};
pthread_mutex_t
LOCK_instance_map
;
pthread_mutex_t
LOCK_instance_map
;
HASH
hash
;
HASH
hash
;
...
...
server-tools/instance-manager/instance_options.cc
View file @
451de5db
...
@@ -19,43 +19,164 @@
...
@@ -19,43 +19,164 @@
#endif
#endif
#include "instance_options.h"
#include "instance_options.h"
#include "parse_output.h"
#include "buffer.h"
#include <my_sys.h>
#include <my_sys.h>
#include <mysql.h>
#include <mysql.h>
#include <signal.h>
#include <signal.h>
#include <m_string.h>
#include <m_string.h>
int
Instance_options
::
complete_initialization
(
const
char
*
default_path
,
const
char
*
default_user
,
/*
const
char
*
default_password
)
Get compiled-in value of default_option
SYNOPSYS
get_default_option()
result buffer to put found value
result_len buffer size
oprion_name the name of the option, prefixed with "--"
DESCRIPTION
Get compile-in value of requested option from server
RETURN
0 - ok
1 - error occured
*/
int
Instance_options
::
get_default_option
(
char
*
result
,
size_t
result_len
,
const
char
*
option_name
)
{
{
/* we need to reserve space for the final zero + possible default options */
int
position
=
0
;
if
(
!
(
argv
=
(
char
**
)
alloc_root
(
&
alloc
,
(
options_array
.
elements
+
1
int
rc
=
1
;
+
MAX_NUMBER_OF_DEFAULT_OPTIONS
)
*
sizeof
(
char
*
))))
char
verbose_option
[]
=
" --no-defaults --verbose --help"
;
goto
err
;
Buffer
cmd
(
strlen
(
mysqld_path
)
+
sizeof
(
verbose_option
)
+
1
);
if
(
cmd
.
get_size
())
/* malloc succeeded */
{
cmd
.
append
(
position
,
mysqld_path
,
strlen
(
mysqld_path
));
position
+=
strlen
(
mysqld_path
);
cmd
.
append
(
position
,
verbose_option
,
sizeof
(
verbose_option
)
-
1
);
position
+=
sizeof
(
verbose_option
)
-
1
;
cmd
.
append
(
position
,
"
\0
"
,
1
);
if
(
cmd
.
is_error
())
goto
err
;
/* get the value from "mysqld --help --verbose" */
rc
=
parse_output_and_get_value
(
cmd
.
buffer
,
option_name
+
2
,
result
,
result_len
);
}
return
rc
;
err:
return
1
;
}
int
Instance_options
::
get_pid_filename
(
char
*
result
)
{
const
char
*
pid_file
=
mysqld_pid_file
;
char
datadir
[
MAX_PATH_LEN
];
if
(
mysqld_datadir
==
NULL
)
{
/* we might get an error here if we have wrong path to the mysqld binary */
if
(
get_default_option
(
datadir
,
sizeof
(
datadir
),
"--datadir"
))
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
;
/* get the full path to the pidfile */
my_load_path
(
result
,
pid_file
,
datadir
);
return
0
;
}
int
Instance_options
::
unlink_pidfile
()
{
return
unlink
(
pid_file_with_path
);
}
pid_t
Instance_options
::
get_pid
()
{
FILE
*
pid_file_stream
;
/* get the pid */
if
((
pid_file_stream
=
my_fopen
(
pid_file_with_path
,
O_RDONLY
|
O_BINARY
,
MYF
(
0
)))
!=
NULL
)
{
pid_t
pid
;
fscanf
(
pid_file_stream
,
"%i"
,
&
pid
);
my_fclose
(
pid_file_stream
,
MYF
(
0
));
return
pid
;
}
else
return
0
;
}
int
Instance_options
::
complete_initialization
(
const
char
*
default_path
,
int
only_instance
)
{
const
char
*
tmp
;
if
(
mysqld_path
==
NULL
)
if
(
mysqld_path
==
NULL
)
{
{
if
(
!
(
mysqld_path
=
strdup_root
(
&
alloc
,
default_path
)))
if
(
!
(
mysqld_path
=
strdup_root
(
&
alloc
,
default_path
)))
goto
err
;
goto
err
;
}
}
/* this option must be first in the argv */
if
(
!
(
tmp
=
strdup_root
(
&
alloc
,
"--no-defaults"
)))
if
(
add_to_argv
(
mysqld_path
))
goto
err
;
goto
err
;
/* the following options are not for argv */
if
(
mysqld_pid_file
==
NULL
)
if
(
mysqld_user
==
NULL
)
{
{
if
(
!
(
mysqld_user
=
strdup_root
(
&
alloc
,
default_user
)))
char
pidfilename
[
MAX_PATH_LEN
];
goto
err
;
char
hostname
[
MAX_PATH_LEN
];
/*
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
))
(
only_instance
==
0
)
?
strxnmov
(
pidfilename
,
MAX_PATH_LEN
-
1
,
"--pid-file="
,
instance_name
,
"-"
,
hostname
,
".pid"
,
NullS
)
:
strxnmov
(
pidfilename
,
MAX_PATH_LEN
-
1
,
"--pid-file="
,
hostname
,
".pid"
,
NullS
);
else
(
only_instance
==
0
)
?
strxnmov
(
pidfilename
,
MAX_PATH_LEN
-
1
,
"--pid-file="
,
instance_name
,
".pid"
,
NullS
)
:
strxnmov
(
pidfilename
,
MAX_PATH_LEN
-
1
,
"--pid-file="
,
"mysql"
,
".pid"
,
NullS
);
add_option
(
pidfilename
);
}
}
if
(
mysqld_password
==
NULL
)
if
(
get_pid_filename
(
pid_file_with_path
))
{
goto
err
;
if
(
!
(
mysqld_password
=
strdup_root
(
&
alloc
,
default_password
)))
goto
err
;
/* we need to reserve space for the final zero + possible default options */
}
if
(
!
(
argv
=
(
char
**
)
alloc_root
(
&
alloc
,
(
options_array
.
elements
+
1
+
MAX_NUMBER_OF_DEFAULT_OPTIONS
)
*
sizeof
(
char
*
))))
goto
err
;
/* the path must be first in the argv */
if
(
add_to_argv
(
mysqld_path
))
goto
err
;
if
(
add_to_argv
(
tmp
))
goto
err
;
memcpy
((
gptr
)
(
argv
+
filled_default_options
),
options_array
.
buffer
,
memcpy
((
gptr
)
(
argv
+
filled_default_options
),
options_array
.
buffer
,
options_array
.
elements
*
sizeof
(
char
*
));
options_array
.
elements
*
sizeof
(
char
*
));
...
@@ -102,9 +223,8 @@ int Instance_options::add_option(const char* option)
...
@@ -102,9 +223,8 @@ int Instance_options::add_option(const char* option)
{
"--bind-address="
,
15
,
&
mysqld_bind_address
,
SAVE_WHOLE_AND_ADD
},
{
"--bind-address="
,
15
,
&
mysqld_bind_address
,
SAVE_WHOLE_AND_ADD
},
{
"--pid-file="
,
11
,
&
mysqld_pid_file
,
SAVE_WHOLE_AND_ADD
},
{
"--pid-file="
,
11
,
&
mysqld_pid_file
,
SAVE_WHOLE_AND_ADD
},
{
"--mysqld-path="
,
14
,
&
mysqld_path
,
SAVE_VALUE
},
{
"--mysqld-path="
,
14
,
&
mysqld_path
,
SAVE_VALUE
},
{
"--admin-user="
,
13
,
&
mysqld_user
,
SAVE_VALUE
},
{
"--nonguarded"
,
9
,
&
nonguarded
,
SAVE_WHOLE
},
{
"--admin-password="
,
17
,
&
mysqld_password
,
SAVE_VALUE
},
{
"--shutdown_delay"
,
9
,
&
shutdown_delay
,
SAVE_VALUE
},
{
"--guarded"
,
9
,
&
is_guarded
,
SAVE_WHOLE
},
{
NULL
,
0
,
NULL
,
0
}
{
NULL
,
0
,
NULL
,
0
}
};
};
struct
selected_options_st
*
selected_options
;
struct
selected_options_st
*
selected_options
;
...
@@ -131,6 +251,9 @@ int Instance_options::add_option(const char* option)
...
@@ -131,6 +251,9 @@ int Instance_options::add_option(const char* option)
}
}
}
}
/* if we haven't returned earlier we should just save the option */
insert_dynamic
(
&
options_array
,(
gptr
)
&
tmp
);
return
0
;
return
0
;
err:
err:
...
@@ -148,6 +271,18 @@ int Instance_options::add_to_argv(const char* option)
...
@@ -148,6 +271,18 @@ int Instance_options::add_to_argv(const char* option)
}
}
/* function for debug purposes */
void
Instance_options
::
print_argv
()
{
int
i
;
printf
(
"printing out an instance %s argv:
\n
"
,
instance_name
);
for
(
i
=
0
;
argv
[
i
]
!=
NULL
;
i
++
)
{
printf
(
"argv: %s
\n
"
,
argv
[
i
]);
}
}
/*
/*
We execute this function to initialize some options.
We execute this function to initialize some options.
Return value: 0 - ok. 1 - unable to allocate memory.
Return value: 0 - ok. 1 - unable to allocate memory.
...
...
server-tools/instance-manager/instance_options.h
View file @
451de5db
...
@@ -38,21 +38,29 @@ class Instance_options
...
@@ -38,21 +38,29 @@ class Instance_options
public:
public:
Instance_options
()
:
Instance_options
()
:
mysqld_socket
(
0
),
mysqld_datadir
(
0
),
mysqld_bind_address
(
0
),
mysqld_socket
(
0
),
mysqld_datadir
(
0
),
mysqld_bind_address
(
0
),
mysqld_pid_file
(
0
),
mysqld_port
(
0
),
mysqld_path
(
0
),
mysqld_user
(
0
),
mysqld_pid_file
(
0
),
mysqld_port
(
0
),
mysqld_path
(
0
),
nonguarded
(
0
),
mysqld_password
(
0
),
is_guarded
(
0
),
filled_default_options
(
0
)
shutdown_delay
(
0
),
filled_default_options
(
0
)
{}
{}
~
Instance_options
();
~
Instance_options
();
/* fills in argv */
/* fills in argv */
int
complete_initialization
(
const
char
*
default_path
,
int
complete_initialization
(
const
char
*
default_path
,
int
only_instance
);
const
char
*
default_user
,
const
char
*
default_password
);
int
add_option
(
const
char
*
option
);
int
add_option
(
const
char
*
option
);
int
init
(
const
char
*
instance_name_arg
);
int
init
(
const
char
*
instance_name_arg
);
pid_t
get_pid
();
int
get_pid_filename
(
char
*
result
);
int
unlink_pidfile
();
void
print_argv
();
public:
public:
enum
{
MAX_NUMBER_OF_DEFAULT_OPTIONS
=
1
};
/*
We need this value to be greater or equal then FN_REFLEN found in
my_global.h to use my_load_path()
*/
enum
{
MAX_PATH_LEN
=
512
};
enum
{
MAX_NUMBER_OF_DEFAULT_OPTIONS
=
2
};
enum
{
MEM_ROOT_BLOCK_SIZE
=
512
};
enum
{
MEM_ROOT_BLOCK_SIZE
=
512
};
char
pid_file_with_path
[
MAX_PATH_LEN
];
char
**
argv
;
char
**
argv
;
/* We need the some options, so we store them as a separate pointers */
/* We need the some options, so we store them as a separate pointers */
const
char
*
mysqld_socket
;
const
char
*
mysqld_socket
;
...
@@ -63,12 +71,14 @@ public:
...
@@ -63,12 +71,14 @@ public:
uint
instance_name_len
;
uint
instance_name_len
;
const
char
*
instance_name
;
const
char
*
instance_name
;
const
char
*
mysqld_path
;
const
char
*
mysqld_path
;
const
char
*
mysqld_user
;
const
char
*
nonguarded
;
const
char
*
mysqld_password
;
const
char
*
shutdown_delay
;
const
char
*
is_guarded
;
/* this value is computed and cashed here */
DYNAMIC_ARRAY
options_array
;
DYNAMIC_ARRAY
options_array
;
private:
private:
int
add_to_argv
(
const
char
*
option
);
int
add_to_argv
(
const
char
*
option
);
int
get_default_option
(
char
*
result
,
size_t
result_len
,
const
char
*
option_name
);
private:
private:
uint
filled_default_options
;
uint
filled_default_options
;
MEM_ROOT
alloc
;
MEM_ROOT
alloc
;
...
...
server-tools/instance-manager/listener.cc
View file @
451de5db
...
@@ -57,13 +57,11 @@ Listener_thread::Listener_thread(const Listener_thread_args &args) :
...
@@ -57,13 +57,11 @@ Listener_thread::Listener_thread(const Listener_thread_args &args) :
,
total_connection_count
(
0
)
,
total_connection_count
(
0
)
,
thread_info
(
pthread_self
())
,
thread_info
(
pthread_self
())
{
{
thread_registry
.
register_thread
(
&
thread_info
);
}
}
Listener_thread
::~
Listener_thread
()
Listener_thread
::~
Listener_thread
()
{
{
thread_registry
.
unregister_thread
(
&
thread_info
);
}
}
...
@@ -82,6 +80,13 @@ void Listener_thread::run()
...
@@ -82,6 +80,13 @@ void Listener_thread::run()
enum
{
LISTEN_BACK_LOG_SIZE
=
5
};
// standard backlog size
enum
{
LISTEN_BACK_LOG_SIZE
=
5
};
// standard backlog size
int
flags
;
int
flags
;
int
arg
=
1
;
/* value to be set by setsockopt */
int
arg
=
1
;
/* value to be set by setsockopt */
int
unix_socket
;
uint
im_port
;
thread_registry
.
register_thread
(
&
thread_info
);
my_thread_init
();
/* I. prepare 'listen' sockets */
/* I. prepare 'listen' sockets */
int
ip_socket
=
socket
(
AF_INET
,
SOCK_STREAM
,
0
);
int
ip_socket
=
socket
(
AF_INET
,
SOCK_STREAM
,
0
);
...
@@ -89,8 +94,7 @@ void Listener_thread::run()
...
@@ -89,8 +94,7 @@ void Listener_thread::run()
{
{
log_error
(
"Listener_thead::run(): socket(AF_INET) failed, %s"
,
log_error
(
"Listener_thead::run(): socket(AF_INET) failed, %s"
,
strerror
(
errno
));
strerror
(
errno
));
thread_registry
.
request_shutdown
();
goto
err
;
return
;
}
}
struct
sockaddr_in
ip_socket_address
;
struct
sockaddr_in
ip_socket_address
;
...
@@ -104,7 +108,7 @@ void Listener_thread::run()
...
@@ -104,7 +108,7 @@ void Listener_thread::run()
}
}
else
else
im_bind_addr
=
htonl
(
INADDR_ANY
);
im_bind_addr
=
htonl
(
INADDR_ANY
);
uint
im_port
=
options
.
port_number
;
im_port
=
options
.
port_number
;
ip_socket_address
.
sin_family
=
AF_INET
;
ip_socket_address
.
sin_family
=
AF_INET
;
ip_socket_address
.
sin_addr
.
s_addr
=
im_bind_addr
;
ip_socket_address
.
sin_addr
.
s_addr
=
im_bind_addr
;
...
@@ -119,16 +123,14 @@ void Listener_thread::run()
...
@@ -119,16 +123,14 @@ void Listener_thread::run()
{
{
log_error
(
"Listener_thread::run(): bind(ip socket) failed, '%s'"
,
log_error
(
"Listener_thread::run(): bind(ip socket) failed, '%s'"
,
strerror
(
errno
));
strerror
(
errno
));
thread_registry
.
request_shutdown
();
goto
err
;
return
;
}
}
if
(
listen
(
ip_socket
,
LISTEN_BACK_LOG_SIZE
))
if
(
listen
(
ip_socket
,
LISTEN_BACK_LOG_SIZE
))
{
{
log_error
(
"Listener_thread::run(): listen(ip socket) failed, %s"
,
log_error
(
"Listener_thread::run(): listen(ip socket) failed, %s"
,
strerror
(
errno
));
strerror
(
errno
));
thread_registry
.
request_shutdown
();
goto
err
;
return
;
}
}
/* set the socket nonblocking */
/* set the socket nonblocking */
flags
=
fcntl
(
ip_socket
,
F_GETFL
,
0
);
flags
=
fcntl
(
ip_socket
,
F_GETFL
,
0
);
...
@@ -140,13 +142,12 @@ void Listener_thread::run()
...
@@ -140,13 +142,12 @@ void Listener_thread::run()
log_info
(
"accepting connections on ip socket"
);
log_info
(
"accepting connections on ip socket"
);
/*--------------------------------------------------------------*/
/*--------------------------------------------------------------*/
int
unix_socket
=
socket
(
AF_UNIX
,
SOCK_STREAM
,
0
);
unix_socket
=
socket
(
AF_UNIX
,
SOCK_STREAM
,
0
);
if
(
unix_socket
==
INVALID_SOCKET
)
if
(
unix_socket
==
INVALID_SOCKET
)
{
{
log_error
(
"Listener_thead::run(): socket(AF_UNIX) failed, %s"
,
log_error
(
"Listener_thead::run(): socket(AF_UNIX) failed, %s"
,
strerror
(
errno
));
strerror
(
errno
));
thread_registry
.
request_shutdown
();
goto
err
;
return
;
}
}
struct
sockaddr_un
unix_socket_address
;
struct
sockaddr_un
unix_socket_address
;
...
@@ -169,8 +170,7 @@ void Listener_thread::run()
...
@@ -169,8 +170,7 @@ void Listener_thread::run()
log_error
(
"Listener_thread::run(): bind(unix socket) failed, "
log_error
(
"Listener_thread::run(): bind(unix socket) failed, "
"socket file name is '%s', error '%s'"
,
"socket file name is '%s', error '%s'"
,
unix_socket_address
.
sun_path
,
strerror
(
errno
));
unix_socket_address
.
sun_path
,
strerror
(
errno
));
thread_registry
.
request_shutdown
();
goto
err
;
return
;
}
}
umask
(
old_mask
);
umask
(
old_mask
);
...
@@ -178,8 +178,7 @@ void Listener_thread::run()
...
@@ -178,8 +178,7 @@ void Listener_thread::run()
{
{
log_error
(
"Listener_thread::run(): listen(unix socket) failed, %s"
,
log_error
(
"Listener_thread::run(): listen(unix socket) failed, %s"
,
strerror
(
errno
));
strerror
(
errno
));
thread_registry
.
request_shutdown
();
goto
err
;
return
;
}
}
/* set the socket nonblocking */
/* set the socket nonblocking */
...
@@ -205,7 +204,15 @@ void Listener_thread::run()
...
@@ -205,7 +204,15 @@ void Listener_thread::run()
while
(
thread_registry
.
is_shutdown
()
==
false
)
while
(
thread_registry
.
is_shutdown
()
==
false
)
{
{
fd_set
read_fds_arg
=
read_fds
;
fd_set
read_fds_arg
=
read_fds
;
/*
When using valgrind 2.0 this syscall doesn't get kicked off by a
signal during shutdown. This results in failing assert
(Thread_registry::~Thread_registry). Valgrind 2.2 works fine.
*/
int
rc
=
select
(
n
,
&
read_fds_arg
,
0
,
0
,
0
);
int
rc
=
select
(
n
,
&
read_fds_arg
,
0
,
0
,
0
);
if
(
rc
==
-
1
&&
errno
!=
EINTR
)
if
(
rc
==
-
1
&&
errno
!=
EINTR
)
log_error
(
"Listener_thread::run(): select() failed, %s"
,
log_error
(
"Listener_thread::run(): select() failed, %s"
,
strerror
(
errno
));
strerror
(
errno
));
...
@@ -256,6 +263,16 @@ void Listener_thread::run()
...
@@ -256,6 +263,16 @@ void Listener_thread::run()
close
(
unix_socket
);
close
(
unix_socket
);
close
(
ip_socket
);
close
(
ip_socket
);
unlink
(
unix_socket_address
.
sun_path
);
unlink
(
unix_socket_address
.
sun_path
);
thread_registry
.
unregister_thread
(
&
thread_info
);
my_thread_end
();
return
;
err:
thread_registry
.
unregister_thread
(
&
thread_info
);
thread_registry
.
request_shutdown
();
my_thread_end
();
return
;
}
}
...
...
server-tools/instance-manager/log.cc
View file @
451de5db
...
@@ -32,8 +32,8 @@
...
@@ -32,8 +32,8 @@
SYNOPSYS
SYNOPSYS
log()
log()
*/
*/
static
inline
void
log
(
FILE
*
file
,
const
char
*
format
,
va_list
args
)
static
inline
void
log
(
FILE
*
file
,
const
char
*
format
,
va_list
args
)
{
{
/*
/*
log() should be thread-safe; it implies that we either call fprintf()
log() should be thread-safe; it implies that we either call fprintf()
...
...
server-tools/instance-manager/log.h
View file @
451de5db
...
@@ -17,14 +17,14 @@
...
@@ -17,14 +17,14 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/*
/*
Logging facilities.
Logging facilities.
Two logging streams are supported: error log and info log. Additionally
Two logging streams are supported: error log and info log. Additionally
libdbug may be used for debug information output.
libdbug may be used for debug information output.
ANSI C buffered I/O is used to perform logging.
ANSI C buffered I/O is used to perform logging.
Logging is performed via stdout/stder, so one can reopen them to point to
Logging is performed via stdout/stder, so one can reopen them to point to
ordinary files. To initialize loggin environment log_init() must be called.
ordinary files. To initialize loggin environment log_init() must be called.
Rationale:
Rationale:
- no MYSQL_LOG as it has BIN mode, and not easy to fetch from sql_class.h
- no MYSQL_LOG as it has BIN mode, and not easy to fetch from sql_class.h
- no constructors/desctructors to make logging available all the time
- no constructors/desctructors to make logging available all the time
...
...
server-tools/instance-manager/manager.cc
View file @
451de5db
...
@@ -16,12 +16,6 @@
...
@@ -16,12 +16,6 @@
#include "manager.h"
#include "manager.h"
#include <my_global.h>
#include <my_sys.h>
#include <m_string.h>
#include <signal.h>
#include <thr_alarm.h>
#include "thread_registry.h"
#include "thread_registry.h"
#include "listener.h"
#include "listener.h"
#include "instance_map.h"
#include "instance_map.h"
...
@@ -30,6 +24,14 @@
...
@@ -30,6 +24,14 @@
#include "log.h"
#include "log.h"
#include "guardian.h"
#include "guardian.h"
#include <my_global.h>
#include <my_sys.h>
#include <m_string.h>
#include <signal.h>
#include <thr_alarm.h>
#include <sys/wait.h>
static
int
create_pid_file
(
const
char
*
pid_file_name
)
static
int
create_pid_file
(
const
char
*
pid_file_name
)
{
{
if
(
FILE
*
pid_file
=
my_fopen
(
pid_file_name
,
if
(
FILE
*
pid_file
=
my_fopen
(
pid_file_name
,
...
@@ -65,9 +67,7 @@ void manager(const Options &options)
...
@@ -65,9 +67,7 @@ void manager(const Options &options)
*/
*/
User_map
user_map
;
User_map
user_map
;
Instance_map
instance_map
(
options
.
default_mysqld_path
,
Instance_map
instance_map
(
options
.
default_mysqld_path
,
options
.
first_option
);
options
.
default_admin_user
,
options
.
default_admin_password
);
Guardian_thread
guardian_thread
(
thread_registry
,
Guardian_thread
guardian_thread
(
thread_registry
,
&
instance_map
,
&
instance_map
,
options
.
monitoring_interval
);
options
.
monitoring_interval
);
...
@@ -77,8 +77,18 @@ void manager(const Options &options)
...
@@ -77,8 +77,18 @@ void manager(const Options &options)
instance_map
.
guardian
=
&
guardian_thread
;
instance_map
.
guardian
=
&
guardian_thread
;
if
(
instance_map
.
init
()
||
user_map
.
init
()
||
instance_map
.
load
()
||
if
(
instance_map
.
init
()
||
user_map
.
init
())
user_map
.
load
(
options
.
password_file_name
))
return
;
if
(
instance_map
.
load
())
{
log_error
(
"Cannot init instances repository. This might be caused by "
"the wrong config file options. For instance, missing mysqld "
"binary. Aborting."
);
return
;
}
if
(
user_map
.
load
(
options
.
password_file_name
))
return
;
return
;
/* write pid file */
/* write pid file */
...
@@ -126,6 +136,12 @@ void manager(const Options &options)
...
@@ -126,6 +136,12 @@ void manager(const Options &options)
pthread_attr_t
guardian_thd_attr
;
pthread_attr_t
guardian_thd_attr
;
int
rc
;
int
rc
;
/*
NOTE: Guardian should be shutdown first. Only then all other threads
need to be stopped. This should be done, as guardian is responsible for
shutting down the instances, and this is a long operation.
*/
pthread_attr_init
(
&
guardian_thd_attr
);
pthread_attr_init
(
&
guardian_thd_attr
);
pthread_attr_setdetachstate
(
&
guardian_thd_attr
,
PTHREAD_CREATE_DETACHED
);
pthread_attr_setdetachstate
(
&
guardian_thd_attr
,
PTHREAD_CREATE_DETACHED
);
rc
=
pthread_create
(
&
guardian_thd_id
,
&
guardian_thd_attr
,
guardian
,
rc
=
pthread_create
(
&
guardian_thd_id
,
&
guardian_thd_attr
,
guardian
,
...
@@ -153,26 +169,45 @@ void manager(const Options &options)
...
@@ -153,26 +169,45 @@ void manager(const Options &options)
more then 10 alarms at the same time.
more then 10 alarms at the same time.
*/
*/
init_thr_alarm
(
10
);
init_thr_alarm
(
10
);
/* init list of guarded instances */
guardian_thread
.
init
();
/*
/*
Now we can init the list of guarded instances. We have to do it after
After the list of guarded instances have been initialized,
alarm structures initialization as we have to use net_* functions while
Guardian should start them.
making the list. And they in their turn need alarms for timeout suppport.
*/
*/
guardian_thread
.
start
(
);
pthread_cond_signal
(
&
guardian_thread
.
COND_guardian
);
signal
(
SIGPIPE
,
SIG_IGN
);
signal
(
SIGPIPE
,
SIG_IGN
);
while
(
!
shutdown_complete
)
while
(
!
shutdown_complete
)
{
{
sigwait
(
&
mask
,
&
signo
);
int
status
=
0
;
if
((
status
=
my_sigwait
(
&
mask
,
&
signo
))
!=
0
)
{
log_error
(
"sigwait() failed"
);
goto
err
;
}
switch
(
signo
)
switch
(
signo
)
{
{
case
THR_SERVER_ALARM
:
case
THR_SERVER_ALARM
:
process_alarm
(
signo
);
process_alarm
(
signo
);
break
;
break
;
default:
default:
thread_registry
.
deliver_shutdown
();
{
shutdown_complete
=
TRUE
;
if
(
!
guardian_thread
.
is_stopped
())
{
bool
stop_instances
=
true
;
guardian_thread
.
request_shutdown
(
stop_instances
);
pthread_cond_signal
(
&
guardian_thread
.
COND_guardian
);
}
else
{
thread_registry
.
deliver_shutdown
();
shutdown_complete
=
TRUE
;
}
}
break
;
break
;
}
}
}
}
...
@@ -181,9 +216,6 @@ err:
...
@@ -181,9 +216,6 @@ err:
/* delete the pid file */
/* delete the pid file */
my_delete
(
options
.
pid_file_name
,
MYF
(
0
));
my_delete
(
options
.
pid_file_name
,
MYF
(
0
));
/* close permanent connections to the running instances */
instance_map
.
cleanup
();
/* free alarm structures */
/* free alarm structures */
end_thr_alarm
(
1
);
end_thr_alarm
(
1
);
/* don't pthread_exit to kill all threads who did not shut down in time */
/* don't pthread_exit to kill all threads who did not shut down in time */
...
...
server-tools/instance-manager/messages.cc
View file @
451de5db
...
@@ -45,8 +45,8 @@ static const char *mysqld_error_message(unsigned sql_errno)
...
@@ -45,8 +45,8 @@ static const char *mysqld_error_message(unsigned sql_errno)
case
ER_BAD_INSTANCE_NAME
:
case
ER_BAD_INSTANCE_NAME
:
return
"Bad instance name. Check that the instance with such a name exists"
;
return
"Bad instance name. Check that the instance with such a name exists"
;
case
ER_INSTANCE_IS_NOT_STARTED
:
case
ER_INSTANCE_IS_NOT_STARTED
:
return
"Cannot stop instance. Perhaps the instance is not started
or you
"
return
"Cannot stop instance. Perhaps the instance is not started
, or was started
"
" have specified wrong username/password in the config file
"
;
"manually, so IM cannot find the pidfile.
"
;
case
ER_INSTANCE_ALREADY_STARTED
:
case
ER_INSTANCE_ALREADY_STARTED
:
return
"The instance is already started"
;
return
"The instance is already started"
;
case
ER_CANNOT_START_INSTANCE
:
case
ER_CANNOT_START_INSTANCE
:
...
...
server-tools/instance-manager/mysql_connection.cc
View file @
451de5db
...
@@ -82,7 +82,6 @@ private:
...
@@ -82,7 +82,6 @@ private:
private:
private:
/* Names are conventionally the same as in mysqld */
/* Names are conventionally the same as in mysqld */
int
check_connection
();
int
check_connection
();
int
check_user
(
const
char
*
user
,
const
char
*
password
);
int
do_command
();
int
do_command
();
int
dispatch_command
(
enum
enum_server_command
command
,
int
dispatch_command
(
enum
enum_server_command
command
,
const
char
*
text
,
uint
len
);
const
char
*
text
,
uint
len
);
...
@@ -287,12 +286,6 @@ int Mysql_connection_thread::check_connection()
...
@@ -287,12 +286,6 @@ int Mysql_connection_thread::check_connection()
}
}
int
Mysql_connection_thread
::
check_user
(
const
char
*
user
,
const
char
*
password
)
{
return
0
;
}
int
Mysql_connection_thread
::
do_command
()
int
Mysql_connection_thread
::
do_command
()
{
{
char
*
packet
;
char
*
packet
;
...
...
server-tools/instance-manager/mysqlmanager.cc
View file @
451de5db
...
@@ -22,6 +22,8 @@
...
@@ -22,6 +22,8 @@
#include <my_sys.h>
#include <my_sys.h>
#include <string.h>
#include <string.h>
#include <signal.h>
#include <signal.h>
#include <pwd.h>
#include <grp.h>
#include <sys/wait.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/stat.h>
...
@@ -54,6 +56,8 @@
...
@@ -54,6 +56,8 @@
static
void
init_environment
(
char
*
progname
);
static
void
init_environment
(
char
*
progname
);
static
void
daemonize
(
const
char
*
log_file_name
);
static
void
daemonize
(
const
char
*
log_file_name
);
static
void
angel
(
const
Options
&
options
);
static
void
angel
(
const
Options
&
options
);
static
struct
passwd
*
check_user
(
const
char
*
user
);
static
int
set_user
(
const
char
*
user
,
struct
passwd
*
user_info
);
/*
/*
...
@@ -68,7 +72,20 @@ int main(int argc, char *argv[])
...
@@ -68,7 +72,20 @@ int main(int argc, char *argv[])
{
{
init_environment
(
argv
[
0
]);
init_environment
(
argv
[
0
]);
Options
options
;
Options
options
;
options
.
load
(
argc
,
argv
);
struct
passwd
*
user_info
;
if
(
options
.
load
(
argc
,
argv
))
goto
err
;
if
((
user_info
=
check_user
(
options
.
user
)))
{
if
(
set_user
(
options
.
user
,
user_info
))
{
options
.
cleanup
();
return
1
;
}
}
if
(
options
.
run_as_service
)
if
(
options
.
run_as_service
)
{
{
/* forks, and returns only in child */
/* forks, and returns only in child */
...
@@ -77,11 +94,84 @@ int main(int argc, char *argv[])
...
@@ -77,11 +94,84 @@ int main(int argc, char *argv[])
angel
(
options
);
angel
(
options
);
}
}
manager
(
options
);
manager
(
options
);
options
.
cleanup
();
my_end
(
0
);
return
0
;
return
0
;
err:
my_end
(
0
);
return
1
;
}
}
/******************* Auxilary functions implementation **********************/
/******************* Auxilary functions implementation **********************/
/* Change to run as another user if started with --user */
static
struct
passwd
*
check_user
(
const
char
*
user
)
{
#if !defined(__WIN__) && !defined(OS2) && !defined(__NETWARE__)
struct
passwd
*
user_info
;
uid_t
user_id
=
geteuid
();
/* Don't bother if we aren't superuser */
if
(
user_id
)
{
if
(
user
)
{
/* Don't give a warning, if real user is same as given with --user */
user_info
=
getpwnam
(
user
);
if
((
!
user_info
||
user_id
!=
user_info
->
pw_uid
))
log_info
(
"One can only use the --user switch if running as root
\n
"
);
}
return
NULL
;
}
if
(
!
user
)
{
log_info
(
"You are running mysqlmanager as root! This might introduce security problems. It is safer to use --user option istead.
\n
"
);
return
NULL
;
}
if
(
!
strcmp
(
user
,
"root"
))
return
NULL
;
/* Avoid problem with dynamic libraries */
if
(
!
(
user_info
=
getpwnam
(
user
)))
{
/* Allow a numeric uid to be used */
const
char
*
pos
;
for
(
pos
=
user
;
my_isdigit
(
default_charset_info
,
*
pos
);
pos
++
)
;
if
(
*
pos
)
/* Not numeric id */
goto
err
;
if
(
!
(
user_info
=
getpwuid
(
atoi
(
user
))))
goto
err
;
else
return
user_info
;
}
else
return
user_info
;
err:
log_error
(
"Fatal error: Can't change to run as user '%s' ; Please check that the user exists!
\n
"
,
user
);
#endif
return
NULL
;
}
static
int
set_user
(
const
char
*
user
,
struct
passwd
*
user_info
)
{
DBUG_ASSERT
(
user_info
);
#ifdef HAVE_INITGROUPS
initgroups
((
char
*
)
user
,
user_info
->
pw_gid
);
#endif
if
(
setgid
(
user_info
->
pw_gid
)
==
-
1
)
{
log_error
(
"setgid() failed"
);
return
1
;
}
if
(
setuid
(
user_info
->
pw_uid
)
==
-
1
)
{
log_error
(
"setuid() failed"
);
return
1
;
}
return
0
;
}
/*
/*
Init environment, common for daemon and non-daemon
Init environment, common for daemon and non-daemon
...
...
server-tools/instance-manager/options.cc
View file @
451de5db
...
@@ -23,6 +23,8 @@
...
@@ -23,6 +23,8 @@
#include <my_global.h>
#include <my_global.h>
#include <my_sys.h>
#include <my_sys.h>
#include <my_getopt.h>
#include <my_getopt.h>
#include <m_string.h>
#include <mysql_com.h>
#include "priv.h"
#include "priv.h"
...
@@ -35,11 +37,13 @@ const char *Options::pid_file_name= QUOTE(DEFAULT_PID_FILE_NAME);
...
@@ -35,11 +37,13 @@ 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
::
socket_file_name
=
QUOTE
(
DEFAULT_SOCKET_FILE_NAME
);
const
char
*
Options
::
password_file_name
=
QUOTE
(
DEFAULT_PASSWORD_FILE_NAME
);
const
char
*
Options
::
password_file_name
=
QUOTE
(
DEFAULT_PASSWORD_FILE_NAME
);
const
char
*
Options
::
default_mysqld_path
=
QUOTE
(
DEFAULT_MYSQLD_PATH
);
const
char
*
Options
::
default_mysqld_path
=
QUOTE
(
DEFAULT_MYSQLD_PATH
);
const
char
*
Options
::
default_admin_user
=
QUOTE
(
DEFAULT_USER
);
const
char
*
Options
::
first_option
=
0
;
/* No default value */
const
char
*
Options
::
default_admin_password
=
QUOTE
(
DEFAULT_PASSWORD
);
const
char
*
Options
::
bind_address
=
0
;
/* No default value */
const
char
*
Options
::
bind_address
=
0
;
/* No default value */
const
char
*
Options
::
user
=
0
;
/* No default value */
uint
Options
::
monitoring_interval
=
DEFAULT_MONITORING_INTERVAL
;
uint
Options
::
monitoring_interval
=
DEFAULT_MONITORING_INTERVAL
;
uint
Options
::
port_number
=
DEFAULT_PORT
;
uint
Options
::
port_number
=
DEFAULT_PORT
;
/* just to declare */
char
**
Options
::
saved_argv
;
/*
/*
List of options, accepted by the instance manager.
List of options, accepted by the instance manager.
...
@@ -54,9 +58,6 @@ enum options {
...
@@ -54,9 +58,6 @@ enum options {
OPT_MYSQLD_PATH
,
OPT_MYSQLD_PATH
,
OPT_RUN_AS_SERVICE
,
OPT_RUN_AS_SERVICE
,
OPT_USER
,
OPT_USER
,
OPT_PASSWORD
,
OPT_DEFAULT_ADMIN_USER
,
OPT_DEFAULT_ADMIN_PASSWORD
,
OPT_MONITORING_INTERVAL
,
OPT_MONITORING_INTERVAL
,
OPT_PORT
,
OPT_PORT
,
OPT_BIND_ADDRESS
OPT_BIND_ADDRESS
...
@@ -79,13 +80,16 @@ static struct my_option my_long_options[] =
...
@@ -79,13 +80,16 @@ static struct my_option my_long_options[] =
(
gptr
*
)
&
Options
::
socket_file_name
,
(
gptr
*
)
&
Options
::
socket_file_name
,
(
gptr
*
)
&
Options
::
socket_file_name
,
(
gptr
*
)
&
Options
::
socket_file_name
,
0
,
GET_STR
,
REQUIRED_ARG
,
0
,
0
,
0
,
0
,
0
,
0
},
0
,
GET_STR
,
REQUIRED_ARG
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"passwd"
,
'P'
,
"Prepare entry for passwd file and exit."
,
0
,
0
,
0
,
GET_NO_ARG
,
NO_ARG
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"bind-address"
,
OPT_BIND_ADDRESS
,
"Bind address to use for connection."
,
{
"bind-address"
,
OPT_BIND_ADDRESS
,
"Bind address to use for connection."
,
(
gptr
*
)
&
Options
::
bind_address
,
(
gptr
*
)
&
Options
::
bind_address
,
(
gptr
*
)
&
Options
::
bind_address
,
(
gptr
*
)
&
Options
::
bind_address
,
0
,
GET_STR
,
REQUIRED_ARG
,
0
,
0
,
0
,
0
,
0
,
0
},
0
,
GET_STR
,
REQUIRED_ARG
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"port"
,
OPT_PORT
,
"Port number to use for connections"
,
{
"port"
,
OPT_PORT
,
"Port number to use for connections"
,
(
gptr
*
)
&
Options
::
port_number
,
(
gptr
*
)
&
Options
::
port_number
,
(
gptr
*
)
&
Options
::
port_number
,
(
gptr
*
)
&
Options
::
port_number
,
0
,
GET_UINT
,
REQUIRED_ARG
,
0
,
0
,
0
,
0
,
0
,
0
},
0
,
GET_UINT
,
REQUIRED_ARG
,
DEFAULT_PORT
,
0
,
0
,
0
,
0
,
0
},
{
"password-file"
,
OPT_PASSWORD_FILE
,
"Look for Instane Manager users"
{
"password-file"
,
OPT_PASSWORD_FILE
,
"Look for Instane Manager users"
" and passwords here."
,
" and passwords here."
,
...
@@ -98,28 +102,22 @@ static struct my_option my_long_options[] =
...
@@ -98,28 +102,22 @@ static struct my_option my_long_options[] =
(
gptr
*
)
&
Options
::
default_mysqld_path
,
(
gptr
*
)
&
Options
::
default_mysqld_path
,
(
gptr
*
)
&
Options
::
default_mysqld_path
,
(
gptr
*
)
&
Options
::
default_mysqld_path
,
0
,
GET_STR
,
REQUIRED_ARG
,
0
,
0
,
0
,
0
,
0
,
0
},
0
,
GET_STR
,
REQUIRED_ARG
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"default-admin-user"
,
OPT_DEFAULT_ADMIN_USER
,
"Username to shutdown MySQL"
" instances."
,
(
gptr
*
)
&
Options
::
default_admin_user
,
(
gptr
*
)
&
Options
::
default_admin_user
,
0
,
GET_STR
,
REQUIRED_ARG
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"default-admin-password"
,
OPT_DEFAULT_ADMIN_PASSWORD
,
"Password to"
"shutdown MySQL instances."
,
(
gptr
*
)
&
Options
::
default_admin_password
,
(
gptr
*
)
&
Options
::
default_admin_password
,
0
,
GET_STR
,
REQUIRED_ARG
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"monitoring-interval"
,
OPT_MONITORING_INTERVAL
,
"Interval to monitor instances"
{
"monitoring-interval"
,
OPT_MONITORING_INTERVAL
,
"Interval to monitor instances"
" in seconds."
,
" in seconds."
,
(
gptr
*
)
&
Options
::
monitoring_interval
,
(
gptr
*
)
&
Options
::
monitoring_interval
,
(
gptr
*
)
&
Options
::
monitoring_interval
,
(
gptr
*
)
&
Options
::
monitoring_interval
,
0
,
GET_UINT
,
REQUIRED_ARG
,
0
,
0
,
0
,
0
,
0
,
0
},
0
,
GET_UINT
,
REQUIRED_ARG
,
DEFAULT_MONITORING_INTERVAL
,
0
,
0
,
0
,
0
,
0
},
{
"run-as-service"
,
OPT_RUN_AS_SERVICE
,
{
"run-as-service"
,
OPT_RUN_AS_SERVICE
,
"Daemonize and start angel process."
,
(
gptr
*
)
&
Options
::
run_as_service
,
"Daemonize and start angel process."
,
(
gptr
*
)
&
Options
::
run_as_service
,
0
,
0
,
GET_BOOL
,
NO_ARG
,
0
,
0
,
1
,
0
,
0
,
0
},
0
,
0
,
GET_BOOL
,
NO_ARG
,
0
,
0
,
1
,
0
,
0
,
0
},
{
"user"
,
OPT_USER
,
"Username to start mysqlmanager"
,
(
gptr
*
)
&
Options
::
user
,
(
gptr
*
)
&
Options
::
user
,
0
,
GET_STR
,
REQUIRED_ARG
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"version"
,
'V'
,
"Output version information and exit."
,
0
,
0
,
0
,
{
"version"
,
'V'
,
"Output version information and exit."
,
0
,
0
,
0
,
GET_NO_ARG
,
NO_ARG
,
0
,
0
,
0
,
0
,
0
,
0
},
GET_NO_ARG
,
NO_ARG
,
0
,
0
,
0
,
0
,
0
,
0
},
...
@@ -150,6 +148,38 @@ static void usage()
...
@@ -150,6 +148,38 @@ static void usage()
my_print_variables
(
my_long_options
);
my_print_variables
(
my_long_options
);
}
}
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
C_MODE_START
static
my_bool
static
my_bool
...
@@ -161,7 +191,9 @@ get_one_option(int optid,
...
@@ -161,7 +191,9 @@ get_one_option(int optid,
case
'V'
:
case
'V'
:
version
();
version
();
exit
(
0
);
exit
(
0
);
case
'I'
:
case
'P'
:
passwd
();
exit
(
0
);
case
'?'
:
case
'?'
:
usage
();
usage
();
exit
(
0
);
exit
(
0
);
...
@@ -180,12 +212,28 @@ C_MODE_END
...
@@ -180,12 +212,28 @@ C_MODE_END
May not return.
May not return.
*/
*/
void
Options
::
load
(
int
argc
,
char
**
argv
)
int
Options
::
load
(
int
argc
,
char
**
argv
)
{
{
int
rc
;
if
(
argc
>=
2
)
{
if
(
is_prefix
(
argv
[
1
],
"--defaults-file="
)
||
is_prefix
(
argv
[
1
],
"--defaults-extra-file="
))
Options
::
first_option
=
argv
[
1
];
}
/* config-file options are prepended to command-line ones */
/* config-file options are prepended to command-line ones */
load_defaults
(
"my"
,
default_groups
,
&
argc
,
&
argv
);
load_defaults
(
"my"
,
default_groups
,
&
argc
,
&
argv
);
if
(
int
rc
=
handle_options
(
&
argc
,
&
argv
,
my_long_options
,
get_one_option
))
if
((
rc
=
handle_options
(
&
argc
,
&
argv
,
my_long_options
,
get_one_option
))
!=
0
)
exit
(
rc
);
return
rc
;
Options
::
saved_argv
=
argv
;
return
0
;
}
}
void
Options
::
cleanup
()
{
/* free_defaults returns nothing */
free_defaults
(
Options
::
saved_argv
);
}
server-tools/instance-manager/options.h
View file @
451de5db
...
@@ -34,13 +34,17 @@ struct Options
...
@@ -34,13 +34,17 @@ struct Options
static
const
char
*
socket_file_name
;
static
const
char
*
socket_file_name
;
static
const
char
*
password_file_name
;
static
const
char
*
password_file_name
;
static
const
char
*
default_mysqld_path
;
static
const
char
*
default_mysqld_path
;
static
const
char
*
default_admin_user
;
static
const
char
*
user
;
static
const
char
*
default_admin_password
;
/* the option which should be passed to process_default_option_files */
static
const
char
*
first_option
;
static
uint
monitoring_interval
;
static
uint
monitoring_interval
;
static
uint
port_number
;
static
uint
port_number
;
static
const
char
*
bind_address
;
static
const
char
*
bind_address
;
static
void
load
(
int
argc
,
char
**
argv
);
static
char
**
saved_argv
;
static
int
load
(
int
argc
,
char
**
argv
);
void
cleanup
();
};
};
#endif // INCLUDES_MYSQL_INSTANCE_MANAGER_OPTIONS_H
#endif // INCLUDES_MYSQL_INSTANCE_MANAGER_OPTIONS_H
server-tools/instance-manager/parse.cc
View file @
451de5db
...
@@ -49,29 +49,6 @@ static struct tokens_st tokens[]= {
...
@@ -49,29 +49,6 @@ static struct tokens_st tokens[]= {
};
};
/*
tries to find next word in the text
if found, returns the beginning and puts word length to word_len argument.
if not found returns pointer to first non-space or to '\0', word_len == 0
*/
inline
void
get_word
(
const
char
**
text
,
uint
*
word_len
)
{
const
char
*
word_end
;
/* skip space */
while
(
my_isspace
(
default_charset_info
,
**
text
))
++
(
*
text
);
word_end
=
*
text
;
while
(
my_isalnum
(
default_charset_info
,
*
word_end
))
++
word_end
;
*
word_len
=
word_end
-
*
text
;
}
/*
/*
Returns token no if word corresponds to some token, otherwise returns
Returns token no if word corresponds to some token, otherwise returns
TOK_NOT_FOUND
TOK_NOT_FOUND
...
...
server-tools/instance-manager/parse.h
View file @
451de5db
...
@@ -20,4 +20,34 @@
...
@@ -20,4 +20,34 @@
Command
*
parse_command
(
Command_factory
*
factory
,
const
char
*
text
);
Command
*
parse_command
(
Command_factory
*
factory
,
const
char
*
text
);
/* define kinds of the word seek method */
enum
{
ALPHANUM
=
1
,
NONSPACE
};
/*
tries to find next word in the text
if found, returns the beginning and puts word length to word_len argument.
if not found returns pointer to first non-space or to '\0', word_len == 0
*/
inline
void
get_word
(
const
char
**
text
,
uint
*
word_len
,
int
seek_method
=
ALPHANUM
)
{
const
char
*
word_end
;
/* skip space */
while
(
my_isspace
(
default_charset_info
,
**
text
))
++
(
*
text
);
word_end
=
*
text
;
if
(
seek_method
==
ALPHANUM
)
while
(
my_isalnum
(
default_charset_info
,
*
word_end
))
++
word_end
;
else
while
(
!
my_isspace
(
default_charset_info
,
*
word_end
))
++
word_end
;
*
word_len
=
word_end
-
*
text
;
}
#endif
/* INCLUDES_MYSQL_INSTANCE_MANAGER_PARSE_H */
#endif
/* INCLUDES_MYSQL_INSTANCE_MANAGER_PARSE_H */
server-tools/instance-manager/parse_output.cc
0 → 100644
View file @
451de5db
/* Copyright (C) 2004 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 */
#include "parse.h"
#include <stdio.h>
#include <my_global.h>
#include <my_sys.h>
#include <string.h>
/*
Parse output of the given command
SYNOPSYS
parse_output_and_get_value()
command the command to execue with popen.
word the word to look for (usually an option name)
result the buffer to store the next word (option value)
result_len self-explanatory
DESCRIPTION
Parse output of the "command". Find the "word" and return the next one
RETURN
0 - ok
1 - error occured
*/
int
parse_output_and_get_value
(
const
char
*
command
,
const
char
*
word
,
char
*
result
,
size_t
result_len
)
{
FILE
*
output
;
uint
wordlen
;
/* should be enought to store the string from the output */
enum
{
MAX_LINE_LEN
=
512
};
char
linebuf
[
MAX_LINE_LEN
];
wordlen
=
strlen
(
word
);
if
((
output
=
popen
(
command
,
"r"
))
==
NULL
)
goto
err
;
/*
We want fully buffered stream. We also want system to
allocate appropriate buffer.
*/
setvbuf
(
output
,
NULL
,
_IOFBF
,
0
);
while
(
fgets
(
linebuf
,
sizeof
(
linebuf
)
-
1
,
output
))
{
uint
lineword_len
=
0
;
char
*
linep
=
linebuf
;
linebuf
[
sizeof
(
linebuf
)
-
1
]
=
'\0'
;
/* safety */
/*
Get the word, which might contain non-alphanumeric characters. (Usually
these are '/', '-' and '.' in the path expressions and filenames)
*/
get_word
((
const
char
**
)
&
linep
,
&
lineword_len
,
NONSPACE
);
if
(
!
strncmp
(
word
,
linep
,
wordlen
))
{
/*
If we have found the word, return the next one. This is usually
an option value.
*/
linep
+=
lineword_len
;
/* swallow the previous one */
get_word
((
const
char
**
)
&
linep
,
&
lineword_len
,
NONSPACE
);
if
(
result_len
<=
lineword_len
)
goto
err
;
strncpy
(
result
,
linep
,
lineword_len
);
result
[
lineword_len
]
=
'\0'
;
goto
pclose
;
}
}
pclose:
/* we are not interested in the termination status */
pclose
(
output
);
return
0
;
err:
return
1
;
}
server-tools/instance-manager/parse_output.h
0 → 100644
View file @
451de5db
/* Copyright (C) 2004 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 */
int
parse_output_and_get_value
(
const
char
*
command
,
const
char
*
word
,
char
*
result
,
size_t
result_len
);
server-tools/instance-manager/protocol.cc
View file @
451de5db
...
@@ -154,7 +154,8 @@ int send_fields(struct st_net *net, LIST *fields)
...
@@ -154,7 +154,8 @@ int send_fields(struct st_net *net, LIST *fields)
store_to_string
(
&
send_buff
,
(
char
*
)
""
,
&
position
);
/* table name alias */
store_to_string
(
&
send_buff
,
(
char
*
)
""
,
&
position
);
/* table name alias */
store_to_string
(
&
send_buff
,
field
->
name
,
&
position
);
/* column name */
store_to_string
(
&
send_buff
,
field
->
name
,
&
position
);
/* column name */
store_to_string
(
&
send_buff
,
field
->
name
,
&
position
);
/* column name alias */
store_to_string
(
&
send_buff
,
field
->
name
,
&
position
);
/* column name alias */
if
(
send_buff
.
reserve
(
position
,
12
))
send_buff
.
reserve
(
position
,
12
);
if
(
send_buff
.
is_error
())
goto
err
;
goto
err
;
send_buff
.
buffer
[
position
++
]
=
12
;
send_buff
.
buffer
[
position
++
]
=
12
;
int2store
(
send_buff
.
buffer
+
position
,
1
);
/* charsetnr */
int2store
(
send_buff
.
buffer
+
position
,
1
);
/* charsetnr */
...
...
server-tools/instance-manager/thread_registry.cc
View file @
451de5db
...
@@ -197,6 +197,7 @@ void Thread_registry::deliver_shutdown()
...
@@ -197,6 +197,7 @@ void Thread_registry::deliver_shutdown()
if
(
info
->
current_cond
)
if
(
info
->
current_cond
)
pthread_cond_signal
(
info
->
current_cond
);
pthread_cond_signal
(
info
->
current_cond
);
}
}
pthread_mutex_unlock
(
&
LOCK_thread_registry
);
pthread_mutex_unlock
(
&
LOCK_thread_registry
);
}
}
...
...
server-tools/instance-manager/thread_repository.cc
deleted
100644 → 0
View file @
32a3c163
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
#ifdef __GNUC__
#pragma implementation
#endif
#include "thread_repository.h"
#include <assert.h>
#include <signal.h>
#include "log.h"
/* Kick-off signal handler */
enum
{
THREAD_KICK_OFF_SIGNAL
=
SIGUSR2
};
static
void
handle_signal
(
int
__attribute__
((
unused
))
sig_no
)
{
}
/*
TODO: think about moving signal information (now it's shutdown_in_progress)
to Thread_info. It will reduce contention and allow signal deliverence to
a particular thread, not to the whole worker crew
*/
Thread_repository
::
Thread_repository
()
:
shutdown_in_progress
(
false
)
{
pthread_mutex_init
(
&
LOCK_thread_repository
,
0
);
pthread_cond_init
(
&
COND_thread_repository_is_empty
,
0
);
/* head is used by-value to simplify nodes inserting */
head
.
next
=
head
.
prev
=
&
head
;
}
Thread_repository
::~
Thread_repository
()
{
/* Check that no one uses the repository. */
pthread_mutex_lock
(
&
LOCK_thread_repository
);
/* All threads must unregister */
DBUG_ASSERT
(
head
.
next
==
&
head
);
pthread_mutex_unlock
(
&
LOCK_thread_repository
);
pthread_cond_destroy
(
&
COND_thread_repository_is_empty
);
pthread_mutex_destroy
(
&
LOCK_thread_repository
);
}
/*
Set signal handler for kick-off thread, and insert a thread info to the
repository. New node is appended to the end of the list; head.prev always
points to the last node.
*/
void
Thread_repository
::
register_thread
(
Thread_info
*
info
)
{
struct
sigaction
sa
;
sa
.
sa_handler
=
handle_signal
;
sa
.
sa_flags
=
0
;
sigemptyset
(
&
sa
.
sa_mask
);
sigaction
(
THREAD_KICK_OFF_SIGNAL
,
&
sa
,
0
);
info
->
current_cond
=
0
;
pthread_mutex_lock
(
&
LOCK_thread_repository
);
info
->
next
=
&
head
;
info
->
prev
=
head
.
prev
;
head
.
prev
->
next
=
info
;
head
.
prev
=
info
;
pthread_mutex_unlock
(
&
LOCK_thread_repository
);
}
/*
Unregister a thread from the repository and free Thread_info structure.
Every registered thread must unregister. Unregistering should be the last
thing a thread is doing, otherwise it could have no time to finalize.
*/
void
Thread_repository
::
unregister_thread
(
Thread_info
*
info
)
{
pthread_mutex_lock
(
&
LOCK_thread_repository
);
info
->
prev
->
next
=
info
->
next
;
info
->
next
->
prev
=
info
->
prev
;
if
(
head
.
next
==
&
head
)
pthread_cond_signal
(
&
COND_thread_repository_is_empty
);
pthread_mutex_unlock
(
&
LOCK_thread_repository
);
}
/*
Check whether shutdown is in progress, and if yes, return immidiately.
Else set info->current_cond and call pthread_cond_wait. When
pthread_cond_wait returns, unregister current cond and check the shutdown
status again.
RETURN VALUE
return value from pthread_cond_wait
*/
int
Thread_repository
::
cond_wait
(
Thread_info
*
info
,
pthread_cond_t
*
cond
,
pthread_mutex_t
*
mutex
,
bool
*
is_shutdown
)
{
pthread_mutex_lock
(
&
LOCK_thread_repository
);
*
is_shutdown
=
shutdown_in_progress
;
if
(
*
is_shutdown
)
{
pthread_mutex_unlock
(
&
LOCK_thread_repository
);
return
0
;
}
info
->
current_cond
=
cond
;
pthread_mutex_unlock
(
&
LOCK_thread_repository
);
/* sic: race condition here, cond can be signaled in deliver_shutdown */
int
rc
=
pthread_cond_wait
(
cond
,
mutex
);
pthread_mutex_lock
(
&
LOCK_thread_repository
);
info
->
current_cond
=
0
;
*
is_shutdown
=
shutdown_in_progress
;
pthread_mutex_unlock
(
&
LOCK_thread_repository
);
return
rc
;
}
/*
Deliver shutdown message to the workers crew.
As it's impossible to avoid all race conditions, we signal latecomers
again.
*/
void
Thread_repository
::
deliver_shutdown
()
{
struct
timespec
shutdown_time
;
set_timespec
(
shutdown_time
,
1
);
Thread_info
*
info
;
pthread_mutex_lock
(
&
LOCK_thread_repository
);
shutdown_in_progress
=
true
;
for
(
info
=
head
.
next
;
info
!=
&
head
;
info
=
info
->
next
)
{
pthread_kill
(
info
->
thread_id
,
THREAD_KICK_OFF_SIGNAL
);
/*
sic: race condition here, the thread may not yet fall into
pthread_cond_wait.
*/
if
(
info
->
current_cond
)
pthread_cond_signal
(
info
->
current_cond
);
}
while
(
pthread_cond_timedwait
(
&
COND_thread_repository_is_empty
,
&
LOCK_thread_repository
,
&
shutdown_time
)
!=
ETIMEDOUT
&&
head
.
next
!=
&
head
)
;
/*
If previous signals did not reach some threads, they must be sleeping
in pthread_cond_wait or a blocking syscall. Wake them up:
every thread shall check signal variables after each syscall/cond_wait,
so this time everybody should be informed (presumably each worker can
get CPU during shutdown_time.)
*/
for
(
info
=
head
.
next
;
info
!=
&
head
;
info
=
info
->
next
)
{
pthread_kill
(
info
->
thread_id
,
THREAD_KICK_OFF_SIGNAL
);
if
(
info
->
current_cond
)
pthread_cond_signal
(
info
->
current_cond
);
}
pthread_mutex_unlock
(
&
LOCK_thread_repository
);
}
server-tools/instance-manager/thread_repository.h
deleted
100644 → 0
View file @
32a3c163
#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_THREAD_REPOSITORY_HH
#define INCLUDES_MYSQL_INSTANCE_MANAGER_THREAD_REPOSITORY_HH
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
/*
A multi-threaded application shall nicely work with signals.
This means it shall, first of all, shut down nicely on ``quit'' signals:
stop all running threads, cleanup and exit.
Note, that a thread can't be shut down nicely if it doesn't want to be.
That's why to perform clean shutdown, all threads consituting a process
must observe certain rules. Here we use the rules, described in Butenhof
book 'Programming with POSIX threads', namely:
- all user signals are handled in 'signal thread' in synchronous manner
(by means of sigwait). To guarantee that the signal thread is the only who
can receive user signals, all threads block them, and signal thread is
the only who calls sigwait() with an apporpriate sigmask.
To propogate a signal to the workers the signal thread sets
a variable, corresponding to the signal. Additionally the signal thread
sends each worker an internal signal (by means of pthread_kill) to kick it
out from possible blocking syscall, and possibly pthread_cond_signal if
some thread is blocked in pthread_cond_[timed]wait.
- a worker handles only internal 'kick' signal (the handler does nothing).
In case when a syscall returns 'EINTR' the worker checks all
signal-related variables and behaves accordingly.
Also these variables shall be checked from time to time in long
CPU-bounded operations, and before/after pthread_cond_wait. (It's supposed
that a worker thread either waits in a syscall/conditional variable, or
computes something.)
- to guarantee signal deliverence, there should be some kind of feedback,
e. g. all workers shall account in the signal thread Thread Repository and
unregister from it on exit.
Configuration reload (on SIGHUP) and thread timeouts/alarms can be handled
in manner, similar to ``quit'' signals.
*/
#ifdef __GNUC__
#pragma interface
#endif
#include <my_global.h>
#include <my_pthread.h>
/*
Thread_info - repository entry for each worker thread
All entries comprise double-linked list like:
0 -- entry -- entry -- entry - 0
Double-linked list is used to unregister threads easy.
*/
class
Thread_info
{
pthread_cond_t
*
current_cond
;
Thread_info
*
prev
,
*
next
;
pthread_t
thread_id
;
Thread_info
()
{}
friend
class
Thread_repository
;
public:
Thread_info
(
pthread_t
thread_id_arg
)
:
thread_id
(
thread_id_arg
)
{}
};
/*
Thread_repository - contains handles for each worker thread to deliver
signal information to workers.
*/
class
Thread_repository
{
public:
Thread_repository
();
~
Thread_repository
();
void
register_thread
(
Thread_info
*
info
);
void
unregister_thread
(
Thread_info
*
info
);
void
deliver_shutdown
();
inline
bool
is_shutdown
();
int
cond_wait
(
Thread_info
*
info
,
pthread_cond_t
*
cond
,
pthread_mutex_t
*
mutex
,
bool
*
is_shutdown
);
private:
Thread_info
head
;
bool
shutdown_in_progress
;
pthread_mutex_t
LOCK_thread_repository
;
pthread_cond_t
COND_thread_repository_is_empty
;
};
inline
bool
Thread_repository
::
is_shutdown
()
{
pthread_mutex_lock
(
&
LOCK_thread_repository
);
bool
res
=
shutdown_in_progress
;
pthread_mutex_unlock
(
&
LOCK_thread_repository
);
return
res
;
}
#endif // INCLUDES_MYSQL_INSTANCE_MANAGER_THREAD_REPOSITORY_HH
server-tools/instance-manager/user_map.cc
View file @
451de5db
...
@@ -69,7 +69,7 @@ int User::init(const char *line)
...
@@ -69,7 +69,7 @@ int User::init(const char *line)
return
0
;
return
0
;
err:
err:
log_error
(
"error parsing user and password at line %
d
"
,
line
);
log_error
(
"error parsing user and password at line %
s
"
,
line
);
return
1
;
return
1
;
}
}
...
@@ -128,9 +128,10 @@ int User_map::load(const char *password_file_name)
...
@@ -128,9 +128,10 @@ int User_map::load(const char *password_file_name)
if
((
file
=
my_fopen
(
password_file_name
,
O_RDONLY
|
O_BINARY
,
MYF
(
0
)))
==
0
)
if
((
file
=
my_fopen
(
password_file_name
,
O_RDONLY
|
O_BINARY
,
MYF
(
0
)))
==
0
)
{
{
log_error
(
"can't open password file %s: errno=%d, %s"
,
password_file_name
,
/* 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
));
errno
,
strerror
(
errno
));
return
1
;
return
0
;
}
}
while
(
fgets
(
line
,
sizeof
(
line
),
file
))
while
(
fgets
(
line
,
sizeof
(
line
),
file
))
...
...
support-files/mysql.spec.sh
View file @
451de5db
...
@@ -417,8 +417,9 @@ install -s -m755 $MBD/sql/mysqld-max $RBR%{_sbindir}/mysqld-max
...
@@ -417,8 +417,9 @@ install -s -m755 $MBD/sql/mysqld-max $RBR%{_sbindir}/mysqld-max
install
-m644
$MBD
/sql/mysqld-max.sym
$RBR
%
{
_libdir
}
/mysql/mysqld-max.sym
install
-m644
$MBD
/sql/mysqld-max.sym
$RBR
%
{
_libdir
}
/mysql/mysqld-max.sym
install
-m644
$MBD
/sql/mysqld.sym
$RBR
%
{
_libdir
}
/mysql/mysqld.sym
install
-m644
$MBD
/sql/mysqld.sym
$RBR
%
{
_libdir
}
/mysql/mysqld.sym
# Install logrotate
and autostart
# Install logrotate
, autostart and config file
install
-m644
$MBD
/support-files/mysql-log-rotate
$RBR
%
{
_sysconfdir
}
/logrotate.d/mysql
install
-m644
$MBD
/support-files/mysql-log-rotate
$RBR
%
{
_sysconfdir
}
/logrotate.d/mysql
install
-m644
$MBD
/support-files/my.cnf
$RBR
%
{
_sysconfdir
}
/my.cnf
install
-m755
$MBD
/support-files/mysql.server
$RBR
%
{
_sysconfdir
}
/init.d/mysql
install
-m755
$MBD
/support-files/mysql.server
$RBR
%
{
_sysconfdir
}
/init.d/mysql
# Create a symlink "rcmysql", pointing to the init.script. SuSE users
# Create a symlink "rcmysql", pointing to the init.script. SuSE users
...
@@ -429,10 +430,6 @@ ln -s %{_sysconfdir}/init.d/mysql $RPM_BUILD_ROOT%{_sbindir}/rcmysql
...
@@ -429,10 +430,6 @@ ln -s %{_sysconfdir}/init.d/mysql $RPM_BUILD_ROOT%{_sbindir}/rcmysql
# (safe_mysqld will be gone in MySQL 4.1)
# (safe_mysqld will be gone in MySQL 4.1)
ln
-sf
./mysqld_safe
$RBR
%
{
_bindir
}
/safe_mysqld
ln
-sf
./mysqld_safe
$RBR
%
{
_bindir
}
/safe_mysqld
# Touch the place where the my.cnf config file might be located
# Just to make sure it's in the file list and marked as a config file
touch
$RBR
%
{
_sysconfdir
}
/my.cnf
%pre server
%pre server
# Shut down a previously installed server first
# Shut down a previously installed server first
if
test
-x
%
{
_sysconfdir
}
/init.d/mysql
if
test
-x
%
{
_sysconfdir
}
/init.d/mysql
...
@@ -550,8 +547,6 @@ fi
...
@@ -550,8 +547,6 @@ fi
%doc %attr
(
644, root, man
)
%
{
_mandir
}
/man1/perror.1
*
%doc %attr
(
644, root, man
)
%
{
_mandir
}
/man1/perror.1
*
%doc %attr
(
644, root, man
)
%
{
_mandir
}
/man1/replace.1
*
%doc %attr
(
644, root, man
)
%
{
_mandir
}
/man1/replace.1
*
%ghost %config
(
noreplace,missingok
)
%
{
_sysconfdir
}
/my.cnf
%attr
(
755, root, root
)
%
{
_bindir
}
/my_print_defaults
%attr
(
755, root, root
)
%
{
_bindir
}
/my_print_defaults
%attr
(
755, root, root
)
%
{
_bindir
}
/myisamchk
%attr
(
755, root, root
)
%
{
_bindir
}
/myisamchk
%attr
(
755, root, root
)
%
{
_bindir
}
/myisam_ftdump
%attr
(
755, root, root
)
%
{
_bindir
}
/myisam_ftdump
...
@@ -579,10 +574,12 @@ fi
...
@@ -579,10 +574,12 @@ fi
%attr
(
755, root, root
)
%
{
_bindir
}
/safe_mysqld
%attr
(
755, root, root
)
%
{
_bindir
}
/safe_mysqld
%attr
(
755, root, root
)
%
{
_sbindir
}
/mysqld
%attr
(
755, root, root
)
%
{
_sbindir
}
/mysqld
%attr
(
755, root, root
)
%
{
_sbindir
}
/mysqlmanager
%attr
(
755, root, root
)
%
{
_sbindir
}
/rcmysql
%attr
(
755, root, root
)
%
{
_sbindir
}
/rcmysql
%attr
(
644, root, root
)
%
{
_libdir
}
/mysql/mysqld.sym
%attr
(
644, root, root
)
%
{
_libdir
}
/mysql/mysqld.sym
%attr
(
644, root, root
)
%config
(
noreplace,missingok
)
%
{
_sysconfdir
}
/logrotate.d/mysql
%attr
(
644, root, root
)
%config
(
noreplace,missingok
)
%
{
_sysconfdir
}
/logrotate.d/mysql
%attr
(
644, root, root
)
%config
(
noreplace,missingok
)
%
{
_sysconfdir
}
/my.cnf
%attr
(
755, root, root
)
%
{
_sysconfdir
}
/init.d/mysql
%attr
(
755, root, root
)
%
{
_sysconfdir
}
/init.d/mysql
%attr
(
755, root, root
)
%
{
_datadir
}
/mysql/
%attr
(
755, root, root
)
%
{
_datadir
}
/mysql/
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment