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
fd94614f
Commit
fd94614f
authored
Dec 09, 2004
by
petr@mysql.com
Browse files
Options
Browse Files
Download
Plain Diff
merge
parents
aa2f1161
d2115d13
Changes
44
Hide whitespace changes
Inline
Side-by-side
Showing
44 changed files
with
4414 additions
and
147 deletions
+4414
-147
.bzrignore
.bzrignore
+5
-0
server-tools/instance-manager/Makefile.am
server-tools/instance-manager/Makefile.am
+75
-13
server-tools/instance-manager/buffer.cc
server-tools/instance-manager/buffer.cc
+97
-0
server-tools/instance-manager/buffer.h
server-tools/instance-manager/buffer.h
+57
-0
server-tools/instance-manager/client_func.c
server-tools/instance-manager/client_func.c
+32
-0
server-tools/instance-manager/command.cc
server-tools/instance-manager/command.cc
+33
-0
server-tools/instance-manager/command.h
server-tools/instance-manager/command.h
+47
-0
server-tools/instance-manager/commands.cc
server-tools/instance-manager/commands.cc
+421
-0
server-tools/instance-manager/commands.h
server-tools/instance-manager/commands.h
+131
-0
server-tools/instance-manager/factory.cc
server-tools/instance-manager/factory.cc
+60
-0
server-tools/instance-manager/factory.h
server-tools/instance-manager/factory.h
+45
-0
server-tools/instance-manager/guardian.cc
server-tools/instance-manager/guardian.cc
+214
-0
server-tools/instance-manager/guardian.h
server-tools/instance-manager/guardian.h
+86
-0
server-tools/instance-manager/instance.cc
server-tools/instance-manager/instance.cc
+167
-0
server-tools/instance-manager/instance.h
server-tools/instance-manager/instance.h
+60
-0
server-tools/instance-manager/instance_map.cc
server-tools/instance-manager/instance_map.cc
+256
-0
server-tools/instance-manager/instance_map.h
server-tools/instance-manager/instance_map.h
+93
-0
server-tools/instance-manager/instance_options.cc
server-tools/instance-manager/instance_options.cc
+181
-0
server-tools/instance-manager/instance_options.h
server-tools/instance-manager/instance_options.h
+77
-0
server-tools/instance-manager/listener.cc
server-tools/instance-manager/listener.cc
+299
-55
server-tools/instance-manager/listener.h
server-tools/instance-manager/listener.h
+21
-10
server-tools/instance-manager/log.cc
server-tools/instance-manager/log.cc
+3
-3
server-tools/instance-manager/log.h
server-tools/instance-manager/log.h
+3
-6
server-tools/instance-manager/manager.cc
server-tools/instance-manager/manager.cc
+140
-11
server-tools/instance-manager/manager.h
server-tools/instance-manager/manager.h
+4
-2
server-tools/instance-manager/messages.cc
server-tools/instance-manager/messages.cc
+73
-0
server-tools/instance-manager/messages.h
server-tools/instance-manager/messages.h
+26
-0
server-tools/instance-manager/mysql_connection.cc
server-tools/instance-manager/mysql_connection.cc
+388
-0
server-tools/instance-manager/mysql_connection.h
server-tools/instance-manager/mysql_connection.h
+60
-0
server-tools/instance-manager/mysql_manager_error.h
server-tools/instance-manager/mysql_manager_error.h
+27
-0
server-tools/instance-manager/mysqlmanager.cc
server-tools/instance-manager/mysqlmanager.cc
+38
-31
server-tools/instance-manager/options.cc
server-tools/instance-manager/options.cc
+78
-10
server-tools/instance-manager/options.h
server-tools/instance-manager/options.h
+10
-2
server-tools/instance-manager/parse.cc
server-tools/instance-manager/parse.cc
+207
-0
server-tools/instance-manager/parse.h
server-tools/instance-manager/parse.h
+23
-0
server-tools/instance-manager/priv.cc
server-tools/instance-manager/priv.cc
+39
-0
server-tools/instance-manager/priv.h
server-tools/instance-manager/priv.h
+64
-0
server-tools/instance-manager/protocol.cc
server-tools/instance-manager/protocol.cc
+179
-0
server-tools/instance-manager/protocol.h
server-tools/instance-manager/protocol.h
+43
-0
server-tools/instance-manager/thread_registry.cc
server-tools/instance-manager/thread_registry.cc
+206
-0
server-tools/instance-manager/thread_registry.h
server-tools/instance-manager/thread_registry.h
+116
-0
server-tools/instance-manager/user_map.cc
server-tools/instance-manager/user_map.cc
+176
-0
server-tools/instance-manager/user_map.h
server-tools/instance-manager/user_map.h
+45
-0
sql/net_serv.cc
sql/net_serv.cc
+9
-4
No files found.
.bzrignore
View file @
fd94614f
...
...
@@ -538,6 +538,7 @@ myisam/test2.MYD
myisam/test2.MYI
mysql-4.0.2-alpha-pc-linux-gnu-i686.tar.gz
mysql-4.0.2-alpha.tar.gz
mysql-5.0.2-alpha.tar.gz
mysql-max-4.0.2-alpha-pc-linux-gnu-i686.tar.gz
mysql-test/gmon.out
mysql-test/install_test_db
...
...
@@ -816,7 +817,11 @@ scripts/mysqldumpslow
scripts/mysqlhotcopy
scripts/safe_mysqld
select_test
server-tools/instance-manager/client.c
server-tools/instance-manager/client_settings.h
server-tools/instance-manager/errmsg.c
server-tools/instance-manager/mysqlmanager
server-tools/instance-manager/thr_alarm.c
sql-bench/Results-linux/ATIS-mysql_bdb-Linux_2.2.14_my_SMP_i686
sql-bench/bench-count-distinct
sql-bench/bench-init.pl
...
...
server-tools/instance-manager/Makefile.am
View file @
fd94614f
# 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
INCLUDES
=
-I
$(top_srcdir)
/include
DEFS
=
-DMYSQL_INSTANCE_MANAGER
-DMYSQL_SERVER
# As all autoconf variables depend from ${prefix} and being resolved only when
# make is run, we can
'
t put these defines to a header file (e.g. to
# make is run, we can
no
t put these defines to a header file (e.g. to
# default_options.h, generated from default_options.h.in)
# See automake/autoconf docs for details
noinst_LIBRARIES
=
liboptions.a
noinst_LIBRARIES
=
liboptions.a libnet.a
liboptions_a_CPPFLAGS
=
$(CPPFLAGS)
\
-DDEFAULT_PID_FILE_NAME
=
"
$(localstatedir)
/mysqlmanager.pid"
\
-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_MYSQLD_PATH
=
"
$(bindir)
/mysqld
$(EXEEXT)
"
\
-DDEFAULT_USER
=
"root"
\
-DDEFAULT_PASSWORD
=
""
\
-DDEFAULT_MONITORING_INTERVAL
=
"5"
\
-DDEFAULT_PORT
=
"33006"
\
-DPROTOCOL_VERSION
=
@PROTOCOL_VERSION@
liboptions_a_SOURCES
=
options.h options.cc priv.h priv.cc
# MySQL sometimes uses symlinks to reuse code
# All symlinked files are grouped in libnet.a
nodist_libnet_a_SOURCES
=
net_serv.cc client_settings.h
libnet_a_LIBADD
=
$(top_builddir)
/sql/password.
$(OBJEXT)
\
$(top_builddir)
/sql/pack.
$(OBJEXT)
\
$(top_builddir)
/sql/sql_state.
$(OBJEXT)
\
$(top_builddir)
/sql/mini_client_errors.
$(OBJEXT)
\
$(top_builddir)
/sql/client.
$(OBJEXT)
CLEANFILES
=
net_serv.cc client_settings.h
net_serv.cc
:
Makefile
rm
-f
$(srcdir)
/net_serv.cc
@
LN_CP_F@
$(top_srcdir)
/sql/net_serv.cc
$(srcdir)
/net_serv.cc
client_settings.h
:
Makefile
rm
-f
$(srcdir)
/client_settings.h
@
LN_CP_F@
$(top_srcdir)
/sql/client_settings.h
$(srcdir)
/client_settings.h
liboptions_a_SOURCES
=
options.h options.cc
bin_PROGRAMS
=
mysqlmanager
bin_PROGRAMS
=
mysqlmanager
mysqlmanager_SOURCES
=
command.cc command.h mysqlmanager.cc
\
manager.h manager.cc log.h log.cc
\
thread_registry.h thread_registry.cc
\
listener.h listener.cc protocol.h protocol.cc
\
mysql_connection.h mysql_connection.cc
\
user_map.h user_map.cc
\
messages.h messages.cc
\
commands.h commands.cc
\
factory.h factory.cc
\
instance.h instance.cc
\
instance_map.h instance_map.cc
\
instance_options.h instance_options.cc
\
buffer.h buffer.cc parse.cc parse.h
\
guardian.cc guardian.h
\
mysql_manager_error.h client_func.c
mysqlmanager_SOURCES
=
mysqlmanager.cc manager.h manager.cc log.h log.cc
\
listener.h listener.cc
\
thread_repository.h thread_repository.cc
mysqlmanager_LDADD
=
liboptions.a
\
libnet.a
\
$(top_builddir)
/vio/libvio.a
\
$(top_builddir)
/mysys/libmysys.a
\
$(top_builddir)
/strings/libmystrings.a
\
$(top_builddir)
/dbug/libdbug.a
\
@openssl_libs@ @ZLIB_LIBS@
mysqlmanager_LDADD
=
liboptions.a
\
$(top_builddir)
/mysys/libmysys.a
\
$(top_builddir)
/strings/libmystrings.a
\
$(top_builddir)
/dbug/libdbug.a
tags
:
tags
:
ctags
-R
*
.h
*
.cc
# Don't update the files from bitkeeper
...
...
server-tools/instance-manager/buffer.cc
0 → 100644
View file @
fd94614f
/* 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 */
#ifdef __GNUC__
#pragma implementation
#endif
#include "buffer.h"
#include <m_string.h>
/*
Puts the given string to the buffer.
SYNOPSYS
append()
position start position in the buffer
string string to be put in the buffer
len_arg the length of the string. This way we can avoid some
strlens.
DESCRIPTION
The method puts a string into the buffer, starting from position .
In the case when the buffer is too small it reallocs the buffer. The
total size of the buffer is restricted with 16.
RETURN
0 - ok
1 - The buffer came to 16Mb barrier
*/
int
Buffer
::
append
(
uint
position
,
const
char
*
string
,
uint
len_arg
)
{
if
(
reserve
(
position
,
len_arg
))
return
1
;
strnmov
(
buffer
+
position
,
string
,
len_arg
);
return
0
;
}
/*
Checks whether the current buffer size is ok to put a string of the length
"len_arg" starting from "position" and reallocs it if no.
SYNOPSYS
reserve()
position the number starting byte on the buffer to store a buffer
len_arg the length of the string.
DESCRIPTION
The method checks whether it is possible to pus a string of teh "len_arg"
length into the buffer, starting from "position" byte. In the case when the
buffer is too small it reallocs the buffer. The total size of the buffer is
restricted with 16 Mb.
RETURN
0 - ok
1 - The buffer came to 16Mb barrier
*/
int
Buffer
::
reserve
(
uint
position
,
uint
len_arg
)
{
if
(
position
+
len_arg
>=
MAX_BUFFER_SIZE
)
goto
err
;
if
(
position
+
len_arg
>=
buffer_size
)
{
buffer
=
(
char
*
)
realloc
(
buffer
,
min
(
MAX_BUFFER_SIZE
,
max
((
uint
)
(
buffer_size
*
1.5
),
position
+
len_arg
)));
if
(
buffer
=
NULL
)
goto
err
;
buffer_size
=
(
uint
)
(
buffer_size
*
1.5
);
}
return
0
;
err:
return
1
;
}
server-tools/instance-manager/buffer.h
0 → 100644
View file @
fd94614f
#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_BUFFER_H
#define INCLUDES_MYSQL_INSTANCE_MANAGER_BUFFER_H
/* 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 <my_global.h>
#ifdef __GNUC__
#pragma interface
#endif
/*
This class is a simple implementation of the buffer of varying size.
It is used to store MySQL client-server protocol packets. This is why
the maximum buffer size if 16Mb. (See internals manual section
7. MySQL Client/Server Protocol)
*/
class
Buffer
{
private:
enum
{
BUFFER_INITIAL_SIZE
=
4096
};
/* maximum buffer size is 16Mb */
enum
{
MAX_BUFFER_SIZE
=
16777216
};
size_t
buffer_size
;
public:
Buffer
()
{
buffer
=
(
char
*
)
malloc
(
BUFFER_INITIAL_SIZE
);
buffer_size
=
BUFFER_INITIAL_SIZE
;
}
~
Buffer
()
{
free
(
buffer
);
}
public:
char
*
buffer
;
int
append
(
uint
position
,
const
char
*
string
,
uint
len_arg
);
int
reserve
(
uint
position
,
uint
len_arg
);
};
#endif
/* INCLUDES_MYSQL_INSTANCE_MANAGER_BUFFER_H */
server-tools/instance-manager/client_func.c
0 → 100644
View file @
fd94614f
#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/command.cc
0 → 100644
View file @
fd94614f
/* 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 */
#ifdef __GNUC__
#pragma implementation
#endif
#include "command.h"
Command
::
Command
(
Instance_map
*
instance_map_arg
)
:
instance_map
(
instance_map_arg
)
{}
Command
::~
Command
()
{}
#ifdef __GNUC__
FIX_GCC_LINKING_PROBLEM
#endif
server-tools/instance-manager/command.h
0 → 100644
View file @
fd94614f
#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_COMMAND_H
#define INCLUDES_MYSQL_INSTANCE_MANAGER_COMMAND_H
/* 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 */
#ifdef __GNUC__
#pragma interface
#endif
#include <my_global.h>
/* Class responsible for allocation of im commands. */
class
Instance_map
;
/*
Command - entry point for any command.
GangOf4: 'Command' design pattern
*/
class
Command
{
public:
Command
(
Instance_map
*
instance_map_arg
=
0
);
virtual
~
Command
();
/* method of executing: */
virtual
int
execute
(
struct
st_net
*
net
,
ulong
connection_id
)
=
0
;
protected:
Instance_map
*
instance_map
;
};
#endif
/* INCLUDES_MYSQL_INSTANCE_MANAGER_COMMAND_H */
server-tools/instance-manager/commands.cc
0 → 100644
View file @
fd94614f
/* 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 "command.h"
#include "commands.h"
#include "instance.h"
#include "instance_map.h"
#include "messages.h"
#include "protocol.h"
#include "buffer.h"
#include <m_string.h>
/* implementation for Show_instances: */
/*
The method sends a list of instances in the instance map to the client.
SYNOPSYS
Show_instances::do_command()
net The network connection to the client.
RETURN
0 - ok
1 - error occured
*/
int
Show_instances
::
do_command
(
struct
st_net
*
net
)
{
Buffer
send_buff
;
/* buffer for packets */
LIST
name
,
status
;
NAME_WITH_LENGTH
name_field
,
status_field
;
LIST
*
field_list
;
uint
position
=
0
;
name_field
.
name
=
(
char
*
)
"instance_name"
;
name_field
.
length
=
20
;
name
.
data
=
&
name_field
;
status_field
.
name
=
(
char
*
)
"status"
;
status_field
.
length
=
20
;
status
.
data
=
&
status_field
;
field_list
=
list_add
(
NULL
,
&
status
);
field_list
=
list_add
(
field_list
,
&
name
);
send_fields
(
net
,
field_list
);
{
Instance
*
instance
;
Instance_map
::
Iterator
iterator
(
instance_map
);
instance_map
->
lock
();
while
(
instance
=
iterator
.
next
())
{
position
=
0
;
store_to_string
(
&
send_buff
,
instance
->
options
.
instance_name
,
&
position
);
if
(
instance
->
is_running
())
store_to_string
(
&
send_buff
,
(
char
*
)
"online"
,
&
position
);
else
store_to_string
(
&
send_buff
,
(
char
*
)
"offline"
,
&
position
);
if
(
my_net_write
(
net
,
send_buff
.
buffer
,
(
uint
)
position
))
goto
err
;
}
instance_map
->
unlock
();
}
if
(
send_eof
(
net
))
goto
err
;
if
(
net_flush
(
net
))
goto
err
;
return
0
;
err:
return
1
;
}
int
Show_instances
::
execute
(
struct
st_net
*
net
,
ulong
connection_id
)
{
if
(
do_command
(
net
))
return
ER_OUT_OF_RESOURCES
;
return
0
;
}
/* implementation for Flush_instances: */
int
Flush_instances
::
execute
(
struct
st_net
*
net
,
ulong
connection_id
)
{
if
(
instance_map
->
flush_instances
())
return
ER_OUT_OF_RESOURCES
;
net_send_ok
(
net
,
connection_id
);
return
0
;
}
/* implementation for Show_instance_status: */
Show_instance_status
::
Show_instance_status
(
Instance_map
*
instance_map_arg
,
const
char
*
name
,
uint
len
)
:
Command
(
instance_map_arg
)
{
Instance
*
instance
;
/* we make a search here, since we don't want t store the name */
if
(
instance
=
instance_map
->
find
(
name
,
len
))
{
instance_name
=
instance
->
options
.
instance_name
;
}
else
instance_name
=
NULL
;
}
/*
The method sends a table with a status of requested instance to the client.
SYNOPSYS
Show_instance_status::do_command()
net The network connection to the client.
instance_name The name of the instance.
RETURN
0 - ok
1 - error occured
*/
int
Show_instance_status
::
do_command
(
struct
st_net
*
net
,
const
char
*
instance_name
)
{
enum
{
MAX_VERSION_LENGTH
=
40
};
Buffer
send_buff
;
/* buffer for packets */
LIST
name
,
status
,
version
;
LIST
*
field_list
;
NAME_WITH_LENGTH
name_field
,
status_field
,
version_field
;
uint
position
=
0
;
/* create list of the fileds to be passed to send_fields */
name_field
.
name
=
(
char
*
)
"instance_name"
;
name_field
.
length
=
20
;
name
.
data
=
&
name_field
;
status_field
.
name
=
(
char
*
)
"status"
;
status_field
.
length
=
20
;
status
.
data
=
&
status_field
;
version_field
.
name
=
(
char
*
)
"version"
;
version_field
.
length
=
MAX_VERSION_LENGTH
;
version
.
data
=
&
version_field
;
field_list
=
list_add
(
NULL
,
&
version
);
field_list
=
list_add
(
field_list
,
&
status
);
field_list
=
list_add
(
field_list
,
&
name
);
send_fields
(
net
,
field_list
);
{
Instance
*
instance
;
store_to_string
(
&
send_buff
,
(
char
*
)
instance_name
,
&
position
);
if
((
instance
=
instance_map
->
find
(
instance_name
,
strlen
(
instance_name
)))
==
NULL
)
goto
err
;
if
(
instance
->
is_running
())
{
store_to_string
(
&
send_buff
,
(
char
*
)
"online"
,
&
position
);
store_to_string
(
&
send_buff
,
mysql_get_server_info
(
&
(
instance
->
mysql
)),
&
position
);
}
else
{
store_to_string
(
&
send_buff
,
(
char
*
)
"offline"
,
&
position
);
store_to_string
(
&
send_buff
,
(
char
*
)
"unknown"
,
&
position
);
}
if
(
my_net_write
(
net
,
send_buff
.
buffer
,
(
uint
)
position
))
goto
err
;
}
send_eof
(
net
);
net_flush
(
net
);
return
0
;
err:
return
1
;
}
int
Show_instance_status
::
execute
(
struct
st_net
*
net
,
ulong
connection_id
)
{
if
(
instance_name
!=
NULL
)
{
if
(
do_command
(
net
,
instance_name
))
return
ER_OUT_OF_RESOURCES
;
return
0
;
}
else
{
return
ER_BAD_INSTANCE_NAME
;
}
}
/* Implementation for Show_instance_options */
Show_instance_options
::
Show_instance_options
(
Instance_map
*
instance_map_arg
,
const
char
*
name
,
uint
len
)
:
Command
(
instance_map_arg
)
{
Instance
*
instance
;
/* we make a search here, since we don't want t store the name */
if
(
instance
=
instance_map
->
find
(
name
,
len
))
{
instance_name
=
instance
->
options
.
instance_name
;
}
else
instance_name
=
NULL
;
}
int
Show_instance_options
::
do_command
(
struct
st_net
*
net
,
const
char
*
instance_name
)
{
enum
{
MAX_VERSION_LENGTH
=
40
};
Buffer
send_buff
;
/* buffer for packets */
LIST
name
,
option
;
LIST
*
field_list
;
NAME_WITH_LENGTH
name_field
,
option_field
;
uint
position
=
0
;
/* create list of the fileds to be passed to send_fields */
name_field
.
name
=
(
char
*
)
"option_name"
;
name_field
.
length
=
20
;
name
.
data
=
&
name_field
;
option_field
.
name
=
(
char
*
)
"value"
;
option_field
.
length
=
20
;
option
.
data
=
&
option_field
;
field_list
=
list_add
(
NULL
,
&
option
);
field_list
=
list_add
(
field_list
,
&
name
);
send_fields
(
net
,
field_list
);
{
Instance
*
instance
;
if
((
instance
=
instance_map
->
find
(
instance_name
,
strlen
(
instance_name
)))
==
NULL
)
goto
err
;
store_to_string
(
&
send_buff
,
(
char
*
)
"instance_name"
,
&
position
);
store_to_string
(
&
send_buff
,
(
char
*
)
instance_name
,
&
position
);
if
(
my_net_write
(
net
,
send_buff
.
buffer
,
(
uint
)
position
))
goto
err
;
if
(
instance
->
options
.
mysqld_path
!=
NULL
)
{
position
=
0
;
store_to_string
(
&
send_buff
,
(
char
*
)
"mysqld_path"
,
&
position
);
store_to_string
(
&
send_buff
,
(
char
*
)
instance
->
options
.
mysqld_path
,
&
position
);
if
(
my_net_write
(
net
,
send_buff
.
buffer
,
(
uint
)
position
))
goto
err
;
}
if
(
instance
->
options
.
is_guarded
!=
NULL
)
{
position
=
0
;
store_to_string
(
&
send_buff
,
(
char
*
)
"guarded"
,
&
position
);
store_to_string
(
&
send_buff
,
""
,
&
position
);
if
(
my_net_write
(
net
,
send_buff
.
buffer
,
(
uint
)
position
))
goto
err
;
}
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
;
}
/* loop through the options stored in DYNAMIC_ARRAY */
for
(
int
i
=
0
;
i
<
instance
->
options
.
options_array
.
elements
;
i
++
)
{
char
*
tmp_option
,
*
option_value
;
get_dynamic
(
&
(
instance
->
options
.
options_array
),
(
gptr
)
&
tmp_option
,
i
);
option_value
=
strchr
(
tmp_option
,
'='
);
/* split the option string into two parts */
*
option_value
=
0
;
position
=
0
;
store_to_string
(
&
send_buff
,
tmp_option
+
2
,
&
position
);
store_to_string
(
&
send_buff
,
option_value
+
1
,
&
position
);
/* join name and the value into the same option again */
*
option_value
=
'='
;
if
(
my_net_write
(
net
,
send_buff
.
buffer
,
(
uint
)
position
))
goto
err
;
}
}
send_eof
(
net
);
net_flush
(
net
);
return
0
;
err:
return
1
;
}
int
Show_instance_options
::
execute
(
struct
st_net
*
net
,
ulong
connection_id
)
{
if
(
instance_name
!=
NULL
)
{
if
(
do_command
(
net
,
instance_name
))
return
ER_OUT_OF_RESOURCES
;
return
0
;
}
else
{
return
ER_BAD_INSTANCE_NAME
;
}
}
/* Implementation for Start_instance */
Start_instance
::
Start_instance
(
Instance_map
*
instance_map_arg
,
const
char
*
name
,
uint
len
)
:
Command
(
instance_map_arg
)
{
/* we make a search here, since we don't want t store the name */
if
(
instance
=
instance_map
->
find
(
name
,
len
))
instance_name
=
instance
->
options
.
instance_name
;
}
int
Start_instance
::
execute
(
struct
st_net
*
net
,
ulong
connection_id
)
{
uint
err_code
;
if
(
instance
==
0
)
{
return
ER_BAD_INSTANCE_NAME
;
/* haven't found an instance */
}
else
{
if
(
err_code
=
instance
->
start
())
return
err_code
;
if
(
instance
->
options
.
is_guarded
!=
NULL
)
instance_map
->
guardian
->
guard
(
instance
);
net_send_ok
(
net
,
connection_id
);
return
0
;
}
}
/* Implementation for Stop_instance: */
Stop_instance
::
Stop_instance
(
Instance_map
*
instance_map_arg
,
const
char
*
name
,
uint
len
)
:
Command
(
instance_map_arg
)
{
/* we make a search here, since we don't want t store the name */
if
(
instance
=
instance_map
->
find
(
name
,
len
))
instance_name
=
instance
->
options
.
instance_name
;
}
int
Stop_instance
::
execute
(
struct
st_net
*
net
,
ulong
connection_id
)
{
uint
err_code
;
if
(
instance
==
0
)
{
return
ER_BAD_INSTANCE_NAME
;
/* haven't found an instance */
}
else
{
if
(
instance
->
options
.
is_guarded
!=
NULL
)
instance_map
->
guardian
->
stop_guard
(
instance
);
if
(
err_code
=
instance
->
stop
())
return
err_code
;
printf
(
"instance was stopped
\n
"
);
net_send_ok
(
net
,
connection_id
);
return
0
;
}
}
int
Syntax_error
::
execute
(
struct
st_net
*
net
,
ulong
connection_id
)
{
return
ER_SYNTAX_ERROR
;
}
server-tools/instance-manager/commands.h
0 → 100644
View file @
fd94614f
#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_COMMANDS_H
#define INCLUDES_MYSQL_INSTANCE_MANAGER_COMMANDS_H
/* 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 "instance.h"
#include "my_global.h"
/*
Print all instances of this instance manager.
Grammar: SHOW ISTANCES
*/
class
Show_instances
:
public
Command
{
public:
Show_instances
(
Instance_map
*
instance_map_arg
)
:
Command
(
instance_map_arg
)
{}
int
do_command
(
struct
st_net
*
net
);
int
execute
(
struct
st_net
*
net
,
ulong
connection_id
);
};
/*
Reread configuration file and refresh instance map.
Grammar: FLUSH INSTANCES
*/
class
Flush_instances
:
public
Command
{
public:
Flush_instances
(
Instance_map
*
instance_map_arg
)
:
Command
(
instance_map_arg
)
{}
int
execute
(
struct
st_net
*
net
,
ulong
connection_id
);
};
/*
Print status of an instance.
Grammar: SHOW ISTANCE STATUS <instance_name>
*/
class
Show_instance_status
:
public
Command
{
public:
Show_instance_status
(
Instance_map
*
instance_map_arg
,
const
char
*
name
,
uint
len
);
int
do_command
(
struct
st_net
*
net
,
const
char
*
instance_name
);
int
execute
(
struct
st_net
*
net
,
ulong
connection_id
);
const
char
*
instance_name
;
};
/*
Print options if chosen instance.
Grammar: SHOW INSTANCE OPTIONS <instance_name>
*/
class
Show_instance_options
:
public
Command
{
public:
Show_instance_options
(
Instance_map
*
instance_map_arg
,
const
char
*
name
,
uint
len
);
int
execute
(
struct
st_net
*
net
,
ulong
connection_id
);
int
do_command
(
struct
st_net
*
net
,
const
char
*
instance_name
);
const
char
*
instance_name
;
};
/*
Start an instance.
Grammar: START INSTANCE <instance_name>
*/
class
Start_instance
:
public
Command
{
public:
Start_instance
(
Instance_map
*
instance_map_arg
,
const
char
*
name
,
uint
len
);
int
execute
(
struct
st_net
*
net
,
ulong
connection_id
);
const
char
*
instance_name
;
Instance
*
instance
;
};
/*
Stop an instance.
Grammar: STOP INSTANCE <instance_name>
*/
class
Stop_instance
:
public
Command
{
public:
Stop_instance
(
Instance_map
*
instance_map_arg
,
const
char
*
name
,
uint
len
);
Instance
*
instance
;
int
execute
(
struct
st_net
*
net
,
ulong
connection_id
);
const
char
*
instance_name
;
};
/*
Syntax error command. This command is issued if parser reported a syntax error.
We need it to distinguish the parse error and the situation when parser internal
error occured. E.g. parsing failed because we hadn't had enought memory. In the
latter case parse_command() should return an error.
*/
class
Syntax_error
:
public
Command
{
public:
int
execute
(
struct
st_net
*
net
,
ulong
connection_id
);
};
#endif
/* INCLUDES_MYSQL_INSTANCE_MANAGER_COMMANDS_H */
server-tools/instance-manager/factory.cc
0 → 100644
View file @
fd94614f
/* 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 "factory.h"
#include "my_global.h"
#include <stdio.h>
#include <ctype.h>
Show_instances
*
Command_factory
::
new_Show_instances
()
{
return
new
Show_instances
(
&
instance_map
);
}
Flush_instances
*
Command_factory
::
new_Flush_instances
()
{
return
new
Flush_instances
(
&
instance_map
);
}
Show_instance_status
*
Command_factory
::
new_Show_instance_status
(
const
char
*
name
,
uint
len
)
{
return
new
Show_instance_status
(
&
instance_map
,
name
,
len
);
}
Show_instance_options
*
Command_factory
::
new_Show_instance_options
(
const
char
*
name
,
uint
len
)
{
return
new
Show_instance_options
(
&
instance_map
,
name
,
len
);
}
Start_instance
*
Command_factory
::
new_Start_instance
(
const
char
*
name
,
uint
len
)
{
return
new
Start_instance
(
&
instance_map
,
name
,
len
);
}
Stop_instance
*
Command_factory
::
new_Stop_instance
(
const
char
*
name
,
uint
len
)
{
return
new
Stop_instance
(
&
instance_map
,
name
,
len
);
}
Syntax_error
*
Command_factory
::
new_Syntax_error
()
{
return
new
Syntax_error
();
}
server-tools/instance-manager/factory.h
0 → 100644
View file @
fd94614f
#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_FACTORY_H
#define INCLUDES_MYSQL_INSTANCE_MANAGER_FACTORY_H
/* 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 "command.h"
#include "commands.h"
#include "instance_map.h"
/*
This class could be used to handle various protocols. We could pass to
the parser various derived classes. I.e Mylsq_command_factory,
Http_command_factory e.t.c. Also see comment in the instance_map.cc
*/
class
Command_factory
{
public:
Command_factory
(
Instance_map
&
instance_map
)
:
instance_map
(
instance_map
)
{}
Show_instances
*
new_Show_instances
();
Show_instance_status
*
new_Show_instance_status
(
const
char
*
name
,
uint
len
);
Show_instance_options
*
new_Show_instance_options
(
const
char
*
name
,
uint
len
);
Start_instance
*
new_Start_instance
(
const
char
*
name
,
uint
len
);
Stop_instance
*
new_Stop_instance
(
const
char
*
name
,
uint
len
);
Flush_instances
*
new_Flush_instances
();
Syntax_error
*
new_Syntax_error
();
Instance_map
&
instance_map
;
};
#endif
/* INCLUDES_MYSQL_INSTANCE_MANAGER_FACTORY_H */
server-tools/instance-manager/guardian.cc
0 → 100644
View file @
fd94614f
/* 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 */
#ifdef __GNUC__
#pragma implementation
#endif
#include "guardian.h"
#include "instance_map.h"
#include "mysql_manager_error.h"
#include "log.h"
#include <string.h>
C_MODE_START
pthread_handler_decl
(
guardian
,
arg
)
{
Guardian_thread
*
guardian_thread
=
(
Guardian_thread
*
)
arg
;
guardian_thread
->
run
();
return
0
;
}
C_MODE_END
Guardian_thread
::
Guardian_thread
(
Thread_registry
&
thread_registry_arg
,
Instance_map
*
instance_map_arg
,
uint
monitoring_interval_arg
)
:
Guardian_thread_args
(
thread_registry_arg
,
instance_map_arg
,
monitoring_interval_arg
),
thread_info
(
pthread_self
())
{
pthread_mutex_init
(
&
LOCK_guardian
,
0
);
thread_registry
.
register_thread
(
&
thread_info
);
init_alloc_root
(
&
alloc
,
MEM_ROOT_BLOCK_SIZE
,
0
);
guarded_instances
=
NULL
;
starting_instances
=
NULL
;
}
Guardian_thread
::~
Guardian_thread
()
{
/* delay guardian destruction to the moment when no one needs it */
pthread_mutex_lock
(
&
LOCK_guardian
);
free_root
(
&
alloc
,
MYF
(
0
));
thread_registry
.
unregister_thread
(
&
thread_info
);
pthread_mutex_unlock
(
&
LOCK_guardian
);
pthread_mutex_destroy
(
&
LOCK_guardian
);
}
/*
Run guardian thread
SYNOPSYS
run()
DESCRIPTION
Check for all guarded instances and restart them if needed. If everything
is fine go and sleep for some time.
*/
void
Guardian_thread
::
run
()
{
Instance
*
instance
;
LIST
*
loop
;
my_thread_init
();
while
(
!
thread_registry
.
is_shutdown
())
{
pthread_mutex_lock
(
&
LOCK_guardian
);
loop
=
guarded_instances
;
while
(
loop
!=
NULL
)
{
instance
=
(
Instance
*
)
loop
->
data
;
/* instance-> start already checks whether instance is running */
if
(
instance
->
start
()
!=
ER_INSTANCE_ALREADY_STARTED
)
log_info
(
"guardian attempted to restart instance %s"
,
instance
->
options
.
instance_name
);
loop
=
loop
->
next
;
}
move_to_list
(
&
starting_instances
,
&
guarded_instances
);
pthread_mutex_unlock
(
&
LOCK_guardian
);
sleep
(
monitoring_interval
);
}
my_thread_end
();
}
int
Guardian_thread
::
start
()
{
Instance
*
instance
;
Instance_map
::
Iterator
iterator
(
instance_map
);
instance_map
->
lock
();
while
(
instance
=
iterator
.
next
())
{
if
((
instance
->
options
.
is_guarded
!=
NULL
)
&&
(
instance
->
is_running
()))
if
(
guard
(
instance
))
return
1
;
}
instance_map
->
unlock
();
return
0
;
}
/*
Start instance guarding
SYNOPSYS
guard()
instance the instance to be guarded
DESCRIPTION
The instance is added to the list of starting instances. Then after one guardian
loop it is moved to the guarded instances list. Usually guard() is called after we
start an instance, so we need to give some time to the instance to start.
RETURN
0 - ok
1 - error occured
*/
int
Guardian_thread
::
guard
(
Instance
*
instance
)
{
return
add_instance_to_list
(
instance
,
&
starting_instances
);
}
void
Guardian_thread
::
move_to_list
(
LIST
**
from
,
LIST
**
to
)
{
LIST
*
tmp
;
while
(
*
from
)
{
tmp
=
rest
(
*
from
);
*
to
=
list_add
(
*
to
,
*
from
);
*
from
=
tmp
;
}
}
int
Guardian_thread
::
add_instance_to_list
(
Instance
*
instance
,
LIST
**
list
)
{
LIST
*
node
;
node
=
(
LIST
*
)
alloc_root
(
&
alloc
,
sizeof
(
LIST
));
if
(
node
==
NULL
)
return
1
;
/* we store the pointers to instances from the instance_map's MEM_ROOT */
node
->
data
=
(
void
*
)
instance
;
pthread_mutex_lock
(
&
LOCK_guardian
);
*
list
=
list_add
(
*
list
,
node
);
pthread_mutex_unlock
(
&
LOCK_guardian
);
return
0
;
}
/*
TODO: perhaps it would make sense to create a pool of the LIST elements
elements and give them upon request. Now we are loosing a bit of memory when
guarded instance was stopped and then restarted (since we cannot free just
a piece of the MEM_ROOT).
*/
int
Guardian_thread
::
stop_guard
(
Instance
*
instance
)
{
LIST
*
node
;
pthread_mutex_lock
(
&
LOCK_guardian
);
node
=
guarded_instances
;
while
(
node
!=
NULL
)
{
/*
We compare only pointers, as we always use pointers from the
instance_map's MEM_ROOT.
*/
if
((
Instance
*
)
node
->
data
==
instance
)
{
guarded_instances
=
list_delete
(
guarded_instances
,
node
);
pthread_mutex_unlock
(
&
LOCK_guardian
);
return
0
;
}
else
node
=
node
->
next
;
}
pthread_mutex_unlock
(
&
LOCK_guardian
);
/* if there is nothing to delete it is also fine */
return
0
;
}
server-tools/instance-manager/guardian.h
0 → 100644
View file @
fd94614f
#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_GUARDIAN_H
#define INCLUDES_MYSQL_INSTANCE_MANAGER_GUARDIAN_H
/* 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 <my_global.h>
#include <my_sys.h>
#include <my_list.h>
#ifdef __GNUC__
#pragma interface
#endif
class
Instance_map
;
#include "thread_registry.h"
#include "instance.h"
C_MODE_START
pthread_handler_decl
(
guardian
,
arg
);
C_MODE_END
struct
Guardian_thread_args
{
Thread_registry
&
thread_registry
;
Instance_map
*
instance_map
;
uint
monitoring_interval
;
Guardian_thread_args
(
Thread_registry
&
thread_registry_arg
,
Instance_map
*
instance_map_arg
,
uint
monitoring_interval_arg
)
:
thread_registry
(
thread_registry_arg
),
instance_map
(
instance_map_arg
),
monitoring_interval
(
monitoring_interval_arg
)
{}
};
/*
The guardian thread is responsible for monitoring and restarting of guarded
instances.
*/
class
Guardian_thread
:
public
Guardian_thread_args
{
public:
Guardian_thread
(
Thread_registry
&
thread_registry_arg
,
Instance_map
*
instance_map_arg
,
uint
monitoring_interval_arg
);
~
Guardian_thread
();
void
run
();
int
init
();
int
start
();
int
guard
(
Instance
*
instance
);
int
stop_guard
(
Instance
*
instance
);
private:
int
add_instance_to_list
(
Instance
*
instance
,
LIST
**
list
);
void
move_to_list
(
LIST
**
from
,
LIST
**
to
);
private:
pthread_mutex_t
LOCK_guardian
;
Thread_info
thread_info
;
LIST
*
guarded_instances
;
LIST
*
starting_instances
;
MEM_ROOT
alloc
;
enum
{
MEM_ROOT_BLOCK_SIZE
=
512
};
};
#endif
/* INCLUDES_MYSQL_INSTANCE_MANAGER_GUARDIAN_H */
server-tools/instance-manager/instance.cc
0 → 100644
View file @
fd94614f
/* 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 */
#ifdef __GNUC__
#pragma implementation
#endif
#include "instance.h"
#include "mysql_manager_error.h"
#include "log.h"
#include <my_sys.h>
#include <signal.h>
#include <m_string.h>
#include <sys/wait.h>
/*
The method starts an instance.
SYNOPSYS
start()
RETURN
0 ok
ER_CANNOT_START_INSTANCE Cannot start instance
ER_INSTANCE_ALREADY_STARTED The instance on the specified port/socket
is already started
*/
int
Instance
::
start
()
{
pid_t
pid
;
if
(
!
is_running
())
{
log_info
(
"trying to start instance %s"
,
options
.
instance_name
);
switch
(
pid
=
fork
())
{
case
0
:
if
(
fork
())
/* zombie protection */
exit
(
0
);
/* parent goes bye-bye */
else
{
execv
(
options
.
mysqld_path
,
options
.
argv
);
exit
(
1
);
}
case
-
1
:
return
ER_CANNOT_START_INSTANCE
;
default:
waitpid
(
pid
,
NULL
,
0
);
return
0
;
}
}
/* the instance is started already */
return
ER_INSTANCE_ALREADY_STARTED
;
}
int
Instance
::
cleanup
()
{
/*
We cannot close connection in destructor, as mysql_close needs alarm
services which are definitely unavailaible at the time of destructor
call.
*/
if
(
is_connected
)
mysql_close
(
&
mysql
);
return
0
;
}
Instance
::~
Instance
()
{
pthread_mutex_destroy
(
&
LOCK_instance
);
}
bool
Instance
::
is_running
()
{
uint
port
;
const
char
*
socket
;
if
(
options
.
mysqld_port
)
port
=
atoi
(
strchr
(
options
.
mysqld_port
,
'='
)
+
1
);
if
(
options
.
mysqld_socket
)
socket
=
strchr
(
options
.
mysqld_socket
,
'='
)
+
1
;
pthread_mutex_lock
(
&
LOCK_instance
);
if
(
!
is_connected
)
{
mysql_init
(
&
mysql
);
if
(
mysql_real_connect
(
&
mysql
,
LOCAL_HOST
,
options
.
mysqld_user
,
options
.
mysqld_password
,
NullS
,
port
,
socket
,
0
))
{
is_connected
=
TRUE
;
pthread_mutex_unlock
(
&
LOCK_instance
);
return
TRUE
;
}
mysql_close
(
&
mysql
);
pthread_mutex_unlock
(
&
LOCK_instance
);
return
FALSE
;
}
else
if
(
!
mysql_ping
(
&
mysql
))
{
pthread_mutex_unlock
(
&
LOCK_instance
);
return
TRUE
;
}
pthread_mutex_unlock
(
&
LOCK_instance
);
return
FALSE
;
}
/*
Stop an instance.
SYNOPSYS
stop()
RETURN:
0 ok
ER_INSTANCE_IS_NOT_STARTED Looks like the instance it is not started
ER_STOP_INSTANCE mysql_shutdown reported an error
*/
int
Instance
::
stop
()
{
if
(
is_running
())
{
if
(
mysql_shutdown
(
&
mysql
,
SHUTDOWN_DEFAULT
))
goto
err
;
mysql_close
(
&
mysql
);
is_connected
=
FALSE
;
return
0
;
}
return
ER_INSTANCE_IS_NOT_STARTED
;
err:
return
ER_STOP_INSTANCE
;
}
/*
We execute this function to initialize instance parameters.
Return value: 0 - ok. 1 - unable to init DYNAMIC_ARRAY.
*/
int
Instance
::
init
(
const
char
*
name_arg
)
{
pthread_mutex_init
(
&
LOCK_instance
,
0
);
return
options
.
init
(
name_arg
);
}
server-tools/instance-manager/instance.h
0 → 100644
View file @
fd94614f
#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_INSTANCE_H
#define INCLUDES_MYSQL_INSTANCE_MANAGER_INSTANCE_H
/* 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 <my_global.h>
#include <my_sys.h>
#include <mysql.h>
#include "instance_options.h"
#ifdef __GNUC__
#pragma interface
#endif
class
Instance
{
public:
Instance
()
:
is_connected
(
FALSE
)
{}
~
Instance
();
int
init
(
const
char
*
name
);
/* check if the instance is running and set up mysql connection if yes */
bool
is_running
();
int
start
();
int
stop
();
int
cleanup
();
public:
Instance_options
options
;
/* connection to the instance */
MYSQL
mysql
;
private:
/*
Mutex protecting the instance. Currently we use it to avoid the
double start of the instance. This happens when the instance is starting
and we issue the start command once more.
*/
pthread_mutex_t
LOCK_instance
;
/* Here we store the state of the following connection */
bool
is_connected
;
};
#endif
/* INCLUDES_MYSQL_INSTANCE_MANAGER_INSTANCE_H */
server-tools/instance-manager/instance_map.cc
0 → 100644
View file @
fd94614f
/* 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 */
#ifdef __GNUC__
#pragma implementation
#endif
#include "instance_map.h"
#include "buffer.h"
#include "instance.h"
#include <m_ctype.h>
#include <my_sys.h>
#include <mysql_com.h>
#include <m_string.h>
/*
Note: As we are going to suppost different types of connections,
we shouldn't have connection-specific functions. To avoid it we could
put such functions to the Command-derived class instead.
The command could be easily constructed for a specific connection if
we would provide a special factory for each connection.
*/
C_MODE_START
/* Procedure needed for HASH initialization */
static
byte
*
get_instance_key
(
const
byte
*
u
,
uint
*
len
,
my_bool
__attribute__
((
unused
))
t
)
{
const
Instance
*
instance
=
(
const
Instance
*
)
u
;
*
len
=
instance
->
options
.
instance_name_len
;
return
(
byte
*
)
instance
->
options
.
instance_name
;
}
static
void
delete_instance
(
void
*
u
)
{
Instance
*
instance
=
(
Instance
*
)
u
;
delete
instance
;
}
/*
The option handler to pass to the process_default_option_files finction.
SYNOPSYS
process_option()
ctx Handler context. Here it is an instance_map structure.
group_name The name of the group the option belongs to.
option The very option to be processed. It is already
prepared to be used in argv (has -- prefix)
DESCRIPTION
This handler checks whether a group is an instance group and adds
an option to the appropriate instance class. If this is the first
occurence of an instance name, we'll also create the instance
with such name and add it to the instance map.
RETURN
0 - ok
1 - error occured
*/
static
int
process_option
(
void
*
ctx
,
const
char
*
group
,
const
char
*
option
)
{
Instance_map
*
map
=
NULL
;
Instance
*
instance
=
NULL
;
static
const
char
prefix
[]
=
{
'm'
,
'y'
,
's'
,
'q'
,
'l'
,
'd'
};
map
=
(
Instance_map
*
)
ctx
;
if
(
strncmp
(
group
,
prefix
,
sizeof
prefix
)
==
0
&&
(
my_isdigit
(
default_charset_info
,
group
[
sizeof
prefix
])))
{
if
((
instance
=
map
->
find
(
group
,
strlen
(
group
)))
==
NULL
)
{
if
((
instance
=
new
Instance
)
==
0
)
goto
err_new_instance
;
if
(
instance
->
init
(
group
))
goto
err
;
if
(
map
->
add_instance
(
instance
))
goto
err
;
}
if
(
instance
->
options
.
add_option
(
option
))
goto
err
;
}
return
0
;
err:
delete
instance
;
err_new_instance:
return
1
;
}
C_MODE_END
Instance_map
::
Instance_map
(
const
char
*
default_mysqld_path_arg
,
const
char
*
default_admin_user_arg
,
const
char
*
default_admin_password_arg
)
{
mysqld_path
=
default_mysqld_path_arg
;
user
=
default_admin_user_arg
;
password
=
default_admin_password_arg
;
pthread_mutex_init
(
&
LOCK_instance_map
,
0
);
}
int
Instance_map
::
init
()
{
if
(
hash_init
(
&
hash
,
default_charset_info
,
START_HASH_SIZE
,
0
,
0
,
get_instance_key
,
delete_instance
,
0
))
return
1
;
return
0
;
}
Instance_map
::~
Instance_map
()
{
pthread_mutex_lock
(
&
LOCK_instance_map
);
hash_free
(
&
hash
);
pthread_mutex_unlock
(
&
LOCK_instance_map
);
pthread_mutex_destroy
(
&
LOCK_instance_map
);
}
int
Instance_map
::
lock
()
{
return
pthread_mutex_lock
(
&
LOCK_instance_map
);
}
int
Instance_map
::
unlock
()
{
return
pthread_mutex_unlock
(
&
LOCK_instance_map
);
}
int
Instance_map
::
flush_instances
()
{
int
rc
;
pthread_mutex_lock
(
&
LOCK_instance_map
);
hash_free
(
&
hash
);
hash_init
(
&
hash
,
default_charset_info
,
START_HASH_SIZE
,
0
,
0
,
get_instance_key
,
delete_instance
,
0
);
pthread_mutex_unlock
(
&
LOCK_instance_map
);
rc
=
load
();
return
rc
;
}
int
Instance_map
::
add_instance
(
Instance
*
instance
)
{
return
my_hash_insert
(
&
hash
,
(
byte
*
)
instance
);
}
Instance
*
Instance_map
::
find
(
const
char
*
name
,
uint
name_len
)
{
Instance
*
instance
;
pthread_mutex_lock
(
&
LOCK_instance_map
);
instance
=
(
Instance
*
)
hash_search
(
&
hash
,
(
byte
*
)
name
,
name_len
);
pthread_mutex_unlock
(
&
LOCK_instance_map
);
return
instance
;
}
void
Instance_map
::
complete_initialization
()
{
Instance
*
instance
;
uint
i
=
0
;
while
(
i
<
hash
.
records
)
{
instance
=
(
Instance
*
)
hash_element
(
&
hash
,
i
);
instance
->
options
.
complete_initialization
(
mysqld_path
,
user
,
password
);
i
++
;
}
}
int
Instance_map
::
cleanup
()
{
Instance
*
instance
;
uint
i
=
0
;
while
(
i
<
hash
.
records
)
{
instance
=
(
Instance
*
)
hash_element
(
&
hash
,
i
);
instance
->
cleanup
();
i
++
;
}
}
Instance
*
Instance_map
::
find
(
uint
instance_number
)
{
Instance
*
instance
;
char
name
[
80
];
sprintf
(
name
,
"mysqld%i"
,
instance_number
);
pthread_mutex_lock
(
&
LOCK_instance_map
);
instance
=
(
Instance
*
)
hash_search
(
&
hash
,
(
byte
*
)
name
,
strlen
(
name
));
pthread_mutex_unlock
(
&
LOCK_instance_map
);
return
instance
;
}
/* load options from config files and create appropriate instance structures */
int
Instance_map
::
load
()
{
int
error
;
error
=
process_default_option_files
(
"my"
,
process_option
,
(
void
*
)
this
);
complete_initialization
();
return
error
;
}
/*--- Implementaton of the Instance map iterator class ---*/
void
Instance_map
::
Iterator
::
go_to_first
()
{
current_instance
=
0
;
}
Instance
*
Instance_map
::
Iterator
::
next
()
{
if
(
current_instance
<
instance_map
->
hash
.
records
)
return
(
Instance
*
)
hash_element
(
&
instance_map
->
hash
,
current_instance
++
);
else
return
NULL
;
}
server-tools/instance-manager/instance_map.h
0 → 100644
View file @
fd94614f
#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_INSTANCE_MAP_H
#define INCLUDES_MYSQL_INSTANCE_MANAGER_INSTANCE_MAP_H
/* 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 <my_global.h>
#include <my_sys.h>
#include <hash.h>
#ifdef __GNUC__
#pragma interface
#endif
#include "protocol.h"
#include "guardian.h"
class
Instance
;
extern
int
load_all_groups
(
char
***
groups
,
const
char
*
filename
);
extern
void
free_groups
(
char
**
groups
);
/*
Instance_map - stores all existing instances
*/
class
Instance_map
{
friend
class
Iterator
;
public:
/* Instance_map iterator */
class
Iterator
{
private:
uint
current_instance
;
Instance_map
*
instance_map
;
public:
Iterator
(
Instance_map
*
instance_map_arg
)
:
current_instance
(
0
),
instance_map
(
instance_map_arg
)
{}
void
go_to_first
();
Instance
*
next
();
};
public:
/* returns a pointer to the instance or NULL, if there is no such instance */
Instance
*
find
(
const
char
*
name
,
uint
name_len
);
Instance
*
find
(
uint
instance_number
);
int
flush_instances
();
int
cleanup
();
int
lock
();
int
unlock
();
int
init
();
Instance_map
(
const
char
*
default_mysqld_path_arg
,
const
char
*
default_admin_user_arg
,
const
char
*
default_admin_password_arg
);
~
Instance_map
();
/* loads options from config files */
int
load
();
/* adds instance to internal hash */
int
add_instance
(
Instance
*
instance
);
/* inits instances argv's after all options have been loaded */
void
complete_initialization
();
public:
const
char
*
mysqld_path
;
/* user an password to shutdown MySQL */
const
char
*
user
;
const
char
*
password
;
Guardian_thread
*
guardian
;
private:
enum
{
START_HASH_SIZE
=
16
};
pthread_mutex_t
LOCK_instance_map
;
HASH
hash
;
};
#endif
/* INCLUDES_MYSQL_INSTANCE_MANAGER_INSTANCE_MAP_H */
server-tools/instance-manager/instance_options.cc
0 → 100644
View file @
fd94614f
/* 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 */
#ifdef __GNUC__
#pragma implementation
#endif
#include "instance_options.h"
#include <my_sys.h>
#include <mysql.h>
#include <signal.h>
#include <m_string.h>
int
Instance_options
::
complete_initialization
(
const
char
*
default_path
,
const
char
*
default_user
,
const
char
*
default_password
)
{
/* 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
;
if
(
mysqld_path
==
NULL
)
{
if
(
!
(
mysqld_path
=
strdup_root
(
&
alloc
,
default_path
)))
goto
err
;
}
/* this option must be first in the argv */
if
(
add_to_argv
(
mysqld_path
))
goto
err
;
/* the following options are not for argv */
if
(
mysqld_user
==
NULL
)
{
if
(
!
(
mysqld_user
=
strdup_root
(
&
alloc
,
default_user
)))
goto
err
;
}
if
(
mysqld_password
==
NULL
)
{
if
(
!
(
mysqld_password
=
strdup_root
(
&
alloc
,
default_password
)))
goto
err
;
}
memcpy
((
gptr
)
(
argv
+
filled_default_options
),
options_array
.
buffer
,
options_array
.
elements
*
sizeof
(
char
*
));
argv
[
filled_default_options
+
options_array
.
elements
]
=
0
;
return
0
;
err:
return
1
;
}
/*
Assigns given value to the appropriate option from the class.
SYNOPSYS
add_option()
option string with the option prefixed by --
DESCRIPTION
The method is called from the option handling routine.
RETURN
0 - ok
1 - error occured
*/
int
Instance_options
::
add_option
(
const
char
*
option
)
{
char
*
tmp
;
enum
{
SAVE_VALUE
=
1
,
SAVE_WHOLE
,
SAVE_WHOLE_AND_ADD
};
struct
selected_options_st
{
const
char
*
name
;
uint
length
;
const
char
**
value
;
uint
type
;
}
options
[]
=
{
{
"--socket="
,
9
,
&
mysqld_socket
,
SAVE_WHOLE_AND_ADD
},
{
"--port="
,
7
,
&
mysqld_port
,
SAVE_WHOLE_AND_ADD
},
{
"--datadir="
,
10
,
&
mysqld_datadir
,
SAVE_WHOLE_AND_ADD
},
{
"--bind-address="
,
15
,
&
mysqld_bind_address
,
SAVE_WHOLE_AND_ADD
},
{
"--pid-file="
,
11
,
&
mysqld_pid_file
,
SAVE_WHOLE_AND_ADD
},
{
"--mysqld_path="
,
14
,
&
mysqld_path
,
SAVE_VALUE
},
{
"--admin_user="
,
13
,
&
mysqld_user
,
SAVE_VALUE
},
{
"--admin_password="
,
17
,
&
mysqld_password
,
SAVE_VALUE
},
{
"--guarded"
,
9
,
&
is_guarded
,
SAVE_WHOLE
},
{
NULL
,
0
,
NULL
,
0
}
};
struct
selected_options_st
*
selected_options
;
if
(
!
(
tmp
=
strdup_root
(
&
alloc
,
option
)))
goto
err
;
for
(
selected_options
=
options
;
selected_options
->
name
;
selected_options
++
)
{
if
(
!
strncmp
(
tmp
,
selected_options
->
name
,
selected_options
->
length
))
switch
(
selected_options
->
type
){
case
SAVE_WHOLE_AND_ADD
:
*
(
selected_options
->
value
)
=
tmp
;
insert_dynamic
(
&
options_array
,(
gptr
)
&
tmp
);
return
0
;
case
SAVE_VALUE
:
*
(
selected_options
->
value
)
=
strchr
(
tmp
,
'='
)
+
1
;
return
0
;
case
SAVE_WHOLE
:
*
(
selected_options
->
value
)
=
tmp
;
return
0
;
defaut:
break
;
}
}
return
0
;
err:
return
1
;
}
int
Instance_options
::
add_to_argv
(
const
char
*
option
)
{
DBUG_ASSERT
(
filled_default_options
<
MAX_NUMBER_OF_DEFAULT_OPTIONS
);
if
(
option
!=
NULL
)
argv
[
filled_default_options
++
]
=
(
char
*
)
option
;
return
0
;
}
/*
We execute this function to initialize some options.
Return value: 0 - ok. 1 - unable to allocate memory.
*/
int
Instance_options
::
init
(
const
char
*
instance_name_arg
)
{
instance_name_len
=
strlen
(
instance_name_arg
);
init_alloc_root
(
&
alloc
,
MEM_ROOT_BLOCK_SIZE
,
0
);
if
(
my_init_dynamic_array
(
&
options_array
,
sizeof
(
char
*
),
0
,
32
))
goto
err
;
if
(
!
(
instance_name
=
strmake_root
(
&
alloc
,
(
char
*
)
instance_name_arg
,
instance_name_len
)))
goto
err
;
return
0
;
err:
return
1
;
}
Instance_options
::~
Instance_options
()
{
free_root
(
&
alloc
,
MYF
(
0
));
delete_dynamic
(
&
options_array
);
}
server-tools/instance-manager/instance_options.h
0 → 100644
View file @
fd94614f
#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_INSTANCE_OPTIONS_H
#define INCLUDES_MYSQL_INSTANCE_MANAGER_INSTANCE_OPTIONS_H
/* 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 <my_global.h>
#include <my_sys.h>
#ifdef __GNUC__
#pragma interface
#endif
/*
This class contains options of an instance and methods to operate them.
We do not provide this class with the means of synchronization as it is
supposed that options for instances are all loaded at once during the
instance_map initilization and we do not change them later. This way we
don't have to synchronize between threads.
*/
class
Instance_options
{
public:
Instance_options
()
:
mysqld_socket
(
0
),
mysqld_datadir
(
0
),
mysqld_bind_address
(
0
),
mysqld_pid_file
(
0
),
mysqld_port
(
0
),
mysqld_path
(
0
),
mysqld_user
(
0
),
mysqld_password
(
0
),
is_guarded
(
0
),
filled_default_options
(
0
)
{}
~
Instance_options
();
/* fills in argv */
int
complete_initialization
(
const
char
*
default_path
,
const
char
*
default_user
,
const
char
*
default_password
);
int
add_option
(
const
char
*
option
);
int
init
(
const
char
*
instance_name_arg
);
public:
enum
{
MAX_NUMBER_OF_DEFAULT_OPTIONS
=
1
};
enum
{
MEM_ROOT_BLOCK_SIZE
=
512
};
char
**
argv
;
/* We need the some options, so we store them as a separate pointers */
const
char
*
mysqld_socket
;
const
char
*
mysqld_datadir
;
const
char
*
mysqld_bind_address
;
const
char
*
mysqld_pid_file
;
const
char
*
mysqld_port
;
uint
instance_name_len
;
const
char
*
instance_name
;
const
char
*
mysqld_path
;
const
char
*
mysqld_user
;
const
char
*
mysqld_password
;
const
char
*
is_guarded
;
DYNAMIC_ARRAY
options_array
;
private:
int
add_to_argv
(
const
char
*
option
);
private:
uint
filled_default_options
;
MEM_ROOT
alloc
;
};
#endif
/* INCLUDES_MYSQL_INSTANCE_MANAGER_INSTANCE_OPTIONS_H */
server-tools/instance-manager/listener.cc
View file @
fd94614f
/* Copyright (C) 2003 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 "listener.h"
#include "thread_repository.h"
#include <m_string.h>
#include <mysql.h>
#include <violite.h>
#include <sys/un.h>
#include <sys/stat.h>
#include "thread_registry.h"
#include "options.h"
#include "instance_map.h"
#include "log.h"
#include "mysql_connection.h"
C_MODE_START
pthread_handler_decl
(
listener
,
arg
)
/*
Listener_thread - incapsulates listening functionality
*/
class
Listener_thread
:
public
Listener_thread_args
{
public:
Listener_thread
(
const
Listener_thread_args
&
args
);
~
Listener_thread
();
void
run
();
private:
ulong
total_connection_count
;
Thread_info
thread_info
;
private:
void
handle_new_mysql_connection
(
Vio
*
vio
);
};
Listener_thread
::
Listener_thread
(
const
Listener_thread_args
&
args
)
:
Listener_thread_args
(
args
.
thread_registry
,
args
.
options
,
args
.
user_map
,
args
.
instance_map
)
,
total_connection_count
(
0
)
,
thread_info
(
pthread_self
())
{
thread_registry
.
register_thread
(
&
thread_info
);
}
Listener_thread
::~
Listener_thread
()
{
thread_registry
.
unregister_thread
(
&
thread_info
);
}
/*
Listener_thread::run() - listen all supported sockets and spawn a thread
to handle incoming connection.
Using 'die' in case of syscall failure is OK now - we don't hold any
resources and 'die' kills the signal thread automatically. To be rewritten
one day.
See also comments in mysqlmanager.cc to picture general Instance Manager
architecture.
*/
void
Listener_thread
::
run
()
{
Thread_info
info
(
pthread_self
());
Thread_repository
&
thread_repository
=
((
Listener_thread_args
*
)
arg
)
->
thread_repository
;
thread_repository
.
register_thread
(
&
info
);
enum
{
LISTEN_BACK_LOG_SIZE
=
5
};
// standard backlog size
int
flags
;
int
arg
=
1
;
/* value to be set by setsockopt */
/* I. prepare 'listen' sockets */
while
(
true
)
int
ip_socket
=
socket
(
AF_INET
,
SOCK_STREAM
,
0
);
if
(
ip_socket
==
INVALID_SOCKET
)
{
log_
info
(
"listener is alive"
);
sleep
(
2
);
if
(
thread_repository
.
is_shutdown
())
break
;
log_
error
(
"Listener_thead::run(): socket(AF_INET) failed, %s"
,
strerror
(
errno
)
);
thread_registry
.
request_shutdown
();
return
;
}
log_info
(
"listener(): shutdown requested, exiting..."
);
thread_repository
.
unregister_thread
(
&
info
);
return
0
;
struct
sockaddr_in
ip_socket_address
;
bzero
(
&
ip_socket_address
,
sizeof
(
ip_socket_address
));
ulong
im_bind_addr
;
if
(
options
.
bind_address
!=
0
)
{
if
((
im_bind_addr
=
(
ulong
)
inet_addr
(
options
.
bind_address
))
==
INADDR_NONE
)
im_bind_addr
=
htonl
(
INADDR_ANY
);
}
else
im_bind_addr
=
htonl
(
INADDR_ANY
);
uint
im_port
=
options
.
port_number
;
ip_socket_address
.
sin_family
=
AF_INET
;
ip_socket_address
.
sin_addr
.
s_addr
=
im_bind_addr
;
ip_socket_address
.
sin_port
=
(
unsigned
short
)
htons
((
unsigned
short
)
im_port
);
setsockopt
(
ip_socket
,
SOL_SOCKET
,
SO_REUSEADDR
,
(
char
*
)
&
arg
,
sizeof
(
arg
));
if
(
bind
(
ip_socket
,
(
struct
sockaddr
*
)
&
ip_socket_address
,
sizeof
(
ip_socket_address
)))
{
log_error
(
"Listener_thread::run(): bind(ip socket) failed, '%s'"
,
strerror
(
errno
));
thread_registry
.
request_shutdown
();
return
;
}
if
(
listen
(
ip_socket
,
LISTEN_BACK_LOG_SIZE
))
{
log_error
(
"Listener_thread::run(): listen(ip socket) failed, %s"
,
strerror
(
errno
));
thread_registry
.
request_shutdown
();
return
;
}
/* set the socket nonblocking */
flags
=
fcntl
(
ip_socket
,
F_GETFL
,
0
);
fcntl
(
ip_socket
,
F_SETFL
,
flags
|
O_NONBLOCK
);
/* make sure that instances won't be listening our sockets */
flags
=
fcntl
(
ip_socket
,
F_GETFD
,
0
);
fcntl
(
ip_socket
,
F_SETFD
,
flags
|
FD_CLOEXEC
);
log_info
(
"accepting connections on ip socket"
);
/*--------------------------------------------------------------*/
int
unix_socket
=
socket
(
AF_UNIX
,
SOCK_STREAM
,
0
);
if
(
unix_socket
==
INVALID_SOCKET
)
{
log_error
(
"Listener_thead::run(): socket(AF_UNIX) failed, %s"
,
strerror
(
errno
));
thread_registry
.
request_shutdown
();
return
;
}
struct
sockaddr_un
unix_socket_address
;
bzero
(
&
unix_socket_address
,
sizeof
(
unix_socket_address
));
unix_socket_address
.
sun_family
=
AF_UNIX
;
strmake
(
unix_socket_address
.
sun_path
,
options
.
socket_file_name
,
sizeof
(
unix_socket_address
.
sun_path
));
unlink
(
unix_socket_address
.
sun_path
);
// in case we have stale socket file
{
/*
POSIX specifies default permissions for a pathname created by bind
to be 0777. We need everybody to have access to the socket.
*/
mode_t
old_mask
=
umask
(
0
);
if
(
bind
(
unix_socket
,
(
struct
sockaddr
*
)
&
unix_socket_address
,
sizeof
(
unix_socket_address
)))
{
log_error
(
"Listener_thread::run(): bind(unix socket) failed, "
"socket file name is '%s', error '%s'"
,
unix_socket_address
.
sun_path
,
strerror
(
errno
));
thread_registry
.
request_shutdown
();
return
;
}
umask
(
old_mask
);
if
(
listen
(
unix_socket
,
LISTEN_BACK_LOG_SIZE
))
{
log_error
(
"Listener_thread::run(): listen(unix socket) failed, %s"
,
strerror
(
errno
));
thread_registry
.
request_shutdown
();
return
;
}
/* set the socket nonblocking */
flags
=
fcntl
(
unix_socket
,
F_GETFL
,
0
);
fcntl
(
unix_socket
,
F_SETFL
,
flags
|
O_NONBLOCK
);
/* make sure that instances won't be listening our sockets */
flags
=
fcntl
(
unix_socket
,
F_GETFD
,
0
);
fcntl
(
unix_socket
,
F_SETFD
,
flags
|
FD_CLOEXEC
);
}
log_info
(
"accepting connections on unix socket %s"
,
unix_socket_address
.
sun_path
);
/* II. Listen sockets and spawn childs */
{
int
n
=
max
(
unix_socket
,
ip_socket
)
+
1
;
fd_set
read_fds
;
FD_ZERO
(
&
read_fds
);
FD_SET
(
unix_socket
,
&
read_fds
);
FD_SET
(
ip_socket
,
&
read_fds
);
while
(
thread_registry
.
is_shutdown
()
==
false
)
{
fd_set
read_fds_arg
=
read_fds
;
int
rc
=
select
(
n
,
&
read_fds_arg
,
0
,
0
,
0
);
if
(
rc
==
-
1
&&
errno
!=
EINTR
)
log_error
(
"Listener_thread::run(): select() failed, %s"
,
strerror
(
errno
));
else
{
/* Assuming that rc > 0 as we asked to wait forever */
if
(
FD_ISSET
(
unix_socket
,
&
read_fds_arg
))
{
int
client_fd
=
accept
(
unix_socket
,
0
,
0
);
/* accept may return -1 (failure or spurious wakeup) */
if
(
client_fd
>=
0
)
// connection established
{
if
(
Vio
*
vio
=
vio_new
(
client_fd
,
VIO_TYPE_SOCKET
,
1
))
handle_new_mysql_connection
(
vio
);
else
{
shutdown
(
client_fd
,
SHUT_RDWR
);
close
(
client_fd
);
}
}
}
else
if
(
FD_ISSET
(
ip_socket
,
&
read_fds_arg
))
{
int
client_fd
=
accept
(
ip_socket
,
0
,
0
);
/* accept may return -1 (failure or spurious wakeup) */
if
(
client_fd
>=
0
)
// connection established
{
if
(
Vio
*
vio
=
vio_new
(
client_fd
,
VIO_TYPE_TCPIP
,
0
))
{
handle_new_mysql_connection
(
vio
);
}
else
{
shutdown
(
client_fd
,
SHUT_RDWR
);
close
(
client_fd
);
}
}
}
}
}
}
/* III. Release all resources and exit */
log_info
(
"Listener_thread::run(): shutdown requested, exiting..."
);
close
(
unix_socket
);
close
(
ip_socket
);
unlink
(
unix_socket_address
.
sun_path
);
}
C_MODE_END
#if 0
while (true)
/*
Create new mysql connection. Created thread is responsible for deletion of
the Mysql_connection_thread_args and Vio instances passed to it.
SYNOPSYS
handle_new_mysql_connection()
*/
void
Listener_thread
::
handle_new_mysql_connection
(
Vio
*
vio
)
{
if
(
Mysql_connection_thread_args
*
mysql_thread_args
=
new
Mysql_connection_thread_args
(
vio
,
thread_registry
,
user_map
,
++
total_connection_count
,
instance_map
)
)
{
/*
Initialize thread attributes to create detached thread; it seems
easier to do it ad-hoc than have a global variable for attributes.
*/
pthread_t
mysql_thd_id
;
pthread_attr_t
mysql_thd_attr
;
pthread_attr_init
(
&
mysql_thd_attr
);
pthread_attr_setdetachstate
(
&
mysql_thd_attr
,
PTHREAD_CREATE_DETACHED
);
if
(
pthread_create
(
&
mysql_thd_id
,
&
mysql_thd_attr
,
mysql_connection
,
mysql_thread_args
))
{
delete
mysql_thread_args
;
vio_delete
(
vio
);
log_error
(
"handle_one_mysql_connection(): pthread_create(mysql) failed"
);
}
pthread_attr_destroy
(
&
mysql_thd_attr
);
}
else
vio_delete
(
vio
);
}
C_MODE_START
pthread_handler_decl
(
listener
,
arg
)
{
Listener_thread_args
*
args
=
(
Listener_thread_args
*
)
arg
;
Listener_thread
listener
(
*
args
);
listener
.
run
();
/*
Dummy manager implementation: listens on a UNIX socket and
starts echo server in a dedicated thread for each accepted connection.
Enough to test startup/shutdown/options/logging of the instance manager.
args is a stack variable because listener thread lives as long as the
manager process itself
*/
return
0
;
}
C_MODE_END
int fd= socket(AF_UNIX, SOCK_STREAM, 0);
if (!fd)
die("socket(): failed");
struct sockaddr_un address;
bzero(&address, sizeof(address));
address.sun_family= AF_UNIX;
strcpy(address.sun_path, socket_path);
int opt= 1;
if (unlink(socket_path) ||
bind(fd, (struct sockaddr *) &address, sizeof(address)) ||
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)))
die("unlink | bind | setsockopt failed");
if (listen(fd, 5))
die("listen() failed");
int client_fd;
while ((client_fd= accept(fd, 0, 0)) != -1);
{
printf("accepted\n");
const char *message= "\n10hel";
send(client_fd, message, strlen(message), 0);
int sleep_seconds= argc > 1 && atoi(argv[1]) ? atoi(argv[1]) : 1;
printf("sleeping %d seconds\n", sleep_seconds);
sleep(sleep_seconds);
close(client_fd);
}
printf("accept(): failed\n");
close(fd);
#endif
server-tools/instance-manager/listener.h
View file @
fd94614f
#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_LISTENER_H
#define INCLUDES_MYSQL_INSTANCE_MANAGER_LISTENER_H
/* Copyright (C) 200
0
MySQL AB & MySQL Finland AB & TCX DataKonsult AB
/* Copyright (C) 200
3
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
...
...
@@ -23,23 +23,34 @@
#include <my_global.h>
#include <my_pthread.h>
C_MODE_START
pthread_handler_decl
(
listener
,
arg
);
C_MODE_END
class
Thread_repository
;
class
Thread_registry
;
class
Options
;
class
User_map
;
class
Instance_map
;
struct
Listener_thread_args
{
Thread_repository
&
thread_repository
;
const
char
*
socket_file_name
;
Listener_thread_args
(
Thread_repository
&
thread_repository_arg
,
const
char
*
socket_file_name_arg
)
:
thread_repository
(
thread_repository_arg
),
socket_file_name
(
socket_file_name_arg
)
{}
Thread_registry
&
thread_registry
;
const
Options
&
options
;
const
User_map
&
user_map
;
Instance_map
&
instance_map
;
Listener_thread_args
(
Thread_registry
&
thread_registry_arg
,
const
Options
&
options_arg
,
const
User_map
&
user_map_arg
,
Instance_map
&
instance_map_arg
)
:
thread_registry
(
thread_registry_arg
)
,
options
(
options_arg
)
,
user_map
(
user_map_arg
)
,
instance_map
(
instance_map_arg
)
{}
};
#endif
#endif
// INCLUDES_MYSQL_INSTANCE_MANAGER_LISTENER_H
server-tools/instance-manager/log.cc
View file @
fd94614f
/* Copyright (C) 200
0
MySQL AB & MySQL Finland AB & TCX DataKonsult AB
/* Copyright (C) 200
3
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
...
...
@@ -139,12 +139,12 @@ void print_error(const char *format, ...)
}
/*
init_logs
()
log_init
()
RETURN VALUE
0 ok
!0 error
*/
void
log_init
()
{
/*
...
...
server-tools/instance-manager/log.h
View file @
fd94614f
#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_LOG_H
#define INCLUDES_MYSQL_INSTANCE_MANAGER_LOG_H
/* Copyright (C) 200
0
MySQL AB & MySQL Finland AB & TCX DataKonsult AB
/* Copyright (C) 200
3
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
...
...
@@ -22,11 +22,8 @@
Two logging streams are supported: error log and info log. Additionally
libdbug may be used for debug information output.
ANSI C buffered I/O is used to perform logging.
Logging may be performed in two modes:
- console application mode (default), stdout/stderr is used for logging
init_logs() must be called to initialize logging environment
- daemon mode, without controlling terminal, call
init_logs_in_daemon_mode() to initialize
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.
Rationale:
- no MYSQL_LOG as it has BIN mode, and not easy to fetch from sql_class.h
...
...
server-tools/instance-manager/manager.cc
View file @
fd94614f
/* Copyright (C) 200
0
MySQL AB & MySQL Finland AB & TCX DataKonsult AB
/* Copyright (C) 200
3
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
...
...
@@ -17,46 +17,175 @@
#include "manager.h"
#include <my_global.h>
#include <my_sys.h>
#include <m_string.h>
#include <signal.h>
#include <thr_alarm.h>
#include "thread_re
posito
ry.h"
#include "thread_re
gist
ry.h"
#include "listener.h"
#include "instance_map.h"
#include "options.h"
#include "user_map.h"
#include "log.h"
#include "guardian.h"
static
int
create_pid_file
(
const
char
*
pid_file_name
)
{
if
(
FILE
*
pid_file
=
my_fopen
(
pid_file_name
,
O_WRONLY
|
O_CREAT
|
O_BINARY
,
MYF
(
0
)))
{
fprintf
(
pid_file
,
"%d
\n
"
,
(
int
)
getpid
());
my_fclose
(
pid_file
,
MYF
(
0
));
}
else
{
log_error
(
"can't create pid file %s: errno=%d, %s"
,
pid_file_name
,
errno
,
strerror
(
errno
));
return
1
;
}
return
0
;
}
void
manager
(
const
char
*
socket_file_name
)
/*
manager - entry point to the main instance manager process: start
listener thread, write pid file and enter into signal handling.
See also comments in mysqlmanager.cc to picture general Instance Manager
architecture.
*/
void
manager
(
const
Options
&
options
)
{
Thread_repository
thread_repository
;
Listener_thread_args
listener_args
(
thread_repository
,
socket_file_name
);
Thread_registry
thread_registry
;
/*
All objects created in the manager() function live as long as
thread_registry lives, and thread_registry is alive until there are
working threads.
*/
User_map
user_map
;
Instance_map
instance_map
(
options
.
default_mysqld_path
,
options
.
default_admin_user
,
options
.
default_admin_password
);
Guardian_thread
guardian_thread
(
thread_registry
,
&
instance_map
,
options
.
monitoring_interval
);
Listener_thread_args
listener_args
(
thread_registry
,
options
,
user_map
,
instance_map
);
instance_map
.
guardian
=
&
guardian_thread
;
if
(
instance_map
.
init
()
||
user_map
.
init
()
||
instance_map
.
load
()
||
user_map
.
load
(
options
.
password_file_name
))
return
;
/* write pid file */
if
(
create_pid_file
(
options
.
pid_file_name
))
return
;
/* block signals */
sigset_t
mask
;
sigemptyset
(
&
mask
);
sigaddset
(
&
mask
,
SIGINT
);
sigaddset
(
&
mask
,
SIGTERM
);
sigaddset
(
&
mask
,
SIGPIPE
);
sigaddset
(
&
mask
,
SIGHUP
);
/*
We want this signal to be blocked in all theads but the signal
one. It is needed for the thr_alarm subsystem to work.
*/
sigaddset
(
&
mask
,
THR_SERVER_ALARM
);
/* all new threads will inherite this signal mask */
pthread_sigmask
(
SIG_BLOCK
,
&
mask
,
NULL
);
/* create the listener */
{
/* create the listener */
pthread_t
listener_thd_id
;
pthread_attr_t
listener_thd_attr
;
int
rc
;
pthread_attr_init
(
&
listener_thd_attr
);
pthread_attr_setdetachstate
(
&
listener_thd_attr
,
PTHREAD_CREATE_DETACHED
);
if
(
pthread_create
(
&
listener_thd_id
,
&
listener_thd_attr
,
listener
,
&
listener_args
))
die
(
"manager(): pthread_create(listener) failed"
);
rc
=
pthread_create
(
&
listener_thd_id
,
&
listener_thd_attr
,
listener
,
&
listener_args
);
pthread_attr_destroy
(
&
listener_thd_attr
);
if
(
rc
)
{
log_error
(
"manager(): pthread_create(listener) failed"
);
goto
err
;
}
}
/* create guardian thread */
{
pthread_t
guardian_thd_id
;
pthread_attr_t
guardian_thd_attr
;
int
rc
;
pthread_attr_init
(
&
guardian_thd_attr
);
pthread_attr_setdetachstate
(
&
guardian_thd_attr
,
PTHREAD_CREATE_DETACHED
);
rc
=
pthread_create
(
&
guardian_thd_id
,
&
guardian_thd_attr
,
guardian
,
&
guardian_thread
);
pthread_attr_destroy
(
&
guardian_thd_attr
);
if
(
rc
)
{
log_error
(
"manager(): pthread_create(guardian) failed"
);
goto
err
;
}
}
/*
To work nicely with LinuxThreads, the signal thread is the first thread
in the process.
*/
int
signo
;
my_sigwait
(
&
mask
,
&
signo
);
thread_repository
.
deliver_shutdown
();
bool
shutdown_complete
;
shutdown_complete
=
FALSE
;
/*
In our case the signal thread also implements functions of alarm thread.
Here we init alarm thread functionality. We suppose that we won't have
more then 10 alarms at the same time.
*/
init_thr_alarm
(
10
);
/*
Now we can init the list of guarded instances. We have to do it after
alarm structures initialization as we have to use net_* functions while
making the list. And they in their turn need alarms for timeout suppport.
*/
guardian_thread
.
start
();
signal
(
SIGPIPE
,
SIG_IGN
);
while
(
!
shutdown_complete
)
{
sigwait
(
&
mask
,
&
signo
);
switch
(
signo
)
{
case
THR_SERVER_ALARM
:
process_alarm
(
signo
);
break
;
default:
thread_registry
.
deliver_shutdown
();
shutdown_complete
=
TRUE
;
break
;
}
}
err:
/* delete the pid file */
my_delete
(
options
.
pid_file_name
,
MYF
(
0
));
/* close permanent connections to the running instances */
instance_map
.
cleanup
();
/* free alarm structures */
end_thr_alarm
(
1
);
/* don't pthread_exit to kill all threads who did not shut down in time */
}
server-tools/instance-manager/manager.h
View file @
fd94614f
#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_MANAGER_H
#define INCLUDES_MYSQL_INSTANCE_MANAGER_MANAGER_H
/* Copyright (C) 200
0
MySQL AB & MySQL Finland AB & TCX DataKonsult AB
/* Copyright (C) 200
3
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
...
...
@@ -16,6 +16,8 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
void
manager
(
const
char
*
socket_file_name
);
class
Options
;
void
manager
(
const
Options
&
options
);
#endif // INCLUDES_MYSQL_INSTANCE_MANAGER_MANAGER_H
server-tools/instance-manager/messages.cc
0 → 100644
View file @
fd94614f
/* Copyright (C) 2003 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 */
#include "messages.h"
#include <my_global.h>
#include <mysql_com.h>
#include <assert.h>
static
const
char
*
mysqld_error_message
(
unsigned
sql_errno
)
{
switch
(
sql_errno
)
{
case
ER_HANDSHAKE_ERROR
:
return
"Bad handshake"
;
case
ER_OUT_OF_RESOURCES
:
return
"Out of memory; Check if mysqld or some other process"
" uses all available memory. If not you may have to use"
" 'ulimit' to allow mysqld to use more memory or you can"
" add more swap space"
;
case
ER_ACCESS_DENIED_ERROR
:
return
"Access denied. Bad username/password pair"
;
case
ER_NOT_SUPPORTED_AUTH_MODE
:
return
"Client does not support authentication protocol requested by"
" server; consider upgrading MySQL client"
;
case
ER_UNKNOWN_COM_ERROR
:
return
"Unknown command"
;
case
ER_SYNTAX_ERROR
:
return
"You have an error in your command syntax. Check the manual that"
" corresponds to your MySQL Instance Manager version for the right"
" syntax to use"
;
case
ER_BAD_INSTANCE_NAME
:
return
"Bad instance name. Check that the instance with such a name exists"
;
case
ER_INSTANCE_IS_NOT_STARTED
:
return
"Cannot stop instance. Perhaps the instance is not started or you"
" have specified wrong username/password in the config file"
;
case
ER_INSTANCE_ALREADY_STARTED
:
return
"The instance is already started"
;
case
ER_CANNOT_START_INSTANCE
:
return
"Cannot start instance. Possible reasons are wrong instance options"
" or resources shortage"
;
case
ER_STOP_INSTANCE
:
return
"Cannot stop instance"
;
default:
DBUG_ASSERT
(
0
);
return
0
;
}
}
const
char
*
message
(
unsigned
sql_errno
)
{
return
mysqld_error_message
(
sql_errno
);
}
const
char
*
errno_to_sqlstate
(
unsigned
sql_errno
)
{
return
mysql_errno_to_sqlstate
(
sql_errno
);
}
server-tools/instance-manager/messages.h
0 → 100644
View file @
fd94614f
#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_MESSAGES_H
#define INCLUDES_MYSQL_INSTANCE_MANAGER_MESSAGES_H
/* Copyright (C) 2003 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 */
#include "mysqld_error.h"
#include "mysql_manager_error.h"
const
char
*
message
(
unsigned
sql_errno
);
const
char
*
errno_to_sqlstate
(
unsigned
sql_errno
);
#endif // INCLUDES_MYSQL_INSTANCE_MANAGER_MESSAGES_H
server-tools/instance-manager/mysql_connection.cc
0 → 100644
View file @
fd94614f
/* Copyright (C) 2003 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 interface
#endif
#include "mysql_connection.h"
#include "priv.h"
#include <mysql.h>
#include <violite.h>
#include <mysql_com.h>
#include <m_string.h>
#include <my_sys.h>
#include "thread_registry.h"
#include "log.h"
#include "user_map.h"
#include "protocol.h"
#include "messages.h"
#include "command.h"
#include "factory.h"
#include "parse.h"
Command
*
parse_command
(
Command_factory
*
factory
,
const
char
*
text
);
/*
MySQL connection - handle one connection with mysql command line client
See also comments in mysqlmanager.cc to picture general Instance Manager
architecture.
We use conventional technique to work with classes without exceptions:
class acquires all vital resource in init(); Thus if init() succeed,
a user must call cleanup(). All other methods are valid only between
init() and cleanup().
*/
class
Mysql_connection_thread
:
public
Mysql_connection_thread_args
{
public:
Mysql_connection_thread
(
const
Mysql_connection_thread_args
&
args
);
int
init
();
void
cleanup
();
void
run
();
~
Mysql_connection_thread
();
private:
Thread_info
thread_info
;
NET
net
;
struct
rand_struct
rand_st
;
char
scramble
[
SCRAMBLE_LENGTH
+
1
];
uint
status
;
ulong
client_capabilities
;
private:
/* Names are conventionally the same as in mysqld */
int
check_connection
();
int
check_user
(
const
char
*
user
,
const
char
*
password
);
int
do_command
();
int
dispatch_command
(
enum
enum_server_command
command
,
const
char
*
text
,
uint
len
);
};
Mysql_connection_thread
::
Mysql_connection_thread
(
const
Mysql_connection_thread_args
&
args
)
:
Mysql_connection_thread_args
(
args
.
vio
,
args
.
thread_registry
,
args
.
user_map
,
args
.
connection_id
,
args
.
instance_map
)
,
thread_info
(
pthread_self
())
{
thread_registry
.
register_thread
(
&
thread_info
);
}
/*
NET subsystem requieres its user to provide my_net_local_init extern
C function (exactly as declared below). my_net_local_init is called by
my_net_init and is supposed to set NET controlling variables.
See also priv.h for variables description.
*/
C_MODE_START
void
my_net_local_init
(
NET
*
net
)
{
net
->
max_packet
=
net_buffer_length
;
net
->
read_timeout
=
net_read_timeout
;
net
->
write_timeout
=
net_write_timeout
;
net
->
retry_count
=
net_retry_count
;
net
->
max_packet_size
=
max_allowed_packet
;
}
C_MODE_END
/*
Every resource, which we can fail to acquire, is allocated in init().
This function is complementary to cleanup().
*/
int
Mysql_connection_thread
::
init
()
{
/* Allocate buffers for network I/O */
if
(
my_net_init
(
&
net
,
vio
))
return
1
;
net
.
return_status
=
&
status
;
/* Initialize random number generator */
{
ulong
seed1
=
(
ulong
)
&
rand_st
+
rand
();
ulong
seed2
=
rand
()
+
time
(
0
);
randominit
(
&
rand_st
,
seed1
,
seed2
);
}
/* Fill scramble - server's random message used for handshake */
create_random_string
(
scramble
,
SCRAMBLE_LENGTH
,
&
rand_st
);
/* We don't support transactions, every query is atomic */
status
=
SERVER_STATUS_AUTOCOMMIT
;
return
0
;
}
void
Mysql_connection_thread
::
cleanup
()
{
net_end
(
&
net
);
}
Mysql_connection_thread
::~
Mysql_connection_thread
()
{
/* vio_delete closes the socket if necessary */
vio_delete
(
vio
);
thread_registry
.
unregister_thread
(
&
thread_info
);
}
void
Mysql_connection_thread
::
run
()
{
log_info
(
"accepted mysql connection %d"
,
connection_id
);
my_thread_init
();
if
(
check_connection
())
{
my_thread_end
();
return
;
}
log_info
(
"connection %d is checked successfully"
,
connection_id
);
vio_keepalive
(
vio
,
TRUE
);
while
(
!
net
.
error
&&
net
.
vio
&&
!
thread_registry
.
is_shutdown
())
{
if
(
do_command
())
break
;
}
my_thread_end
();
}
int
Mysql_connection_thread
::
check_connection
()
{
ulong
pkt_len
=
0
;
// to hold client reply length
/* buffer for the first packet */
/* packet contains: */
char
buff
[
mysqlmanager_version_length
+
1
+
// server version, 0-ended
4
+
// connection id
SCRAMBLE_LENGTH
+
2
+
// scramble (in 2 pieces)
18
];
// server variables: flags,
// charset number, status,
char
*
pos
=
buff
;
ulong
server_flags
;
memcpy
(
pos
,
mysqlmanager_version
,
mysqlmanager_version_length
+
1
);
pos
+=
mysqlmanager_version_length
+
1
;
int4store
((
uchar
*
)
pos
,
connection_id
);
pos
+=
4
;
/*
Old clients does not understand long scrambles, but can ignore packet
tail: that's why first part of the scramble is placed here, and second
part at the end of packet (even though we don't support old clients,
we must follow standard packet format.)
*/
memcpy
(
pos
,
scramble
,
SCRAMBLE_LENGTH_323
);
pos
+=
SCRAMBLE_LENGTH_323
;
*
pos
++=
'\0'
;
server_flags
=
CLIENT_LONG_FLAG
|
CLIENT_PROTOCOL_41
|
CLIENT_SECURE_CONNECTION
;
/*
18-bytes long section for various flags/variables
Every flag occupies a bit in first half of ulong; int2store will
gracefully pick up all flags.
*/
int2store
(
pos
,
server_flags
);
pos
+=
2
;
*
pos
++=
(
char
)
default_charset_info
->
number
;
// global mysys variable
int2store
(
pos
,
status
);
// connection status
pos
+=
2
;
bzero
(
pos
,
13
);
// not used now
pos
+=
13
;
/* second part of the scramble, null-terminated */
memcpy
(
pos
,
scramble
+
SCRAMBLE_LENGTH_323
,
SCRAMBLE_LENGTH
-
SCRAMBLE_LENGTH_323
+
1
);
pos
+=
SCRAMBLE_LENGTH
-
SCRAMBLE_LENGTH_323
+
1
;
/* write connection message and read reply */
enum
{
MIN_HANDSHAKE_SIZE
=
2
};
if
(
net_write_command
(
&
net
,
protocol_version
,
""
,
0
,
buff
,
pos
-
buff
)
||
(
pkt_len
=
my_net_read
(
&
net
))
==
packet_error
||
pkt_len
<
MIN_HANDSHAKE_SIZE
)
{
net_send_error
(
&
net
,
ER_HANDSHAKE_ERROR
);
return
1
;
}
client_capabilities
=
uint2korr
(
net
.
read_pos
);
if
(
!
(
client_capabilities
&
CLIENT_PROTOCOL_41
))
{
net_send_error_323
(
&
net
,
ER_NOT_SUPPORTED_AUTH_MODE
);
return
1
;
}
client_capabilities
|=
((
ulong
)
uint2korr
(
net
.
read_pos
+
2
))
<<
16
;
pos
=
(
char
*
)
net
.
read_pos
+
32
;
/* At least one byte for username and one byte for password */
if
(
pos
>=
(
char
*
)
net
.
read_pos
+
pkt_len
+
2
)
{
/*TODO add user and password handling in error messages*/
net_send_error
(
&
net
,
ER_HANDSHAKE_ERROR
);
return
1
;
}
const
char
*
user
=
pos
;
const
char
*
password
=
strend
(
user
)
+
1
;
ulong
password_len
=
*
password
++
;
if
(
password_len
!=
SCRAMBLE_LENGTH
)
{
net_send_error
(
&
net
,
ER_ACCESS_DENIED_ERROR
);
return
1
;
}
if
(
user_map
.
authenticate
(
user
,
password
-
user
-
2
,
password
,
scramble
))
{
net_send_error
(
&
net
,
ER_ACCESS_DENIED_ERROR
);
return
1
;
}
net_send_ok
(
&
net
,
connection_id
);
return
0
;
}
int
Mysql_connection_thread
::
check_user
(
const
char
*
user
,
const
char
*
password
)
{
return
0
;
}
int
Mysql_connection_thread
::
do_command
()
{
char
*
packet
;
uint
old_timeout
;
ulong
packet_length
;
/* We start to count packets from 0 for each new command */
net
.
pkt_nr
=
0
;
if
((
packet_length
=
my_net_read
(
&
net
))
==
packet_error
)
{
/* Check if we can continue without closing the connection */
if
(
net
.
error
!=
3
)
// what is 3 - find out
{
return
1
;
}
if
(
thread_registry
.
is_shutdown
())
return
1
;
net_send_error
(
&
net
,
net
.
last_errno
);
net
.
error
=
0
;
return
0
;
}
else
{
if
(
thread_registry
.
is_shutdown
())
return
1
;
packet
=
(
char
*
)
net
.
read_pos
;
enum
enum_server_command
command
=
(
enum
enum_server_command
)
(
uchar
)
*
packet
;
log_info
(
"connection %d: packet_length=%d, command=%d"
,
connection_id
,
packet_length
,
command
);
return
dispatch_command
(
command
,
packet
+
1
,
packet_length
-
1
);
}
}
int
Mysql_connection_thread
::
dispatch_command
(
enum
enum_server_command
command
,
const
char
*
packet
,
uint
len
)
{
switch
(
command
)
{
case
COM_QUIT
:
// client exit
log_info
(
"query for connection %d received quit command"
,
connection_id
);
return
1
;
case
COM_PING
:
log_info
(
"query for connection %d received ping command"
,
connection_id
);
net_send_ok
(
&
net
,
connection_id
);
break
;
case
COM_QUERY
:
{
log_info
(
"query for connection %d : ----
\n
%s
\n
-------------------------"
,
connection_id
,
packet
);
Command_factory
commands_factory
(
instance_map
);
if
(
Command
*
command
=
parse_command
(
&
commands_factory
,
packet
))
{
int
res
=
0
;
log_info
(
"query for connection %d successefully parsed"
,
connection_id
);
res
=
command
->
execute
(
&
net
,
connection_id
);
delete
command
;
if
(
!
res
)
{
log_info
(
"query for connection %d executed ok"
,
connection_id
);
}
else
{
log_info
(
"query for connection %d executed err=%d"
,
connection_id
,
res
);
net_send_error
(
&
net
,
res
);
return
0
;
}
}
else
{
net_send_error
(
&
net
,
ER_OUT_OF_RESOURCES
);
return
0
;
}
break
;
}
default:
log_info
(
"query for connection %d received unknown command"
,
connection_id
);
net_send_error
(
&
net
,
ER_UNKNOWN_COM_ERROR
);
break
;
}
return
0
;
}
C_MODE_START
pthread_handler_decl
(
mysql_connection
,
arg
)
{
Mysql_connection_thread_args
*
args
=
(
Mysql_connection_thread_args
*
)
arg
;
Mysql_connection_thread
mysql_connection_thread
(
*
args
);
delete
args
;
if
(
mysql_connection_thread
.
init
())
log_info
(
"mysql_connection(): error initializing thread"
);
else
{
mysql_connection_thread
.
run
();
mysql_connection_thread
.
cleanup
();
}
return
0
;
}
C_MODE_END
/*
vim: fdm=marker
*/
server-tools/instance-manager/mysql_connection.h
0 → 100644
View file @
fd94614f
#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_MYSQL_CONNECTION_H
#define INCLUDES_MYSQL_INSTANCE_MANAGER_MYSQL_CONNECTION_H
/* Copyright (C) 2003 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 interface
#endif
#include <my_global.h>
#include <my_pthread.h>
C_MODE_START
pthread_handler_decl
(
mysql_connection
,
arg
);
C_MODE_END
class
Thread_registry
;
class
User_map
;
class
Instance_map
;
struct
st_vio
;
struct
Mysql_connection_thread_args
{
struct
st_vio
*
vio
;
Thread_registry
&
thread_registry
;
const
User_map
&
user_map
;
ulong
connection_id
;
Instance_map
&
instance_map
;
Mysql_connection_thread_args
(
struct
st_vio
*
vio_arg
,
Thread_registry
&
thread_registry_arg
,
const
User_map
&
user_map_arg
,
ulong
connection_id_arg
,
Instance_map
&
instance_map_arg
)
:
vio
(
vio_arg
)
,
thread_registry
(
thread_registry_arg
)
,
user_map
(
user_map_arg
)
,
connection_id
(
connection_id_arg
)
,
instance_map
(
instance_map_arg
)
{}
};
#endif // INCLUDES_MYSQL_INSTANCE_MANAGER_MYSQL_CONNECTION_H
server-tools/instance-manager/mysql_manager_error.h
0 → 100644
View file @
fd94614f
#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_MYSQL_MANAGER_ERROR_H
#define INCLUDES_MYSQL_INSTANCE_MANAGER_MYSQL_MANAGER_ERROR_H
/* 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 */
/* Definefile for instance manager error messagenumbers */
#define ER_BAD_INSTANCE_NAME 3000
#define ER_INSTANCE_IS_NOT_STARTED 3001
#define ER_INSTANCE_ALREADY_STARTED 3002
#define ER_CANNOT_START_INSTANCE 3003
#define ER_STOP_INSTANCE 3004
#endif
/* INCLUDES_MYSQL_INSTANCE_MANAGER_MYSQL_MANAGER_ERROR_H */
server-tools/instance-manager/mysqlmanager.cc
View file @
fd94614f
/* Copyright (C) 200
0
MySQL AB & MySQL Finland AB & TCX DataKonsult AB
/* Copyright (C) 200
3
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
...
...
@@ -14,20 +14,21 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include "manager.h"
#include "options.h"
#include "log.h"
#include <my_global.h>
#include <my_sys.h>
#include <string.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "manager.h"
#include "options.h"
#include "log.h"
/*
Few notes about
the
Instance Manager architecture:
Few notes about Instance Manager architecture:
Instance Manager consisits of two processes: the angel process, and the
instance manager process. Responsibilities of the angel process is to
monitor the instance manager process, and restart it in case of
...
...
@@ -35,19 +36,19 @@
'--run-as-service' is provided.
The Instance Manager process consists of several
subsystems (thread sets):
- the signal handling thread: it's responsibilities are to handle
- the signal handling thread: it's responsibilities are to handle
user signals and propogate them to the other threads. All other threads
are accounted in the signal handler thread Thread Re
posito
ry.
- the listener: listens all sockets. There is a listening
are accounted in the signal handler thread Thread Re
gist
ry.
- the listener: listens all sockets. There is a listening
socket for each (mysql, http, snmp, rendezvous (?)) subsystem.
- mysql subsystem: Instance Manager acts like an ordinary MySQL Server,
but with very restricted command set. Each MySQL client connection is
but with very restricted command set. Each MySQL client connection is
handled in a separate thread. All MySQL client connections threads
constitute mysql subsystem.
- http subsystem: it is also possible to talk with Instance Manager via
- http subsystem: it is also possible to talk with Instance Manager via
http. One thread per http connection is used. Threads are pooled.
- 'snmp' connections (FIXME: I know nothing about it yet)
- rendezvous threads
- rendezvous threads
*/
static
void
init_environment
(
char
*
progname
);
...
...
@@ -70,11 +71,12 @@ int main(int argc, char *argv[])
options
.
load
(
argc
,
argv
);
if
(
options
.
run_as_service
)
{
/* forks, and returns only in child */
daemonize
(
options
.
log_file_name
);
/* forks again, and returns only in child: parent becomes angel */
angel
(
options
);
}
else
manager
(
options
.
log_file_name
);
manager
(
options
);
return
0
;
}
...
...
@@ -90,6 +92,7 @@ static void init_environment(char *progname)
MY_INIT
(
progname
);
log_init
();
umask
(
0117
);
srand
(
time
(
0
));
}
...
...
@@ -109,8 +112,8 @@ static void daemonize(const char *log_file_name)
int
fd
;
/*
Become a session leader: setsid must succeed because child is
guaranteed not to be a process group leader (it belongs to the
process group of the parent.)
guaranteed not to be a process group leader (it belongs to the
process group of the parent.)
The goal is not to have a controlling terminal.
*/
setsid
();
...
...
@@ -121,7 +124,7 @@ static void daemonize(const char *log_file_name)
close
(
STDIN_FILENO
);
fd
=
open
(
log_file_name
,
O_WRONLY
|
O_CREAT
|
O_APPEND
|
O_NOCTTY
,
fd
=
open
(
log_file_name
,
O_WRONLY
|
O_CREAT
|
O_APPEND
|
O_NOCTTY
,
S_IRUSR
|
S_IWUSR
|
S_IRGRP
|
S_IWGRP
);
if
(
fd
<
0
)
die
(
"daemonize(): failed to open log file %s, %s"
,
log_file_name
,
...
...
@@ -133,7 +136,7 @@ static void daemonize(const char *log_file_name)
/* TODO: chroot() and/or chdir() here */
break
;
default:
default:
/* successfully exit from parent */
exit
(
0
);
}
...
...
@@ -144,13 +147,13 @@ enum { CHILD_OK= 0, CHILD_NEED_RESPAWN, CHILD_EXIT_ANGEL };
static
volatile
sig_atomic_t
child_status
=
CHILD_OK
;
/*
/*
Signal handler for SIGCHLD: reap child, analyze child exit status, and set
child_status appropriately.
*/
void
reap_child
(
int
__attribute__
((
unused
))
signo
)
{
{
int
child_exit_status
;
/* As we have only one child, no need to cycle waitpid */
if
(
waitpid
(
0
,
&
child_exit_status
,
WNOHANG
)
>
0
)
...
...
@@ -159,16 +162,14 @@ void reap_child(int __attribute__((unused)) signo)
child_status
=
CHILD_NEED_RESPAWN
;
else
/*
As
we
reap_child is not called for SIGSTOP, we should be here only
As reap_child is not called for SIGSTOP, we should be here only
if the child exited normally.
*/
child_status
=
CHILD_EXIT_ANGEL
;
}
}
/* Not static to reuse it in childs */
volatile
sig_atomic_t
is_terminated
=
0
;
static
volatile
sig_atomic_t
is_terminated
=
0
;
/*
Signal handler for terminate signals - SIGTERM, SIGHUP, SIGINT.
...
...
@@ -178,7 +179,7 @@ volatile sig_atomic_t is_terminated= 0;
void
terminate
(
int
signo
)
{
is_terminated
=
signo
;
is_terminated
=
signo
;
}
...
...
@@ -215,18 +216,18 @@ spawn:
pid_t
pid
=
fork
();
switch
(
pid
)
{
case
-
1
:
die
(
"angel(): fork failed, %s"
,
strerror
(
errno
));
die
(
"angel(): fork failed, %s"
,
strerror
(
errno
));
case
0
:
// child, success
/*
restore default actions for signals to let the manager work with
signals as he wishes
*/
*/
sigaction
(
SIGCHLD
,
&
sa_chld_out
,
0
);
sigaction
(
SIGTERM
,
&
sa_term_out
,
0
);
sigaction
(
SIGINT
,
&
sa_int_out
,
0
);
sigaction
(
SIGHUP
,
&
sa_hup_out
,
0
);
manager
(
options
.
socket_file_name
)
;
/* Here we return to main, and fall into manager */
break
;
default:
// parent, success
while
(
child_status
==
CHILD_OK
&&
is_terminated
==
0
)
sigsuspend
(
&
zeromask
);
...
...
@@ -234,12 +235,18 @@ spawn:
if
(
is_terminated
)
log_info
(
"angel got signal %d, exiting"
,
is_terminated
);
else
if
(
child_status
==
CHILD_NEED_RESPAWN
)
{
{
child_status
=
CHILD_OK
;
log_error
(
"angel(): mysqlmanager exited abnormally: respawning..."
);
sleep
(
1
);
/* don't respawn too fast */
goto
spawn
;
}
/* mysqlmanager successfully exited, let's silently evaporate */
/*
mysqlmanager successfully exited, let's silently evaporate
If we return to main we fall into the manager() function, so let's
simply exit().
*/
exit
(
0
);
}
}
server-tools/instance-manager/options.cc
View file @
fd94614f
/* Copyright (C) 200
0
MySQL AB & MySQL Finland AB & TCX DataKonsult AB
/* Copyright (C) 200
3
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
...
...
@@ -15,7 +15,7 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#ifdef __GNUC__
#pragma implementation
#pragma implementation
#endif
#include "options.h"
...
...
@@ -24,14 +24,22 @@
#include <my_sys.h>
#include <my_getopt.h>
#include "priv.h"
#define QUOTE2(x) #x
#define QUOTE(x) QUOTE2(x)
char
Options
::
run_as_service
;
const
char
*
Options
::
log_file_name
=
QUOTE
(
DEFAULT_LOG_FILE_NAME
);
const
char
*
Options
::
pid_file_name
=
QUOTE
(
DEFAULT_PID_FILE_NAME
);
const
char
*
Options
::
socket_file_name
=
QUOTE
(
DEFAULT_SOCKET_FILE_NAME
);
const
char
*
Options
::
password_file_name
=
QUOTE
(
DEFAULT_PASSWORD_FILE_NAME
);
const
char
*
Options
::
default_mysqld_path
=
QUOTE
(
DEFAULT_MYSQLD_PATH
);
const
char
*
Options
::
default_admin_user
=
QUOTE
(
DEFAULT_USER
);
const
char
*
Options
::
default_admin_password
=
QUOTE
(
DEFAULT_PASSWORD
);
const
char
*
Options
::
bind_address
=
0
;
/* No default value */
uint
Options
::
monitoring_interval
=
DEFAULT_MONITORING_INTERVAL
;
uint
Options
::
port_number
=
DEFAULT_PORT
;
/*
List of options, accepted by the instance manager.
...
...
@@ -42,9 +50,18 @@ enum options {
OPT_LOG
=
256
,
OPT_PID_FILE
,
OPT_SOCKET
,
OPT_RUN_AS_SERVICE
OPT_PASSWORD_FILE
,
OPT_MYSQLD_PATH
,
OPT_RUN_AS_SERVICE
,
OPT_USER
,
OPT_PASSWORD
,
OPT_DEFAULT_ADMIN_USER
,
OPT_DEFAULT_ADMIN_PASSWORD
,
OPT_MONITORING_INTERVAL
,
OPT_PORT
,
OPT_BIND_ADDRESS
};
static
struct
my_option
my_long_options
[]
=
{
{
"help"
,
'?'
,
"Display this help and exit."
,
...
...
@@ -57,11 +74,48 @@ static struct my_option my_long_options[] =
{
"pid-file"
,
OPT_PID_FILE
,
"Pid file to use."
,
(
gptr
*
)
&
Options
::
pid_file_name
,
(
gptr
*
)
&
Options
::
pid_file_name
,
0
,
GET_STR
,
REQUIRED_ARG
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"socket"
,
OPT_SOCKET
,
"Socket file to use for connection."
,
(
gptr
*
)
&
Options
::
socket_file_name
,
(
gptr
*
)
&
Options
::
socket_file_name
,
0
,
GET_STR
,
REQUIRED_ARG
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"bind-address"
,
OPT_BIND_ADDRESS
,
"Bind address to use for connection."
,
(
gptr
*
)
&
Options
::
bind_address
,
(
gptr
*
)
&
Options
::
bind_address
,
0
,
GET_STR
,
REQUIRED_ARG
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"port"
,
OPT_PORT
,
"Port number to use for connections"
,
(
gptr
*
)
&
Options
::
port_number
,
(
gptr
*
)
&
Options
::
port_number
,
0
,
GET_UINT
,
REQUIRED_ARG
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"password-file"
,
OPT_PASSWORD_FILE
,
"Look for Instane Manager users"
" and passwords here."
,
(
gptr
*
)
&
Options
::
password_file_name
,
(
gptr
*
)
&
Options
::
password_file_name
,
0
,
GET_STR
,
REQUIRED_ARG
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"default-mysqld-path"
,
OPT_MYSQLD_PATH
,
"Where to look for MySQL"
" Server binary."
,
(
gptr
*
)
&
Options
::
default_mysqld_path
,
(
gptr
*
)
&
Options
::
default_mysqld_path
,
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"
" in seconds."
,
(
gptr
*
)
&
Options
::
monitoring_interval
,
(
gptr
*
)
&
Options
::
monitoring_interval
,
0
,
GET_UINT
,
REQUIRED_ARG
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"run-as-service"
,
OPT_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
},
...
...
@@ -74,15 +128,26 @@ static struct my_option my_long_options[] =
static
void
version
()
{
static
const
char
mysqlmanager_version
[]
=
"0.1-alpha"
;
printf
(
"%s Ver %s for %s on %s
\n
"
,
my_progname
,
mysqlmanager_version
,
printf
(
"%s Ver %s for %s on %s
\n
"
,
my_progname
,
mysqlmanager_version
,
SYSTEM_TYPE
,
MACHINE_TYPE
);
}
static
const
char
*
default_groups
[]
=
{
"mysql"
,
"manager"
,
0
};
static
void
usage
()
{
version
();
printf
(
"Copyright (C) 2003, 2004 MySQL AB
\n
"
"This software comes with ABSOLUTELY NO WARRANTY. This is free software,
\n
"
"and you are welcome to modify and redistribute it under the GPL license
\n
"
);
printf
(
"Usage: %s [OPTIONS]
\n
"
,
my_progname
);
my_print_help
(
my_long_options
);
print_defaults
(
"my"
,
default_groups
);
my_print_variables
(
my_long_options
);
}
C_MODE_START
...
...
@@ -107,9 +172,9 @@ get_one_option(int optid,
C_MODE_END
/*
/*
- call load_defaults to load configuration file section
- call handle_options to assign defaults and command-line arguments
- call handle_options to assign defaults and command-line arguments
to the class members
if either of these function fail, exit the program
May not return.
...
...
@@ -117,6 +182,9 @@ C_MODE_END
void
Options
::
load
(
int
argc
,
char
**
argv
)
{
/* config-file options are prepended to command-line ones */
load_defaults
(
"my"
,
default_groups
,
&
argc
,
&
argv
);
if
(
int
rc
=
handle_options
(
&
argc
,
&
argv
,
my_long_options
,
get_one_option
))
exit
(
rc
);
}
...
...
server-tools/instance-manager/options.h
View file @
fd94614f
#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_OPTIONS_H
#define INCLUDES_MYSQL_INSTANCE_MANAGER_OPTIONS_H
/* Copyright (C) 200
0
MySQL AB & MySQL Finland AB & TCX DataKonsult AB
/* Copyright (C) 200
3
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
...
...
@@ -24,13 +24,21 @@
Options - all possible options for the instance manager grouped in one
struct.
*/
#include <my_global.h>
struct
Options
struct
Options
{
static
char
run_as_service
;
/* handle_options doesn't support bool */
static
const
char
*
log_file_name
;
static
const
char
*
pid_file_name
;
static
const
char
*
socket_file_name
;
static
const
char
*
password_file_name
;
static
const
char
*
default_mysqld_path
;
static
const
char
*
default_admin_user
;
static
const
char
*
default_admin_password
;
static
uint
monitoring_interval
;
static
uint
port_number
;
static
const
char
*
bind_address
;
static
void
load
(
int
argc
,
char
**
argv
);
};
...
...
server-tools/instance-manager/parse.cc
0 → 100644
View file @
fd94614f
/* 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 <string.h>
enum
Token
{
TOK_FLUSH
=
0
,
TOK_INSTANCE
,
TOK_INSTANCES
,
TOK_OPTIONS
,
TOK_START
,
TOK_STATUS
,
TOK_STOP
,
TOK_SHOW
,
TOK_NOT_FOUND
,
// must be after all tokens
TOK_END
};
struct
tokens_st
{
uint
length
;
const
char
*
tok_name
;
};
static
struct
tokens_st
tokens
[]
=
{
{
5
,
"FLUSH"
},
{
8
,
"INSTANCE"
},
{
9
,
"INSTANCES"
},
{
7
,
"OPTIONS"
},
{
5
,
"START"
},
{
6
,
"STATUS"
},
{
4
,
"STOP"
},
{
4
,
"SHOW"
}
};
/*
tries to find next word in the text
if found, returns the beginning and puts word length to word_len argument.
if not found returns pointer to first non-space or to '\0', word_len == 0
*/
inline
void
get_word
(
const
char
**
text
,
uint
*
word_len
)
{
const
char
*
word_end
;
/* skip space */
while
(
my_isspace
(
default_charset_info
,
**
text
))
++
(
*
text
);
word_end
=
*
text
;
while
(
my_isalnum
(
default_charset_info
,
*
word_end
))
++
word_end
;
*
word_len
=
word_end
-
*
text
;
}
/*
Returns token no if word corresponds to some token, otherwise returns
TOK_NOT_FOUND
*/
inline
Token
find_token
(
const
char
*
word
,
uint
word_len
)
{
int
i
=
0
;
do
{
if
(
my_strnncoll
(
default_charset_info
,
(
const
uchar
*
)
tokens
[
i
].
tok_name
,
tokens
[
i
].
length
,
(
const
uchar
*
)
word
,
word_len
)
==
0
)
break
;
}
while
(
++
i
<
TOK_NOT_FOUND
);
return
(
Token
)
i
;
}
Token
get_token
(
const
char
**
text
,
uint
*
word_len
)
{
get_word
(
text
,
word_len
);
if
(
*
word_len
)
return
find_token
(
*
text
,
*
word_len
);
return
TOK_END
;
}
Token
shift_token
(
const
char
**
text
,
uint
*
word_len
)
{
Token
save
=
get_token
(
text
,
word_len
);
(
*
text
)
+=
*
word_len
;
return
save
;
}
void
print_token
(
const
char
*
token
,
uint
tok_len
)
{
for
(
uint
i
=
0
;
i
<
tok_len
;
++
i
)
printf
(
"%c"
,
token
[
i
]);
}
int
get_text_id
(
const
char
**
text
,
uint
*
word_len
,
const
char
**
id
)
{
get_word
(
text
,
word_len
);
if
(
word_len
==
0
)
return
1
;
*
id
=
*
text
;
return
0
;
}
Command
*
parse_command
(
Command_factory
*
factory
,
const
char
*
text
)
{
uint
word_len
;
const
char
*
instance_name
;
uint
instance_name_len
;
Command
*
command
;
const
char
*
saved_text
=
text
;
Token
tok1
=
shift_token
(
&
text
,
&
word_len
);
switch
(
tok1
)
{
case
TOK_START
:
// fallthrough
case
TOK_STOP
:
if
(
shift_token
(
&
text
,
&
word_len
)
!=
TOK_INSTANCE
)
goto
syntax_error
;
get_word
(
&
text
,
&
word_len
);
if
(
word_len
==
0
)
goto
syntax_error
;
instance_name
=
text
;
instance_name_len
=
word_len
;
text
+=
word_len
;
/* it should be the end of command */
get_word
(
&
text
,
&
word_len
);
if
(
word_len
)
goto
syntax_error
;
command
=
(
tok1
==
TOK_START
)
?
(
Command
*
)
factory
->
new_Start_instance
(
instance_name
,
instance_name_len
)
:
(
Command
*
)
factory
->
new_Stop_instance
(
instance_name
,
instance_name_len
);
break
;
case
TOK_FLUSH
:
if
(
shift_token
(
&
text
,
&
word_len
)
!=
TOK_INSTANCES
)
goto
syntax_error
;
get_word
(
&
text
,
&
word_len
);
if
(
word_len
)
goto
syntax_error
;
command
=
factory
->
new_Flush_instances
();
break
;
case
TOK_SHOW
:
switch
(
shift_token
(
&
text
,
&
word_len
))
{
case
TOK_INSTANCES
:
get_word
(
&
text
,
&
word_len
);
if
(
word_len
)
goto
syntax_error
;
command
=
factory
->
new_Show_instances
();
break
;
case
TOK_INSTANCE
:
switch
(
Token
tok2
=
shift_token
(
&
text
,
&
word_len
))
{
case
TOK_OPTIONS
:
case
TOK_STATUS
:
get_text_id
(
&
text
,
&
instance_name_len
,
&
instance_name
);
text
+=
instance_name_len
;
get_word
(
&
text
,
&
word_len
);
if
(
word_len
)
goto
syntax_error
;
command
=
(
tok2
==
TOK_STATUS
)
?
(
Command
*
)
factory
->
new_Show_instance_status
(
instance_name
,
instance_name_len
)
:
(
Command
*
)
factory
->
new_Show_instance_options
(
instance_name
,
instance_name_len
);
break
;
default:
goto
syntax_error
;
}
break
;
default:
goto
syntax_error
;
}
break
;
default:
syntax_error:
command
=
factory
->
new_Syntax_error
();
}
return
command
;
}
server-tools/instance-manager/parse.h
0 → 100644
View file @
fd94614f
#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_PARSE_H
#define INCLUDES_MYSQL_INSTANCE_MANAGER_PARSE_H
/* 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 "factory.h"
Command
*
parse_command
(
Command_factory
*
factory
,
const
char
*
text
);
#endif
/* INCLUDES_MYSQL_INSTANCE_MANAGER_PARSE_H */
server-tools/instance-manager/priv.cc
0 → 100644
View file @
fd94614f
/* Copyright (C) 2003 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 */
#include "priv.h"
const
char
mysqlmanager_version
[]
=
"0.2-alpha"
;
const
int
mysqlmanager_version_length
=
sizeof
(
mysqlmanager_version
)
-
1
;
const
unsigned
char
protocol_version
=
PROTOCOL_VERSION
;
unsigned
long
net_buffer_length
=
16384
;
unsigned
long
max_allowed_packet
=
16384
;
unsigned
long
net_read_timeout
=
30
;
// same as in mysqld
unsigned
long
net_write_timeout
=
60
;
// same as in mysqld
unsigned
long
net_retry_count
=
10
;
// same as in mysqld
/* needed by net_serv.cc */
unsigned
int
test_flags
=
0
;
unsigned
long
bytes_sent
=
0L
,
bytes_received
=
0L
;
unsigned
long
mysqld_net_retry_count
=
10L
;
unsigned
long
open_files_limit
;
server-tools/instance-manager/priv.h
0 → 100644
View file @
fd94614f
#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_PRIV_H
#define INCLUDES_MYSQL_INSTANCE_MANAGER_PRIV_H
/* Copyright (C) 2003 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 */
extern
const
char
mysqlmanager_version
[];
extern
const
int
mysqlmanager_version_length
;
/* MySQL client-server protocol version: substituted from configure */
extern
const
unsigned
char
protocol_version
;
/*
These variables are used in MySQL subsystem to work with mysql clients
To be moved to a config file/options one day.
*/
/* Buffer length for TCP/IP and socket communication */
extern
unsigned
long
net_buffer_length
;
/* Maximum allowed incoming/ougoung packet length */
extern
unsigned
long
max_allowed_packet
;
/*
Number of seconds to wait for more data from a connection before aborting
the read
*/
extern
unsigned
long
net_read_timeout
;
/*
Number of seconds to wait for a block to be written to a connection
before aborting the write.
*/
extern
unsigned
long
net_write_timeout
;
/*
If a read on a communication port is interrupted, retry this many times
before giving up.
*/
extern
unsigned
long
net_retry_count
;
extern
unsigned
int
test_flags
;
extern
unsigned
long
bytes_sent
,
bytes_received
;
extern
unsigned
long
mysqld_net_retry_count
;
extern
unsigned
long
open_files_limit
;
#endif // INCLUDES_MYSQL_INSTANCE_MANAGER_PRIV_H
server-tools/instance-manager/protocol.cc
0 → 100644
View file @
fd94614f
/* Copyright (C) 2003 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 */
#include <my_global.h>
#include <my_sys.h>
#include <mysql_com.h>
#include <m_string.h>
#include "messages.h"
#include "protocol.h"
static
char
eof_buff
[
1
]
=
{
(
char
)
254
};
/* Marker for end of fields */
int
net_send_ok
(
struct
st_net
*
net
,
unsigned
long
connection_id
)
{
char
buff
[
1
+
// packet type code
9
+
// affected rows count
9
+
// connection id
2
+
// thread return status
2
];
// warning count
char
*
pos
=
buff
;
enum
{
OK_PACKET_CODE
=
0
};
*
pos
++=
OK_PACKET_CODE
;
pos
=
net_store_length
(
pos
,
(
ulonglong
)
0
);
pos
=
net_store_length
(
pos
,
(
ulonglong
)
connection_id
);
int2store
(
pos
,
*
net
->
return_status
);
pos
+=
2
;
/* We don't support warnings, so store 0 for total warning count */
int2store
(
pos
,
0
);
pos
+=
2
;
return
my_net_write
(
net
,
buff
,
pos
-
buff
)
||
net_flush
(
net
);
}
int
net_send_error
(
struct
st_net
*
net
,
uint
sql_errno
)
{
const
char
*
err
=
message
(
sql_errno
);
char
buff
[
1
+
// packet type code
2
+
// sql error number
1
+
SQLSTATE_LENGTH
+
// sql state
MYSQL_ERRMSG_SIZE
];
// message
char
*
pos
=
buff
;
enum
{
ERROR_PACKET_CODE
=
255
};
*
pos
++=
ERROR_PACKET_CODE
;
int2store
(
pos
,
sql_errno
);
pos
+=
2
;
/* The first # is to make the protocol backward compatible */
*
pos
++=
'#'
;
memcpy
(
pos
,
errno_to_sqlstate
(
sql_errno
),
SQLSTATE_LENGTH
);
pos
+=
SQLSTATE_LENGTH
;
pos
=
strmake
(
pos
,
err
,
MYSQL_ERRMSG_SIZE
-
1
)
+
1
;
return
my_net_write
(
net
,
buff
,
pos
-
buff
)
||
net_flush
(
net
);
}
int
net_send_error_323
(
struct
st_net
*
net
,
uint
sql_errno
)
{
const
char
*
err
=
message
(
sql_errno
);
char
buff
[
1
+
// packet type code
2
+
// sql error number
MYSQL_ERRMSG_SIZE
];
// message
char
*
pos
=
buff
;
enum
{
ERROR_PACKET_CODE
=
255
};
*
pos
++=
ERROR_PACKET_CODE
;
int2store
(
pos
,
sql_errno
);
pos
+=
2
;
pos
=
strmake
(
pos
,
err
,
MYSQL_ERRMSG_SIZE
-
1
)
+
1
;
return
my_net_write
(
net
,
buff
,
pos
-
buff
)
||
net_flush
(
net
);
}
char
*
net_store_length
(
char
*
pkg
,
uint
length
)
{
uchar
*
packet
=
(
uchar
*
)
pkg
;
if
(
length
<
251
)
{
*
packet
=
(
uchar
)
length
;
return
(
char
*
)
packet
+
1
;
}
*
packet
++=
252
;
int2store
(
packet
,(
uint
)
length
);
return
(
char
*
)
packet
+
2
;
}
int
store_to_string
(
Buffer
*
buf
,
const
char
*
string
,
uint
*
position
)
{
uint
currpos
;
uint
string_len
;
string_len
=
strlen
(
string
);
if
(
buf
->
reserve
(
*
position
,
2
))
goto
err
;
currpos
=
(
net_store_length
(
buf
->
buffer
+
*
position
,
string_len
)
-
buf
->
buffer
);
if
(
buf
->
append
(
currpos
,
string
,
string_len
))
goto
err
;
*
position
=
*
position
+
string_len
+
(
currpos
-
*
position
);
return
0
;
err:
return
1
;
}
int
send_eof
(
struct
st_net
*
net
)
{
char
buff
[
1
+
/* eof packet code */
2
+
/* warning count */
2
];
/* server status */
buff
[
0
]
=
254
;
int2store
(
buff
+
1
,
0
);
int2store
(
buff
+
3
,
0
);
return
my_net_write
(
net
,
buff
,
sizeof
buff
);
}
int
send_fields
(
struct
st_net
*
net
,
LIST
*
fields
)
{
LIST
*
tmp
=
fields
;
Buffer
send_buff
;
char
small_buff
[
4
];
uint
position
=
0
;
NAME_WITH_LENGTH
*
field
;
/* send the number of fileds */
net_store_length
(
small_buff
,
(
uint
)
list_length
(
fields
));
if
(
my_net_write
(
net
,
small_buff
,
(
uint
)
1
))
goto
err
;
while
(
tmp
)
{
position
=
0
;
field
=
(
NAME_WITH_LENGTH
*
)
tmp
->
data
;
store_to_string
(
&
send_buff
,
(
char
*
)
""
,
&
position
);
/* catalog name */
store_to_string
(
&
send_buff
,
(
char
*
)
""
,
&
position
);
/* db name */
store_to_string
(
&
send_buff
,
(
char
*
)
""
,
&
position
);
/* table name */
store_to_string
(
&
send_buff
,
(
char
*
)
""
,
&
position
);
/* table name alias */
store_to_string
(
&
send_buff
,
field
->
name
,
&
position
);
/* column name */
store_to_string
(
&
send_buff
,
field
->
name
,
&
position
);
/* column name alias */
if
(
send_buff
.
reserve
(
position
,
12
))
goto
err
;
send_buff
.
buffer
[
position
++
]
=
12
;
int2store
(
send_buff
.
buffer
+
position
,
1
);
/* charsetnr */
int4store
(
send_buff
.
buffer
+
position
+
2
,
field
->
length
);
/* field length */
send_buff
.
buffer
[
position
+
6
]
=
FIELD_TYPE_STRING
;
/* type */
int2store
(
send_buff
.
buffer
+
position
+
7
,
0
);
/* flags */
send_buff
.
buffer
[
position
+
9
]
=
(
char
)
0
;
/* decimals */
send_buff
.
buffer
[
position
+
10
]
=
0
;
send_buff
.
buffer
[
position
+
11
]
=
0
;
position
+=
12
;
if
(
my_net_write
(
net
,
send_buff
.
buffer
,
(
uint
)
position
+
1
))
goto
err
;
tmp
=
rest
(
tmp
);
}
if
(
my_net_write
(
net
,
eof_buff
,
1
))
goto
err
;
return
0
;
err:
return
1
;
}
server-tools/instance-manager/protocol.h
0 → 100644
View file @
fd94614f
#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_PROTOCOL_H
#define INCLUDES_MYSQL_INSTANCE_MANAGER_PROTOCOL_H
/* Copyright (C) 2003 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 */
#include "buffer.h"
#include <my_list.h>
typedef
struct
field
{
char
*
name
;
uint
length
;
}
NAME_WITH_LENGTH
;
struct
st_net
;
int
net_send_ok
(
struct
st_net
*
net
,
unsigned
long
connection_id
);
int
net_send_error
(
struct
st_net
*
net
,
unsigned
sql_errno
);
int
net_send_error_323
(
struct
st_net
*
net
,
unsigned
sql_errno
);
int
send_fields
(
struct
st_net
*
net
,
LIST
*
fields
);
char
*
net_store_length
(
char
*
pkg
,
uint
length
);
int
store_to_string
(
Buffer
*
buf
,
const
char
*
string
,
uint
*
position
);
int
send_eof
(
struct
st_net
*
net
);
#endif
/* INCLUDES_MYSQL_INSTANCE_MANAGER_PROTOCOL_H */
server-tools/instance-manager/thread_registry.cc
0 → 100644
View file @
fd94614f
/* Copyright (C) 2003 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_registry.h"
#include <assert.h>
#include <signal.h>
#include <thr_alarm.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_registry
::
Thread_registry
()
:
shutdown_in_progress
(
false
)
,
sigwait_thread_pid
(
pthread_self
())
{
pthread_mutex_init
(
&
LOCK_thread_registry
,
0
);
pthread_cond_init
(
&
COND_thread_registry_is_empty
,
0
);
/* head is used by-value to simplify nodes inserting */
head
.
next
=
head
.
prev
=
&
head
;
}
Thread_registry
::~
Thread_registry
()
{
/* Check that no one uses the repository. */
pthread_mutex_lock
(
&
LOCK_thread_registry
);
/* All threads must unregister */
DBUG_ASSERT
(
head
.
next
==
&
head
);
pthread_mutex_unlock
(
&
LOCK_thread_registry
);
pthread_cond_destroy
(
&
COND_thread_registry_is_empty
);
pthread_mutex_destroy
(
&
LOCK_thread_registry
);
}
/*
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_registry
::
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_registry
);
info
->
next
=
&
head
;
info
->
prev
=
head
.
prev
;
head
.
prev
->
next
=
info
;
head
.
prev
=
info
;
pthread_mutex_unlock
(
&
LOCK_thread_registry
);
}
/*
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_registry
::
unregister_thread
(
Thread_info
*
info
)
{
pthread_mutex_lock
(
&
LOCK_thread_registry
);
info
->
prev
->
next
=
info
->
next
;
info
->
next
->
prev
=
info
->
prev
;
if
(
head
.
next
==
&
head
)
pthread_cond_signal
(
&
COND_thread_registry_is_empty
);
pthread_mutex_unlock
(
&
LOCK_thread_registry
);
}
/*
Check whether shutdown is in progress, and if yes, return immediately.
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_registry
::
cond_wait
(
Thread_info
*
info
,
pthread_cond_t
*
cond
,
pthread_mutex_t
*
mutex
,
bool
*
is_shutdown
)
{
pthread_mutex_lock
(
&
LOCK_thread_registry
);
*
is_shutdown
=
shutdown_in_progress
;
if
(
*
is_shutdown
)
{
pthread_mutex_unlock
(
&
LOCK_thread_registry
);
return
0
;
}
info
->
current_cond
=
cond
;
pthread_mutex_unlock
(
&
LOCK_thread_registry
);
/* sic: race condition here, cond can be signaled in deliver_shutdown */
int
rc
=
pthread_cond_wait
(
cond
,
mutex
);
pthread_mutex_lock
(
&
LOCK_thread_registry
);
info
->
current_cond
=
0
;
*
is_shutdown
=
shutdown_in_progress
;
pthread_mutex_unlock
(
&
LOCK_thread_registry
);
return
rc
;
}
/*
Deliver shutdown message to the workers crew.
As it's impossible to avoid all race conditions, signal latecomers
again.
*/
void
Thread_registry
::
deliver_shutdown
()
{
struct
timespec
shutdown_time
;
set_timespec
(
shutdown_time
,
1
);
pthread_mutex_lock
(
&
LOCK_thread_registry
);
shutdown_in_progress
=
true
;
/* to stop reading from the network we need to flush alarm queue */
end_thr_alarm
(
0
);
/*
We have to deliver final alarms this way, as the main thread has already
stopped alarm processing.
*/
process_alarm
(
THR_SERVER_ALARM
);
for
(
Thread_info
*
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
);
}
/*
The common practice is to test predicate before pthread_cond_wait.
I don't do that here because the predicate is practically always false
before wait - is_shutdown's been just set, and the lock's still not
released - the only case when the predicate is false is when no other
threads exist.
*/
while
(
pthread_cond_timedwait
(
&
COND_thread_registry_is_empty
,
&
LOCK_thread_registry
,
&
shutdown_time
)
!=
ETIMEDOUT
&&
head
.
next
!=
&
head
)
;
/*
If previous signals did not reach some threads, they must be sleeping
in pthread_cond_wait or in 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
(
Thread_info
*
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_registry
);
}
void
Thread_registry
::
request_shutdown
()
{
pthread_kill
(
sigwait_thread_pid
,
SIGTERM
);
}
server-tools/instance-manager/thread_registry.h
0 → 100644
View file @
fd94614f
#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_THREAD_REGISTRY_H
#define INCLUDES_MYSQL_INSTANCE_MANAGER_THREAD_REGISTRY_H
/* 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_registry
;
public:
Thread_info
(
pthread_t
thread_id_arg
)
:
thread_id
(
thread_id_arg
)
{}
};
/*
Thread_registry - contains handles for each worker thread to deliver
signal information to workers.
*/
class
Thread_registry
{
public:
Thread_registry
();
~
Thread_registry
();
void
register_thread
(
Thread_info
*
info
);
void
unregister_thread
(
Thread_info
*
info
);
void
deliver_shutdown
();
void
request_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_registry
;
pthread_cond_t
COND_thread_registry_is_empty
;
pid_t
sigwait_thread_pid
;
};
inline
bool
Thread_registry
::
is_shutdown
()
{
pthread_mutex_lock
(
&
LOCK_thread_registry
);
bool
res
=
shutdown_in_progress
;
pthread_mutex_unlock
(
&
LOCK_thread_registry
);
return
res
;
}
#endif
/* INCLUDES_MYSQL_INSTANCE_MANAGER_THREAD_REGISTRY_H */
server-tools/instance-manager/user_map.cc
0 → 100644
View file @
fd94614f
/* Copyright (C) 2003 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 interface
#endif
#include "user_map.h"
#include <mysql_com.h>
#include <m_string.h>
#include "log.h"
struct
User
{
char
user
[
USERNAME_LENGTH
+
1
];
uint8
user_length
;
uint8
salt
[
SCRAMBLE_LENGTH
];
int
init
(
const
char
*
line
);
};
int
User
::
init
(
const
char
*
line
)
{
const
char
*
name_begin
,
*
name_end
,
*
password
;
if
(
line
[
0
]
==
'\''
||
line
[
0
]
==
'"'
)
{
name_begin
=
line
+
1
;
name_end
=
strchr
(
name_begin
,
line
[
0
]);
if
(
name_end
==
0
||
name_end
[
1
]
!=
':'
)
goto
err
;
password
=
name_end
+
2
;
}
else
{
name_begin
=
line
;
name_end
=
strchr
(
name_begin
,
':'
);
if
(
name_end
==
0
)
goto
err
;
password
=
name_end
+
1
;
}
user_length
=
name_end
-
name_begin
;
if
(
user_length
>
USERNAME_LENGTH
)
goto
err
;
/* assume that newline characater is present */
if
(
strlen
(
password
)
!=
SCRAMBLED_PASSWORD_CHAR_LENGTH
+
1
)
goto
err
;
memcpy
(
user
,
name_begin
,
user_length
);
user
[
user_length
]
=
0
;
get_salt_from_password
(
salt
,
password
);
log_info
(
"loaded user %s"
,
user
);
return
0
;
err:
log_error
(
"error parsing user and password at line %d"
,
line
);
return
1
;
}
C_MODE_START
static
byte
*
get_user_key
(
const
byte
*
u
,
uint
*
len
,
my_bool
__attribute__
((
unused
))
t
)
{
const
User
*
user
=
(
const
User
*
)
u
;
*
len
=
user
->
user_length
;
return
(
byte
*
)
user
->
user
;
}
static
void
delete_user
(
void
*
u
)
{
User
*
user
=
(
User
*
)
u
;
delete
user
;
}
C_MODE_END
int
User_map
::
init
()
{
enum
{
START_HASH_SIZE
=
16
};
if
(
hash_init
(
&
hash
,
default_charset_info
,
START_HASH_SIZE
,
0
,
0
,
get_user_key
,
delete_user
,
0
))
return
1
;
return
0
;
}
User_map
::~
User_map
()
{
hash_free
(
&
hash
);
}
/*
Load all users from the password file. Must be called once right after
construction.
In case of failure, puts error message to the log file and returns 1
*/
int
User_map
::
load
(
const
char
*
password_file_name
)
{
FILE
*
file
;
char
line
[
USERNAME_LENGTH
+
SCRAMBLED_PASSWORD_CHAR_LENGTH
+
2
+
/* for possible quotes */
1
+
/* for ':' */
1
+
/* for newline */
1
];
/* for trailing zero */
uint
line_length
;
User
*
user
;
int
rc
=
1
;
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
,
errno
,
strerror
(
errno
));
return
1
;
}
while
(
fgets
(
line
,
sizeof
(
line
),
file
))
{
/* skip comments and empty lines */
if
(
line
[
0
]
==
'#'
||
line
[
0
]
==
'\n'
&&
(
line
[
1
]
==
'\0'
||
line
[
1
]
==
'\r'
))
continue
;
if
((
user
=
new
User
)
==
0
)
goto
done
;
if
(
user
->
init
(
line
)
||
my_hash_insert
(
&
hash
,
(
byte
*
)
user
))
goto
err_init_user
;
}
if
(
feof
(
file
))
rc
=
0
;
goto
done
;
err_init_user:
delete
user
;
done:
my_fclose
(
file
,
MYF
(
0
));
return
rc
;
}
/*
Check if user exists and password is correct
RETURN VALUE
0 - user found and password OK
1 - password mismatch
2 - user not found
*/
int
User_map
::
authenticate
(
const
char
*
user_name
,
uint
length
,
const
char
*
scrambled_password
,
const
char
*
scramble
)
const
{
const
User
*
user
=
(
const
User
*
)
hash_search
((
HASH
*
)
&
hash
,
(
byte
*
)
user_name
,
length
);
if
(
user
)
return
check_scramble
(
scrambled_password
,
scramble
,
user
->
salt
);
return
2
;
}
server-tools/instance-manager/user_map.h
0 → 100644
View file @
fd94614f
#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_USER_MAP_H
#define INCLUDES_MYSQL_INSTANCE_MANAGER_USER_MAP_H
/* Copyright (C) 2003 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 interface
#endif
#include <my_global.h>
#include <my_sys.h>
#include <hash.h>
/*
User_map -- all users and passwords
*/
class
User_map
{
public:
~
User_map
();
int
init
();
int
load
(
const
char
*
password_file_name
);
int
authenticate
(
const
char
*
user_name
,
uint
length
,
const
char
*
scrambled_password
,
const
char
*
scramble
)
const
;
private:
HASH
hash
;
};
#endif // INCLUDES_MYSQL_INSTANCE_MANAGER_USER_MAP_H
sql/net_serv.cc
View file @
fd94614f
...
...
@@ -72,7 +72,7 @@
/* The following is because alarms doesn't work on windows. */
#define NO_ALARM
#endif
#ifndef NO_ALARM
#include "my_pthread.h"
void
sql_print_error
(
const
char
*
format
,...);
...
...
@@ -83,7 +83,6 @@ void sql_print_error(const char *format,...);
#include "thr_alarm.h"
#ifdef MYSQL_SERVER
#define USE_QUERY_CACHE
/*
The following variables/functions should really not be declared
extern, but as it's hard to include mysql_priv.h here, we have to
...
...
@@ -92,9 +91,14 @@ void sql_print_error(const char *format,...);
extern
uint
test_flags
;
extern
ulong
bytes_sent
,
bytes_received
,
net_big_packet_count
;
extern
pthread_mutex_t
LOCK_bytes_sent
,
LOCK_bytes_received
;
#ifndef MYSQL_INSTANCE_MANAGER
extern
void
query_cache_insert
(
NET
*
net
,
const
char
*
packet
,
ulong
length
);
#define USE_QUERY_CACHE
#define update_statistics(A) A
#else
#endif
/* MYSQL_INSTANCE_MANGER */
#endif
/* defined(MYSQL_SERVER) && !defined(MYSQL_INSTANCE_MANAGER) */
#if !defined(MYSQL_SERVER) || defined(MYSQL_INSTANCE_MANAGER)
#define update_statistics(A)
#define thd_increment_bytes_sent(N)
#endif
...
...
@@ -443,7 +447,8 @@ net_real_write(NET *net,const char *packet,ulong len)
my_bool
net_blocking
=
vio_is_blocking
(
net
->
vio
);
DBUG_ENTER
(
"net_real_write"
);
#if defined(MYSQL_SERVER) && defined(HAVE_QUERY_CACHE)
#if defined(MYSQL_SERVER) && defined(HAVE_QUERY_CACHE) \
&& !defined(MYSQL_INSTANCE_MANAGER)
if
(
net
->
query_cache_query
!=
0
)
query_cache_insert
(
net
,
packet
,
len
);
#endif
...
...
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