1
0
mirror of https://github.com/MariaDB/server.git synced 2025-06-12 01:53:02 +03:00

MWL#192: Non-blocking client API for libmysqlclient.

All client functions that can block on I/O have alternate _start() and
_cont() versions that do not block but return control back to the
application, which can then issue I/O wait in its own fashion and later
call back into the library to continue the operation.

Works behind the scenes by spawning a co-routine/fiber to run the
blocking operation and suspend it while waiting for I/O. This
co-routine/fiber use is invisible to applications.

For i368/x86_64 on GCC, uses very fast assembler co-routine support. On
Windows uses native Win32 Fibers. Falls back to POSIX ucontext on other
platforms. Assembler routines for more platforms are relatively easy to
add by extending mysys/my_context.c, eg. similar to the Lua lcoco
library.

For testing, mysqltest and mysql_client_test are extended with the
option --non-blocking-api. This causes the programs to use the
non-blocking API for database access. mysql-test-run.pl has a similar
option --non-blocking-api that uses this, as well as additional
testcases.

An example program tests/async_queries.c is included that uses the new
non-blocking API with libevent to show how, in a single-threaded
program, to issue many queries in parallel against a database.


client/async_example.c:
  Fix const warning
  ******
  Fix bug with wrong timeout value for poll().
include/Makefile.am:
  Fix missing include for `make dist`
include/mysql.h:
  Add prototypes for all non-blocking API calls.
include/mysql.h.pp:
  Add prototypes for all non-blocking API calls.
mysys/my_context.c:
  Fix type warning for makecontext() function pointer argument.
sql-common/mysql_async.c:
  Fix crashes in the non-blocking API for functions that can take MYSQL argument
  that is NULL.
tests/Makefile.am:
  Add header file to `make dist`
tests/mysql_client_test.c:
  Replace blocking calls with wrappers around the non-blocking calls, used in
  mysql_client_test to test the new non-blocking API.
tests/nonblock-wrappers.h:
  Replace blocking calls with wrappers around the non-blocking calls, used in
  mysql_client_test to test the new non-blocking API.
This commit is contained in:
unknown
2011-09-20 12:49:25 +02:00
parent 1a344b87e4
commit a5b881594d
41 changed files with 4389 additions and 38 deletions

View File

