How to Make a Threaded Client
-----------------------------
have your
own alarm that can break a long read to a server. If you install
interrupt handlers for the `SIGPIPE' interrupt, the socket handling
should be thread-safe.
own
`SIGPIPE' handler, you should first call `mysql_server_init()' and then
install your handler. In older versions of MySQL `SIGPIPE' was blocked,
but only in the thread safe client library, for every call to
`mysql_init()'.
In the older binaries we distribute on our web site
(`http://www.mysql.com/'), the client libraries are not normally
compiled with the thread-safe option (the Windows binaries are by
default compiled to be thread-safe). Newer binary distributions should
have both a normal and a thread-safe client library.
To get a threaded client where you can interrupt the client from other
threads and set timeouts when talking with the MySQL server, you should
use the `-lmysys', `-lmystrings', and `-ldbug' libraries and the
`net_serv.o' code that the server uses.
If you don't need interrupts or timeouts, you can just compile a
thread-safe client library `(mysqlclient_r)' and use this. *Note MySQL
C API: C. In this case you don't have to worry about the `net_serv.o'
object file or the other MySQL libraries.
When using a threaded client and you want to use timeouts and
interrupts, you can make great use of the routines in the `thr_alarm.c'
file. If you are using routines from the `mysys' library, the only
thing you must remember is to call `my_init()' first! *Note C Thread
functions::.
All functions except `mysql_real_connect()' are by default thread-safe.
The following notes describe how to compile a thread-safe client
library and use it in a thread-safe manner. (The notes below for
`mysql_real_connect()' actually apply to `mysql_connect()' as well, but
because `mysql_connect()' is deprecated, you should be using
`mysql_real_connect()' anyway.)
To make `mysql_real_connect()' thread-safe, you must recompile the
client library with this command:
shell> ./configure --enable-thread-safe-client
This will create a thread-safe client library `libmysqlclient_r'.
(Assuming your OS has a thread-safe `gethostbyname_r()' function.)
This library is thread-safe per connection. You can let two threads
share the same connection with the following caveats:
other
thread is using the same connection.
* Many threads can access different result sets that are retrieved
with `mysql_store_result()'.
the same
connection to use `mysql_store_result()'.
* If you want to use multiple threads on the same connection, you
must have a mutex lock around your `mysql_query()' and
`mysql_store_result()' call combination. Once
`mysql_store_result()' is ready, the lock can be released and other
threads may query the same connection.
* If you program with POSIX threads, you can use
`pthread_mutex_lock()' and `pthread_mutex_unlock()' to establish
and release a mutex lock.
You need to know the following if you have a thread that is calling
MySQL functions which did not create the connection to the MySQL
database:
When you call `mysql_init()' or `mysql_connect()', MySQL will create a
thread-specific variable for the thread that is used by the debug
library (among other things).
If you call a MySQL function, before the thread has called
`mysql_init()' or `mysql_connect()', the thread will not have the
necessary thread-specific variables in place and you are likely to end
up with a core dump sooner or later.
The get things to work smoothly you have to do the following:
1. Call `my_init()' at the start of your program if it calls any
other MySQL function before calling `mysql_real_connect()'.
2. Call `mysql_thread_init()' in the thread handler before calling
any MySQL function.
3. In the thread, call `mysql_thread_end()' before calling
`pthread_exit()'. This will free the memory used by MySQL
thread-specific variables.
You may get some errors because of undefined symbols when linking your
client with `libmysqlclient_r'. In most cases this is because you
haven't included the thread libraries on the link/compile line.
libmysqld, the Embedded MySQL Server Library
--------------------------------------------
Overview of the Embedded MySQL Server Library
.............................................
The embedded server library is based on the client/server version of
MySQL, which is written in C/C++. Consequently, the embedded server also
is written in C/C++. There is no embedded server available in other
languages.
The API is identical for the embedded MySQL version and the
client/server version. To change an old threaded application to use the
embedded library, you normally only have to add calls to the following
functions:
*Function* *When to call*
`mysql_server_init()'Should be called before any other MySQL function
is called, preferably early in the `main()'
function.
`mysql_server_end()'Should be called before your program exits.
`mysql_thread_init()'Should be called in each thread you create that
will access MySQL.
`mysql_thread_end()'Should be called before calling `pthread_exit()'
Then you must link your code with `libmysqld.a' instead of
`libmysqlclient.a'.
The above `mysql_server_xxx' functions are also included in
`libmysqlclient.a' to allow you to change between the embedded and the
client/server version by just linking your application with the right
library. *Note `mysql_server_init()': mysql_server_init.
Compiling Programs with `libmysqld'
...................................
To get a `libmysqld' library you should configure MySQL with the
`--with-embedded-server' option.
`mysql_config --libmysqld-libs'.
The correct flags for compiling and linking a threaded program must be
used, even if you do not directly call any thread functions in your
code.
Restrictions when using the Embedded MySQL Server
.................................................
The embedded server has the following limitations:
* No support for ISAM tables. (This is mainly done to make the
library smaller)
* No user defined functions (UDFs).
* No stack trace on core dump.
* No internal RAID support. (This is not normally needed as most OS
has nowadays support for big files).
* You cannot set this up as a server or a master (no replication).
* You can't connect to the embedded server from an outside process
with sockets or TCP/IP.
Some of these limitations can be changed by editing the `mysql_embed.h'
include file and recompiling MySQL.
Using Option Files with the Embedded Server
...........................................
The following is the recommended way to use option files to make it easy
to switch between a client/server application and one where MySQL is
embedded. *Note Option files::.
* Put common options in the `[server]' section. These will be read by
both MySQL versions.
* Put client/server-specific options in the `[mysqld]' section.
* Put embedded MySQL-specific options in the `[embedded]' section.
* Put application-specific options in a `[ApplicationName_SERVER]'
section.
Things left to do in Embedded Server (TODO)
...........................................
* We are going to provide options to leave out some parts of MySQL
to make the library smaller.
* There is still a lot of speed optimisation to do.
* Errors are written to `stderr'. We will add an option to specify a
filename for these.
* We have to change `InnoDB' to not be so verbose when using in the
embedded version.
A Simple Embedded Server Example
................................
to
understand the problem, without the clutter that is a necessary part of
a real application.
To try out the example, create an `test_libmysqld' directory at the
same level as the mysql-4.0 source directory. Save the
`test_libmysqld.c' source and the `GNUmakefile' in the directory, and
run GNU `make' from inside the `test_libmysqld' directory.
`test_libmysqld.c'
/*
* A simple example client, using the embedded MySQL server library
*/
#include
#include
#include
#include
MYSQL *db_connect(const char *dbname);
void db_disconnect(MYSQL *db);
void db_do_query(MYSQL *db, const char *query);
const char *server_groups[] = {
"test_libmysqld_SERVER", "embedded", "server", NULL
};
int
main(int argc, char **argv)
{
MYSQL *one, *two;
groups = {
* "server", "embedded", NULL
* }.
*
* In your $HOME/.my.cnf file, you probably want to put:
[test_libmysqld_SERVER]
language = /path/to/source/of/mysql/sql/share/english
* argv[0], which is the program name) should be valid options
* for the MySQL server.
*
* If you link this client against the normal mysqlclient
* library, this function is just a stub that does nothing.
*/
mysql_server_init(argc, argv, (char **)server_groups);
one = db_connect("test");
two = db_connect(NULL);
db_do_query(one, "SHOW TABLE STATUS");
db_do_query(two, "SHOW DATABASES");
mysql_close(two);
mysql_close(one);
/* This must be called after all other mysql functions */
mysql_server_end();
exit(EXIT_SUCCESS);
}
static void
die(MYSQL *db, char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
(void)putc('\n', stderr);
if (db)
db_disconnect(db);
exit(EXIT_FAILURE);
}
MYSQL *
db_connect(const char *dbname)
{
MYSQL *db = mysql_init(NULL);
if (!db)
die(db, "mysql_init failed: no memory");
/*
* Notice that the client and server use separate group names.
* This is critical, because the server will not accept the
* client's options, and vice versa.
*/
mysql_options(db, MYSQL_READ_DEFAULT_GROUP, "test_libmysqld_CLIENT");
if (!mysql_real_connect(db, NULL, NULL, NULL, dbname, 0, NULL, 0))
die(db, "mysql_real_connect failed: %s", mysql_error(db));
return db;
}
void
db_disconnect(MYSQL *db)
{
mysql_close(db);
}
void
db_do_query(MYSQL *db, const char *query)
{
if (mysql_query(db, query) != 0)
goto err;
if (mysql_field_count(db) > 0)
{
MYSQL_RES *res;
MYSQL_ROW row, end_row;
int num_fields;
if (!(res = mysql_store_result(db)))
goto err;
num_fields = mysql_num_fields(res);
while ((row = mysql_fetch_row(res)))
{
(void)fputs(">> ", stdout);
for (end_row = row + num_fields; row < end_row; ++row)
(void)printf("%s\t", row ? (char*)*row : "NULL");
(void)fputc('\n', stdout);
}
(void)fputc('\n', stdout);
mysql_free_result(res);
}
else
(void)printf("Affected rows: %lld\n", mysql_affected_rows(db));
return;
err:
die(db, "db_do_query failed: %s [%s]", mysql_error(db), query);
}
`GNUmakefile'
# This assumes the MySQL software is installed in /usr/local/mysql
inc := /usr/local/mysql/include/mysql
lib := /usr/local/mysql/lib
# If you have not installed the MySQL software yet, try this instead
#inc := $(HOME)/mysql-4.0/include
#lib := $(HOME)/mysql-4.0/libmysqld
CC := gcc
CPPFLAGS := -I$(inc) -D_THREAD_SAFE -D_REENTRANT
CFLAGS := -g -W -Wall
LDFLAGS := -static
# You can change -lmysqld to -lmysqlclient to use the
# client/server library
LDLIBS = -L$(lib) -lmysqld -lz -lm -lcrypt
ifneq (,$(shell grep FreeBSD /COPYRIGHT 2>/dev/null))
# FreeBSD
LDFLAGS += -pthread
else
# Assume Linux
LDLIBS += -lpthread
endif
# This works for simple one-file test programs
sources := $(wildcard *.c)
objects := $(patsubst %c,%o,$(sources))
targets := $(basename $(sources))
all: $(targets)
clean:
rm -f $(targets) $(objects) *.core
Licensing the Embedded Server
.............................
The MySQL source code is covered by the GNU `GPL' license (*note GPL
license::). One result of this is that any program which includes, by
linking with `libmysqld', the MySQL source code must be released as
free software (under a license compatible with the `GPL').
We encourage everyone to promote free software by releasing code under
the `GPL' or a compatible license. For those who are not able to do
this, another option is to purchase a commercial license for the MySQL
code from MySQL AB. For details, please see *Note MySQL licenses::.
[Назад] [Содержание] [Вперед]
| Главная |