@ -264,6 +264,8 @@ typedef struct character_set
struct st_mysql_methods;
struct st_mysql_stmt;
struct st_mysql_extension;
typedef struct st_mysql
{
NET net; /* Communication parameters */
@ -318,7 +320,7 @@ typedef struct st_mysql
my_bool *unbuffered_fetch_owner;
/* needed for embedded server - no net buffer to store the 'info' */
char *info_buffer;
void *extension;
struct st_mysql_extension *extension;
} MYSQL;
@ -376,6 +378,19 @@ typedef struct st_mysql_parameters
void *extension;
} MYSQL_PARAMETERS;
/*
Flag bits, the asynchronous methods return a combination of these ORed
together to let the application know when to resume the suspended operation.
*/
typedef enum {
MYSQL_WAIT_READ= 1, /* Wait for data to be available on socket to read */
/* mysql_get_socket_fd() will return socket descriptor*/
MYSQL_WAIT_WRITE= 2, /* Wait for socket to be ready to write data */
MYSQL_WAIT_EXCEPT= 4, /* Wait for select() to mark exception on socket */
MYSQL_WAIT_TIMEOUT= 8 /* Wait until timeout occurs. Value of timeout can be */
/* obtained from mysql_get_timeout_value() */
} MYSQL_ASYNC_STATUS;
#if !defined(MYSQL_SERVER) && !defined(EMBEDDED_LIBRARY)
#define max_allowed_packet (*mysql_get_parameters()->p_max_allowed_packet)
#define net_buffer_length (*mysql_get_parameters()->p_net_buffer_length)
@ -437,6 +452,10 @@ const char * STDCALL mysql_info(MYSQL *mysql);
unsigned long STDCALL mysql_thread_id(MYSQL *mysql);
const char * STDCALL mysql_character_set_name(MYSQL *mysql);
int STDCALL mysql_set_character_set(MYSQL *mysql, const char *csname);
int STDCALL mysql_set_character_set_start(int *ret, MYSQL *mysql,
const char *csname);
int STDCALL mysql_set_character_set_cont(int *ret, MYSQL *mysql,
int status);
MYSQL * STDCALL mysql_init(MYSQL *mysql);
my_bool STDCALL mysql_ssl_set(MYSQL *mysql, const char *key,
@ -445,6 +464,12 @@ my_bool STDCALL mysql_ssl_set(MYSQL *mysql, const char *key,
const char * STDCALL mysql_get_ssl_cipher(MYSQL *mysql);
my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user,
const char *passwd, const char *db);
int STDCALL mysql_change_user_start(my_bool *ret, MYSQL *mysql,
const char *user,
const char *passwd,
const char *db);
int STDCALL mysql_change_user_cont(my_bool *ret, MYSQL *mysql,
int status);
MYSQL * STDCALL mysql_real_connect(MYSQL *mysql, const char *host,
const char *user,
const char *passwd,
@ -452,13 +477,44 @@ MYSQL * STDCALL mysql_real_connect(MYSQL *mysql, const char *host,
unsigned int port,
const char *unix_socket,
unsigned long clientflag);
int STDCALL mysql_real_connect_start(MYSQL **ret, MYSQL *mysql,
const char *host,
const char *user,
const char *passwd,
const char *db,
unsigned int port,
const char *unix_socket,
unsigned long clientflag);
int STDCALL mysql_real_connect_cont(MYSQL **ret, MYSQL *mysql,
int status);
int STDCALL mysql_select_db(MYSQL *mysql, const char *db);
int STDCALL mysql_select_db_start(int *ret, MYSQL *mysql,
const char *db);
int STDCALL mysql_select_db_cont(int *ret, MYSQL *mysql,
int status);
int STDCALL mysql_query(MYSQL *mysql, const char *q);
int STDCALL mysql_query_start(int *ret, MYSQL *mysql,
const char *q);
int STDCALL mysql_query_cont(int *ret, MYSQL *mysql,
int status);
int STDCALL mysql_send_query(MYSQL *mysql, const char *q,
unsigned long length);
int STDCALL mysql_send_query_start(int *ret, MYSQL *mysql,
const char *q,
unsigned long length);
int STDCALL mysql_send_query_cont(int *ret, MYSQL *mysql,
int status);
int STDCALL mysql_real_query(MYSQL *mysql, const char *q,
unsigned long length);
int STDCALL mysql_real_query_start(int *ret, MYSQL *mysql,
const char *q,
unsigned long length);
int STDCALL mysql_real_query_cont(int *ret, MYSQL *mysql,
int status);
MYSQL_RES * STDCALL mysql_store_result(MYSQL *mysql);
int STDCALL mysql_store_result_start(MYSQL_RES **ret, MYSQL *mysql);
int STDCALL mysql_store_result_cont(MYSQL_RES **ret, MYSQL *mysql,
int status);
MYSQL_RES * STDCALL mysql_use_result(MYSQL *mysql);
/* perform query on master */
@ -526,15 +582,39 @@ int STDCALL mysql_add_slave(MYSQL* mysql, const char* host,
int STDCALL mysql_shutdown(MYSQL *mysql,
enum mysql_enum_shutdown_level
shutdown_level);
int STDCALL mysql_shutdown_start(int *ret, MYSQL *mysql,
enum mysql_enum_shutdown_level
shutdown_level);
int STDCALL mysql_shutdown_cont(int *ret, MYSQL *mysql,
int status);
int STDCALL mysql_dump_debug_info(MYSQL *mysql);
int STDCALL mysql_dump_debug_info_start(int *ret, MYSQL *mysql);
int STDCALL mysql_dump_debug_info_cont(int *ret, MYSQL *mysql,
int status);
int STDCALL mysql_refresh(MYSQL *mysql,
unsigned int refresh_options);
int STDCALL mysql_refresh_start(int *ret, MYSQL *mysql,
unsigned int refresh_options);
int STDCALL mysql_refresh_cont(int *ret, MYSQL *mysql, int status);
int STDCALL mysql_kill(MYSQL *mysql,unsigned long pid);
int STDCALL mysql_kill_start(int *ret, MYSQL *mysql,
unsigned long pid);
int STDCALL mysql_kill_cont(int *ret, MYSQL *mysql, int status);
int STDCALL mysql_set_server_option(MYSQL *mysql,
enum enum_mysql_set_option
option);
int STDCALL mysql_set_server_option_start(int *ret, MYSQL *mysql,
enum enum_mysql_set_option
option);
int STDCALL mysql_set_server_option_cont(int *ret, MYSQL *mysql,
int status);
int STDCALL mysql_ping(MYSQL *mysql);
int STDCALL mysql_ping_start(int *ret, MYSQL *mysql);
int STDCALL mysql_ping_cont(int *ret, MYSQL *mysql, int status);
const char * STDCALL mysql_stat(MYSQL *mysql);
int STDCALL mysql_stat_start(const char **ret, MYSQL *mysql);
int STDCALL mysql_stat_cont(const char **ret, MYSQL *mysql,
int status);
const char * STDCALL mysql_get_server_info(MYSQL *mysql);
const char * STDCALL mysql_get_server_name(MYSQL *mysql);
const char * STDCALL mysql_get_client_info(void);
@ -543,11 +623,25 @@ const char * STDCALL mysql_get_host_info(MYSQL *mysql);
unsigned long STDCALL mysql_get_server_version(MYSQL *mysql);
unsigned int STDCALL mysql_get_proto_info(MYSQL *mysql);
MYSQL_RES * STDCALL mysql_list_dbs(MYSQL *mysql,const char *wild);
int STDCALL mysql_list_dbs_start(MYSQL_RES **ret, MYSQL *mysql,
const char *wild);
int STDCALL mysql_list_dbs_cont(MYSQL_RES **ret, MYSQL *mysql,
int status);
MYSQL_RES * STDCALL mysql_list_tables(MYSQL *mysql,const char *wild);
int STDCALL mysql_list_tables_start(MYSQL_RES **ret, MYSQL *mysql,
const char *wild);
int STDCALL mysql_list_tables_cont(MYSQL_RES **ret, MYSQL *mysql,
int status);
MYSQL_RES * STDCALL mysql_list_processes(MYSQL *mysql);
int STDCALL mysql_list_processes_start(MYSQL_RES **ret,
MYSQL *mysql);
int STDCALL mysql_list_processes_cont(MYSQL_RES **ret, MYSQL *mysql,
int status);
int STDCALL mysql_options(MYSQL *mysql,enum mysql_option option,
const void *arg);
void STDCALL mysql_free_result(MYSQL_RES *result);
int STDCALL mysql_free_result_start(MYSQL_RES *result);
int STDCALL mysql_free_result_cont(MYSQL_RES *result, int status);
void STDCALL mysql_data_seek(MYSQL_RES *result,
my_ulonglong offset);
MYSQL_ROW_OFFSET STDCALL mysql_row_seek(MYSQL_RES *result,
@ -555,10 +649,19 @@ MYSQL_ROW_OFFSET STDCALL mysql_row_seek(MYSQL_RES *result,
MYSQL_FIELD_OFFSET STDCALL mysql_field_seek(MYSQL_RES *result,
MYSQL_FIELD_OFFSET offset);
MYSQL_ROW STDCALL mysql_fetch_row(MYSQL_RES *result);
int STDCALL mysql_fetch_row_start(MYSQL_ROW *ret,
MYSQL_RES *result);
int STDCALL mysql_fetch_row_cont(MYSQL_ROW *ret, MYSQL_RES *result,
int status);
unsigned long * STDCALL mysql_fetch_lengths(MYSQL_RES *result);
MYSQL_FIELD * STDCALL mysql_fetch_field(MYSQL_RES *result);
MYSQL_RES * STDCALL mysql_list_fields(MYSQL *mysql, const char *table,
const char *wild);
int STDCALL mysql_list_fields_start(MYSQL_RES **ret, MYSQL *mysql,
const char *table,
const char *wild);
int STDCALL mysql_list_fields_cont(MYSQL_RES **ret, MYSQL *mysql,
int status);
unsigned long STDCALL mysql_escape_string(char *to,const char *from,
unsigned long from_length);
unsigned long STDCALL mysql_hex_string(char *to,const char *from,
@ -584,6 +687,10 @@ int STDCALL mysql_manager_fetch_line(MYSQL_MANAGER* con,
char* res_buf,
int res_buf_size);
my_bool STDCALL mysql_read_query_result(MYSQL *mysql);
int STDCALL mysql_read_query_result_start(my_bool *ret,
MYSQL *mysql);
int STDCALL mysql_read_query_result_cont(my_bool *ret,
MYSQL *mysql, int status);
/*
@ -760,16 +867,25 @@ enum enum_stmt_attr_type
STMT_ATTR_PREFETCH_ROWS
};
MYSQL_STMT * STDCALL mysql_stmt_init(MYSQL *mysql);
int STDCALL mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query,
unsigned long length);
int STDCALL mysql_stmt_prepare_start(int *ret, MYSQL_STMT *stmt,
const char *query, unsigned long length);
int STDCALL mysql_stmt_prepare_cont(int *ret, MYSQL_STMT *stmt, int status);
int STDCALL mysql_stmt_execute(MYSQL_STMT *stmt);
int STDCALL mysql_stmt_execute_start(int *ret, MYSQL_STMT *stmt);
int STDCALL mysql_stmt_execute_cont(int *ret, MYSQL_STMT *stmt, int status);
int STDCALL mysql_stmt_fetch(MYSQL_STMT *stmt);
int STDCALL mysql_stmt_fetch_start(int *ret, MYSQL_STMT *stmt);
int STDCALL mysql_stmt_fetch_cont(int *ret, MYSQL_STMT *stmt, int status);
int STDCALL mysql_stmt_fetch_column(MYSQL_STMT *stmt, MYSQL_BIND *bind_arg,
unsigned int column,
unsigned long offset);
int STDCALL mysql_stmt_store_result(MYSQL_STMT *stmt);
int STDCALL mysql_stmt_store_result_start(int *ret, MYSQL_STMT *stmt);
int STDCALL mysql_stmt_store_result_cont(int *ret, MYSQL_STMT *stmt,
int status);
unsigned long STDCALL mysql_stmt_param_count(MYSQL_STMT * stmt);
my_bool STDCALL mysql_stmt_attr_set(MYSQL_STMT *stmt,
enum enum_stmt_attr_type attr_type,
@ -780,12 +896,25 @@ my_bool STDCALL mysql_stmt_attr_get(MYSQL_STMT *stmt,
my_bool STDCALL mysql_stmt_bind_param(MYSQL_STMT * stmt, MYSQL_BIND * bnd);
my_bool STDCALL mysql_stmt_bind_result(MYSQL_STMT * stmt, MYSQL_BIND * bnd);
my_bool STDCALL mysql_stmt_close(MYSQL_STMT * stmt);
int STDCALL mysql_stmt_close_start(my_bool *ret, MYSQL_STMT *stmt);
int STDCALL mysql_stmt_close_cont(my_bool *ret, MYSQL_STMT * stmt, int status);
my_bool STDCALL mysql_stmt_reset(MYSQL_STMT * stmt);
int STDCALL mysql_stmt_reset_start(my_bool *ret, MYSQL_STMT * stmt);
int STDCALL mysql_stmt_reset_cont(my_bool *ret, MYSQL_STMT *stmt, int status);
my_bool STDCALL mysql_stmt_free_result(MYSQL_STMT *stmt);
int STDCALL mysql_stmt_free_result_start(my_bool *ret, MYSQL_STMT *stmt);
int STDCALL mysql_stmt_free_result_cont(my_bool *ret, MYSQL_STMT *stmt,
int status);
my_bool STDCALL mysql_stmt_send_long_data(MYSQL_STMT *stmt,
unsigned int param_number,
const char *data,
unsigned long length);
int STDCALL mysql_stmt_send_long_data_start(my_bool *ret, MYSQL_STMT *stmt,
unsigned int param_number,
const char *data,
unsigned long len);
int STDCALL mysql_stmt_send_long_data_cont(my_bool *ret, MYSQL_STMT *stmt,
int status);
MYSQL_RES *STDCALL mysql_stmt_result_metadata(MYSQL_STMT *stmt);
MYSQL_RES *STDCALL mysql_stmt_param_metadata(MYSQL_STMT *stmt);
unsigned int STDCALL mysql_stmt_errno(MYSQL_STMT * stmt);
@ -801,12 +930,24 @@ my_ulonglong STDCALL mysql_stmt_insert_id(MYSQL_STMT *stmt);
unsigned int STDCALL mysql_stmt_field_count(MYSQL_STMT *stmt);
my_bool STDCALL mysql_commit(MYSQL * mysql);
int STDCALL mysql_commit_start(my_bool *ret, MYSQL * mysql);
int STDCALL mysql_commit_cont(my_bool *ret, MYSQL * mysql, int status);
my_bool STDCALL mysql_rollback(MYSQL * mysql);
int STDCALL mysql_rollback_start(my_bool *ret, MYSQL * mysql);
int STDCALL mysql_rollback_cont(my_bool *ret, MYSQL * mysql, int status);
my_bool STDCALL mysql_autocommit(MYSQL * mysql, my_bool auto_mode);
int STDCALL mysql_autocommit_start(my_bool *ret, MYSQL * mysql,
my_bool auto_mode);
int STDCALL mysql_autocommit_cont(my_bool *ret, MYSQL * mysql, int status);
my_bool STDCALL mysql_more_results(MYSQL *mysql);
int STDCALL mysql_next_result(MYSQL *mysql);
int STDCALL mysql_next_result_start(int *ret, MYSQL *mysql);
int STDCALL mysql_next_result_cont(int *ret, MYSQL *mysql, int status);
void STDCALL mysql_close(MYSQL *sock);
int STDCALL mysql_close_start(MYSQL *sock);
int STDCALL mysql_close_cont(MYSQL *sock, int status);
my_socket STDCALL mysql_get_socket(const MYSQL *mysql);
unsigned int STDCALL mysql_get_timeout_value(const MYSQL *mysql);
/* status return codes */
#define MYSQL_NO_DATA 100
@ -817,7 +958,20 @@ void STDCALL mysql_close(MYSQL *sock);
#ifdef USE_OLD_FUNCTIONS
MYSQL * STDCALL mysql_connect(MYSQL *mysql, const char *host,
const char *user, const char *passwd);
int STDCALL mysql_connect_start(MYSQL **ret, MYSQL *mysql,
const char *host, const char *user,
const char *passwd);
int STDCALL mysql_connect_cont(MYSQL **ret, MYSQL *mysql,
int status);
int STDCALL mysql_create_db(MYSQL *mysql, const char *DB);
int STDCALL mysql_create_db_start(int *ret, MYSQL *mysql,
const char *DB);
int STDCALL mysql_create_db_cont(int *ret, MYSQL *mysql,
int status);
int STDCALL mysql_drop_db(MYSQL *mysql, const char *DB);
int STDCALL mysql_drop_db_start(int *ret, MYSQL *mysql,
const char *DB);
int STDCALL mysql_drop_db_cont(int *ret, MYSQL *mysql, int status);
int STDCALL mysql_drop_db(MYSQL *mysql, const char *DB);
#define mysql_reload(mysql) mysql_refresh((mysql),REFRESH_GRANT)
#endif