1
0
mirror of https://github.com/MariaDB/server.git synced 2025-08-08 11:22:35 +03:00

merge from latest 5.5

This commit is contained in:
Guilhem Bichot
2011-05-21 10:59:32 +02:00
60 changed files with 1090 additions and 342 deletions

View File

@@ -293,7 +293,8 @@ extended_usage()
version string suffix: [none] version string suffix: [none]
All packages except Classic include support for user-defined All packages except Classic include support for user-defined
partitioning. partitioning. All packages include support for Performance
Schema.
If --with-debug is used, an additional "-debug" is appended to the If --with-debug is used, an additional "-debug" is appended to the
version string. version string.

View File

@@ -140,6 +140,14 @@ struct my_aligned_storage
#endif /* __cplusplus */ #endif /* __cplusplus */
# ifndef MY_ALIGNED
/*
Make sure MY_ALIGNED can be used also on platforms where we don't
have a way of aligning data structures.
*/
#define MY_ALIGNED(size)
#endif
#include <my_attribute.h> #include <my_attribute.h>
#endif /* MY_COMPILER_INCLUDED */ #endif /* MY_COMPILER_INCLUDED */

View File

@@ -627,6 +627,8 @@ extern FILE *my_freopen(const char *path, const char *mode, FILE *stream);
extern int my_fclose(FILE *fd,myf MyFlags); extern int my_fclose(FILE *fd,myf MyFlags);
extern File my_fileno(FILE *fd); extern File my_fileno(FILE *fd);
extern int my_chsize(File fd,my_off_t newlength, int filler, myf MyFlags); extern int my_chsize(File fd,my_off_t newlength, int filler, myf MyFlags);
extern void thr_set_sync_wait_callback(void (*before_sync)(void),
void (*after_sync)(void));
extern int my_sync(File fd, myf my_flags); extern int my_sync(File fd, myf my_flags);
extern int my_sync_dir(const char *dir_name, myf my_flags); extern int my_sync_dir(const char *dir_name, myf my_flags);
extern int my_sync_dir_by_file(const char *file_name, myf my_flags); extern int my_sync_dir_by_file(const char *file_name, myf my_flags);

View File

@@ -33,16 +33,23 @@ MYSQL_LEX_STRING *thd_make_lex_string(void* thd, MYSQL_LEX_STRING *lex_str,
int allocate_lex_string); int allocate_lex_string);
#include <mysql/service_thd_wait.h> #include <mysql/service_thd_wait.h>
typedef enum _thd_wait_type_e { typedef enum _thd_wait_type_e {
THD_WAIT_MUTEX= 1, THD_WAIT_SLEEP= 1,
THD_WAIT_DISKIO= 2, THD_WAIT_DISKIO= 2,
THD_WAIT_ROW_TABLE_LOCK= 3, THD_WAIT_ROW_LOCK= 3,
THD_WAIT_GLOBAL_LOCK= 4 THD_WAIT_GLOBAL_LOCK= 4,
THD_WAIT_META_DATA_LOCK= 5,
THD_WAIT_TABLE_LOCK= 6,
THD_WAIT_USER_LOCK= 7,
THD_WAIT_BINLOG= 8,
THD_WAIT_GROUP_COMMIT= 9,
THD_WAIT_SYNC= 10,
THD_WAIT_LAST= 11
} thd_wait_type; } thd_wait_type;
extern struct thd_wait_service_st { extern struct thd_wait_service_st {
void (*thd_wait_begin_func)(void*, thd_wait_type); void (*thd_wait_begin_func)(void*, int);
void (*thd_wait_end_func)(void*); void (*thd_wait_end_func)(void*);
} *thd_wait_service; } *thd_wait_service;
void thd_wait_begin(void* thd, thd_wait_type wait_type); void thd_wait_begin(void* thd, int wait_type);
void thd_wait_end(void* thd); void thd_wait_end(void* thd);
#include <mysql/service_thread_scheduler.h> #include <mysql/service_thread_scheduler.h>
struct scheduler_functions; struct scheduler_functions;

View File

@@ -33,16 +33,23 @@ MYSQL_LEX_STRING *thd_make_lex_string(void* thd, MYSQL_LEX_STRING *lex_str,
int allocate_lex_string); int allocate_lex_string);
#include <mysql/service_thd_wait.h> #include <mysql/service_thd_wait.h>
typedef enum _thd_wait_type_e { typedef enum _thd_wait_type_e {
THD_WAIT_MUTEX= 1, THD_WAIT_SLEEP= 1,
THD_WAIT_DISKIO= 2, THD_WAIT_DISKIO= 2,
THD_WAIT_ROW_TABLE_LOCK= 3, THD_WAIT_ROW_LOCK= 3,
THD_WAIT_GLOBAL_LOCK= 4 THD_WAIT_GLOBAL_LOCK= 4,
THD_WAIT_META_DATA_LOCK= 5,
THD_WAIT_TABLE_LOCK= 6,
THD_WAIT_USER_LOCK= 7,
THD_WAIT_BINLOG= 8,
THD_WAIT_GROUP_COMMIT= 9,
THD_WAIT_SYNC= 10,
THD_WAIT_LAST= 11
} thd_wait_type; } thd_wait_type;
extern struct thd_wait_service_st { extern struct thd_wait_service_st {
void (*thd_wait_begin_func)(void*, thd_wait_type); void (*thd_wait_begin_func)(void*, int);
void (*thd_wait_end_func)(void*); void (*thd_wait_end_func)(void*);
} *thd_wait_service; } *thd_wait_service;
void thd_wait_begin(void* thd, thd_wait_type wait_type); void thd_wait_begin(void* thd, int wait_type);
void thd_wait_end(void* thd); void thd_wait_end(void* thd);
#include <mysql/service_thread_scheduler.h> #include <mysql/service_thread_scheduler.h>
struct scheduler_functions; struct scheduler_functions;

View File

@@ -33,16 +33,23 @@ MYSQL_LEX_STRING *thd_make_lex_string(void* thd, MYSQL_LEX_STRING *lex_str,
int allocate_lex_string); int allocate_lex_string);
#include <mysql/service_thd_wait.h> #include <mysql/service_thd_wait.h>
typedef enum _thd_wait_type_e { typedef enum _thd_wait_type_e {
THD_WAIT_MUTEX= 1, THD_WAIT_SLEEP= 1,
THD_WAIT_DISKIO= 2, THD_WAIT_DISKIO= 2,
THD_WAIT_ROW_TABLE_LOCK= 3, THD_WAIT_ROW_LOCK= 3,
THD_WAIT_GLOBAL_LOCK= 4 THD_WAIT_GLOBAL_LOCK= 4,
THD_WAIT_META_DATA_LOCK= 5,
THD_WAIT_TABLE_LOCK= 6,
THD_WAIT_USER_LOCK= 7,
THD_WAIT_BINLOG= 8,
THD_WAIT_GROUP_COMMIT= 9,
THD_WAIT_SYNC= 10,
THD_WAIT_LAST= 11
} thd_wait_type; } thd_wait_type;
extern struct thd_wait_service_st { extern struct thd_wait_service_st {
void (*thd_wait_begin_func)(void*, thd_wait_type); void (*thd_wait_begin_func)(void*, int);
void (*thd_wait_end_func)(void*); void (*thd_wait_end_func)(void*);
} *thd_wait_service; } *thd_wait_service;
void thd_wait_begin(void* thd, thd_wait_type wait_type); void thd_wait_begin(void* thd, int wait_type);
void thd_wait_end(void* thd); void thd_wait_end(void* thd);
#include <mysql/service_thread_scheduler.h> #include <mysql/service_thread_scheduler.h>
struct scheduler_functions; struct scheduler_functions;

View File

@@ -50,15 +50,35 @@
extern "C" { extern "C" {
#endif #endif
/*
One should only report wait events that could potentially block for a
long time. A mutex wait is too short of an event to report. The reason
is that an event which is reported leads to a new thread starts
executing a query and this has a negative impact of usage of CPU caches
and thus the expected gain of starting a new thread must be higher than
the expected cost of lost performance due to starting a new thread.
Good examples of events that should be reported are waiting for row locks
that could easily be for many milliseconds or even seconds and the same
holds true for global read locks, table locks and other meta data locks.
Another event of interest is going to sleep for an extended time.
*/
typedef enum _thd_wait_type_e { typedef enum _thd_wait_type_e {
THD_WAIT_MUTEX= 1, THD_WAIT_SLEEP= 1,
THD_WAIT_DISKIO= 2, THD_WAIT_DISKIO= 2,
THD_WAIT_ROW_TABLE_LOCK= 3, THD_WAIT_ROW_LOCK= 3,
THD_WAIT_GLOBAL_LOCK= 4 THD_WAIT_GLOBAL_LOCK= 4,
THD_WAIT_META_DATA_LOCK= 5,
THD_WAIT_TABLE_LOCK= 6,
THD_WAIT_USER_LOCK= 7,
THD_WAIT_BINLOG= 8,
THD_WAIT_GROUP_COMMIT= 9,
THD_WAIT_SYNC= 10,
THD_WAIT_LAST= 11
} thd_wait_type; } thd_wait_type;
extern struct thd_wait_service_st { extern struct thd_wait_service_st {
void (*thd_wait_begin_func)(MYSQL_THD, thd_wait_type); void (*thd_wait_begin_func)(MYSQL_THD, int);
void (*thd_wait_end_func)(MYSQL_THD); void (*thd_wait_end_func)(MYSQL_THD);
} *thd_wait_service; } *thd_wait_service;
@@ -70,7 +90,7 @@ extern struct thd_wait_service_st {
#else #else
void thd_wait_begin(MYSQL_THD thd, thd_wait_type wait_type); void thd_wait_begin(MYSQL_THD thd, int wait_type);
void thd_wait_end(MYSQL_THD thd); void thd_wait_end(MYSQL_THD thd);
#endif #endif

View File

@@ -0,0 +1,119 @@
/*
Copyright (C) 2010, 2011 Oracle and/or its affiliates. All rights reserved.
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; version 2 of the License.
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
*/
#ifndef THREAD_POOL_PRIV_INCLUDED
#define THREAD_POOL_PRIV_INCLUDED
/*
The thread pool requires access to some MySQL server error codes, this is
accessed from mysqld_error.h.
We need access to the struct that defines the thread pool plugin interface
which is accessed through scheduler.h.
All accesses to THD variables and functions are defined in this header file.
A thread pool can also use DEBUG_SYNC and must thus include
debug_sync.h
To handle definitions of Information Schema plugins it is also required
to include sql_profile.h and table.h.
*/
#include <mysqld_error.h> /* To get ER_ERROR_ON_READ */
#define MYSQL_SERVER 1
#include <scheduler.h>
#include <debug_sync.h>
#include <sql_profile.h>
#include <table.h>
/* Needed to get access to scheduler variables */
void* thd_get_scheduler_data(THD *thd);
void thd_set_scheduler_data(THD *thd, void *data);
PSI_thread* thd_get_psi(THD *thd);
void thd_set_psi(THD *thd, PSI_thread *psi);
/* Interface to THD variables and functions */
void thd_set_killed(THD *thd);
void thd_clear_errors(THD *thd);
void thd_set_thread_stack(THD *thd, char *stack_start);
void thd_lock_thread_count(THD *thd);
void thd_unlock_thread_count(THD *thd);
void thd_close_connection(THD *thd);
THD *thd_get_current_thd();
void thd_new_connection_setup(THD *thd, char *stack_start);
void thd_lock_data(THD *thd);
void thd_unlock_data(THD *thd);
bool thd_is_transaction_active(THD *thd);
int thd_connection_has_data(THD *thd);
void thd_set_net_read_write(THD *thd, uint val);
void thd_set_mysys_var(THD *thd, st_my_thread_var *mysys_var);
my_socket thd_get_fd(THD *thd);
/* Print to the MySQL error log */
void sql_print_error(const char *format, ...);
/* Store a table record */
bool schema_table_store_record(THD *thd, TABLE *table);
/*
The thread pool must be able to execute statements using the connection
state in THD object. This is the main objective of the thread pool to
schedule the start of these commands.
*/
bool do_command(THD *thd);
/*
The thread pool requires an interface to the connection logic in the
MySQL Server since the thread pool will maintain the event logic on
the TCP connection of the MySQL Server. Thus new connections, dropped
connections will be discovered by the thread pool and it needs to
ensure that the proper MySQL Server logic attached to these events is
executed.
*/
/* Initialise a new connection handler thread */
bool init_new_connection_handler_thread();
/* Set up connection thread before use as execution thread */
bool setup_connection_thread_globals(THD *thd);
/* Prepare connection as part of connection set-up */
bool thd_prepare_connection(THD *thd);
/* Release auditing before executing statement */
void mysql_audit_release(THD *thd);
/* Check if connection is still alive */
bool thd_is_connection_alive(THD *thd);
/* Close connection with possible error code */
void close_connection(THD *thd, uint errcode);
/* End the connection before closing it */
void end_connection(THD *thd);
/* Decrement connection counter */
void dec_connection_count();
/* Destroy THD object */
void delete_thd(THD *thd);
/*
thread_created is maintained by thread pool when activated since
user threads are created by the thread pool (and also special
threads to maintain the thread pool). This is done through
inc_thread_created.
max_connections is needed to calculate the maximum number of threads
that is allowed to be started by the thread pool. The method
get_max_connections() gets reference to this variable.
connection_attrib is the thread attributes for connection threads,
the method get_connection_attrib provides a reference to these
attributes.
*/
void inc_thread_created(void);
ulong get_max_connections(void);
pthread_attr_t *get_connection_attrib(void);
#endif

View File

@@ -50,6 +50,23 @@ extern "C" void unireg_clear(int exit_code)
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
/*
Wrapper error handler for embedded server to call client/server error
handler based on whether thread is in client/server context
*/
static void embedded_error_handler(uint error, const char *str, myf MyFlags)
{
DBUG_ENTER("embedded_error_handler");
/*
If current_thd is NULL, it means restore_global has been called and
thread is in client context, then call client error handler else call
server error handler.
*/
DBUG_RETURN(current_thd ? my_message_sql(error, str, MyFlags):
my_message_stderr(error, str, MyFlags));
}
/* /*
Reads error information from the MYSQL_DATA and puts Reads error information from the MYSQL_DATA and puts
@@ -106,7 +123,8 @@ emb_advanced_command(MYSQL *mysql, enum enum_server_command command,
if (mysql->status != MYSQL_STATUS_READY) if (mysql->status != MYSQL_STATUS_READY)
{ {
set_mysql_error(mysql, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate); set_mysql_error(mysql, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate);
return 1; result= 1;
goto end;
} }
/* Clear result variables */ /* Clear result variables */
@@ -147,6 +165,9 @@ emb_advanced_command(MYSQL *mysql, enum enum_server_command command,
#if defined(ENABLED_PROFILING) #if defined(ENABLED_PROFILING)
thd->profiling.finish_current_query(); thd->profiling.finish_current_query();
#endif #endif
end:
thd->restore_globals();
return result; return result;
} }
@@ -545,7 +566,10 @@ int init_embedded_server(int argc, char **argv, char **groups)
return 1; return 1;
} }
error_handler_hook = my_message_sql; /*
set error_handler_hook to embedded_error_handler wrapper.
*/
error_handler_hook= embedded_error_handler;
acl_error= 0; acl_error= 0;
#ifndef NO_EMBEDDED_ACCESS_CHECKS #ifndef NO_EMBEDDED_ACCESS_CHECKS

View File

@@ -1,5 +1,10 @@
disable_query_log;
if (`select plugin_library IS NULL from information_schema.plugins where plugin_name LIKE '%archive%'`) if (`select plugin_library IS NULL from information_schema.plugins where plugin_name LIKE '%archive%'`)
{ {
--skip archive plugin not available --skip archive plugin not available
} }
if (`SELECT @@plugin_dir != '$ARCHIVE_PLUGIN_DIR'`) {
--skip Archive plugin requires that --plugin-dir is set to the archive plugin dir (either the .opt file does not contain \$ARCHIVE_PLUGIN_OPT or another plugin is in use)
}
enable_query_log;

View File

@@ -1,5 +1,11 @@
disable_query_log;
if (`select plugin_library IS NULL from information_schema.plugins where plugin_name LIKE '%blackhole%'`) if (`select plugin_library IS NULL from information_schema.plugins where plugin_name LIKE '%blackhole%'`)
{ {
--skip blackhole plugin not available; --skip blackhole plugin not available;
} }
if (`SELECT @@plugin_dir != '$BLACKHOLE_PLUGIN_DIR'`) {
--skip Blackhole plugin requires that --plugin-dir is set to the blackhole plugin dir (either the .opt file does not contain \$BLACKHOLE_PLUGIN_OPT or another plugin is in use)
}
enable_query_log;

View File

@@ -0,0 +1,5 @@
if (`SELECT count(*) FROM information_schema.GLOBAL_VARIABLES WHERE
VARIABLE_NAME = 'THREAD_HANDLING' AND
VARIABLE_VALUE = 'loaded-dynamically'`){
skip Test requires: 'not_threadpool';
}

View File

@@ -39,3 +39,4 @@ ha_archive storage/archive ARCHIVE_PLUGIN
ha_blackhole storage/blackhole BLACKHOLE_PLUGIN ha_blackhole storage/blackhole BLACKHOLE_PLUGIN
ha_federated storage/federated FEDERATED_PLUGIN ha_federated storage/federated FEDERATED_PLUGIN
mypluglib plugin/fulltext SIMPLE_PARSER mypluglib plugin/fulltext SIMPLE_PARSER
thread_pool plugin/thread_pool THREADPOOL_PLUGIN thread_pool,TP_THREAD_STATE,TP_THREAD_GROUP_STATE,TP_THREAD_GROUP_STATS

View File

@@ -1389,6 +1389,15 @@ NULL
SELECT DATE_FORMAT('0000-00-11', '%w'); SELECT DATE_FORMAT('0000-00-11', '%w');
DATE_FORMAT('0000-00-11', '%w') DATE_FORMAT('0000-00-11', '%w')
NULL NULL
#
# Bug#12403504 AFTER FIX FOR #11889186 : ASSERTION FAILED: DELSUM+(INT) Y/4-TEMP > 0
#
SELECT MAKEDATE(11111111,1);
MAKEDATE(11111111,1)
NULL
SELECT WEEK(DATE_ADD(FROM_DAYS(1),INTERVAL 1 MONTH), 1);
WEEK(DATE_ADD(FROM_DAYS(1),INTERVAL 1 MONTH), 1)
NULL
End of 5.1 tests End of 5.1 tests
# #
# Bug#57039: constant subtime expression returns incorrect result. # Bug#57039: constant subtime expression returns incorrect result.

View File

@@ -238,11 +238,5 @@ SELECT 9;
9 9
DROP PROCEDURE p1; DROP PROCEDURE p1;
DROP FUNCTION f1; DROP FUNCTION f1;
DROP VIEW IF EXISTS v1;
CREATE VIEW v1 AS SELECT VARIABLE_NAME AS NAME, CONVERT(VARIABLE_VALUE, UNSIGNED) AS VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS;
SELECT VALUE INTO @tc FROM v1 WHERE NAME = 'Threads_connected';
SELECT NAME FROM v1 WHERE NAME = 'Threads_created' AND VALUE < @tc;
NAME
DROP VIEW v1;
set @@global.concurrent_insert= @old_concurrent_insert; set @@global.concurrent_insert= @old_concurrent_insert;
SET GLOBAL log_output = @old_log_output; SET GLOBAL log_output = @old_log_output;

View File

@@ -0,0 +1,13 @@
set @old_concurrent_insert= @@global.concurrent_insert;
set @@global.concurrent_insert= 0;
SET @old_log_output = @@global.log_output;
SET GLOBAL LOG_OUTPUT = 'FILE';
flush status;
DROP VIEW IF EXISTS v1;
CREATE VIEW v1 AS SELECT VARIABLE_NAME AS NAME, CONVERT(VARIABLE_VALUE, UNSIGNED) AS VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS;
SELECT VALUE INTO @tc FROM v1 WHERE NAME = 'Threads_connected';
SELECT NAME FROM v1 WHERE NAME = 'Threads_created' AND VALUE < @tc;
NAME
DROP VIEW v1;
set @@global.concurrent_insert= @old_concurrent_insert;
SET GLOBAL log_output = @old_log_output;

View File

@@ -17,6 +17,7 @@
--source include/not_embedded.inc --source include/not_embedded.inc
--source include/have_perfschema.inc --source include/have_perfschema.inc
--source include/not_threadpool.inc
# Setup : in this main thread # Setup : in this main thread

View File

@@ -17,6 +17,7 @@
--source include/not_embedded.inc --source include/not_embedded.inc
--source include/have_perfschema.inc --source include/have_perfschema.inc
--source include/not_threadpool.inc
# Setup # Setup

View File

@@ -1,7 +1,6 @@
include/master-slave.inc include/master-slave.inc
[connection master] [connection master]
stop slave; include/stop_slave.inc
include/wait_for_slave_to_stop.inc
create table t1 (a int); create table t1 (a int);
drop table t1; drop table t1;
create table t1 (a int); create table t1 (a int);
@@ -9,10 +8,8 @@ drop table t1;
reset slave; reset slave;
start slave io_thread; start slave io_thread;
include/wait_for_slave_param.inc [Slave_IO_State] include/wait_for_slave_param.inc [Slave_IO_State]
stop slave io_thread; include/stop_slave_io.inc
reset slave; reset slave;
start slave; include/start_slave.inc
select master_pos_wait('master-bin.001',200,6)=-1; include/assert.inc [Assert that master_pos_wait does not timeout nor it returns NULL]
master_pos_wait('master-bin.001',200,6)=-1
0
include/rpl_end.inc include/rpl_end.inc

View File

@@ -2,9 +2,9 @@
# to force the deadlock after one event. # to force the deadlock after one event.
source include/master-slave.inc; source include/master-slave.inc;
--let $master_log_file= query_get_value(SHOW MASTER STATUS, File, 1)
connection slave; connection slave;
stop slave; --source include/stop_slave.inc
--source include/wait_for_slave_to_stop.inc
connection master; connection master;
# This will generate a master's binlog > 10 bytes # This will generate a master's binlog > 10 bytes
create table t1 (a int); create table t1 (a int);
@@ -20,20 +20,33 @@ let $slave_param_value= Waiting for the slave SQL thread to free enough relay lo
source include/wait_for_slave_param.inc; source include/wait_for_slave_param.inc;
# A bug caused the I/O thread to refuse stopping. # A bug caused the I/O thread to refuse stopping.
stop slave io_thread; --source include/stop_slave_io.inc
reset slave; reset slave;
start slave; --source include/start_slave.inc
# The I/O thread stops filling the relay log when
# it's >10b. And the SQL thread cannot purge this relay log # The I/O thread stops filling the relay log when it's >10b. And the
# as purge is done only when the SQL thread switches to another # SQL thread cannot purge this relay log as purge is done only when
# relay log, which does not exist here. # the SQL thread switches to another relay log, which does not exist
# So we should have a deadlock. # here. So we should have a deadlock. If it is not resolved
# if it is not resolved automatically we'll detect # automatically we'll detect it with master_pos_wait that waits for
# it with master_pos_wait that waits for farther than 1Ob; # farther than 1Ob; it will timeout after 300 seconds (which is inline
# it will timeout after 10 seconds; # with the default used for sync_slave_with_master and will protect us
# also the slave will probably not cooperate to shutdown # against slow test envs); also the slave will probably not cooperate
# (as 2 threads are locked) # to shutdown (as 2 threads are locked)
select master_pos_wait('master-bin.001',200,6)=-1; --let $outcome= `SELECT MASTER_POS_WAIT('$master_log_file',200,300) AS mpw;`
# master_pos_wait returns:
#
# * >= 0, the number of events the slave had to wait to advance to the
# position
#
# * -1, if there was a timeout
#
# * NULL, if an error occurred, or the SQL thread was not started,
# slave master info is not initialized, the arguments are incorrect
--let $assert_text= Assert that master_pos_wait does not timeout nor it returns NULL
--let $assert_cond= $outcome IS NOT NULL AND $outcome <> -1
--source include/assert.inc
# End of 4.1 tests # End of 4.1 tests
--source include/rpl_end.inc --source include/rpl_end.inc

View File

@@ -14,6 +14,7 @@
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
--source include/not_embedded.inc --source include/not_embedded.inc
--source include/not_threadpool.inc
# 2010-01-28 OBN Added support to load 'innodb' and 'semisync' if possible. # 2010-01-28 OBN Added support to load 'innodb' and 'semisync' if possible.
# As we need to have there variables loaded if the components exist but do # As we need to have there variables loaded if the components exist but do

View File

@@ -31,6 +31,7 @@
# #
--source include/not_embedded.inc --source include/not_embedded.inc
--source include/not_threadpool.inc
SET @global_slow_launch_time = @@GLOBAL.slow_launch_time; SET @global_slow_launch_time = @@GLOBAL.slow_launch_time;

View File

@@ -28,6 +28,7 @@
# #
--source include/not_embedded.inc --source include/not_embedded.inc
--source include/not_threadpool.inc
SET @global_thread_cache_size = @@GLOBAL.thread_cache_size; SET @global_thread_cache_size = @@GLOBAL.thread_cache_size;

View File

@@ -22,6 +22,7 @@
############################################################################### ###############################################################################
--source include/not_embedded.inc --source include/not_embedded.inc
--source include/not_threadpool.inc
SET @start_value= @@global.wait_timeout; SET @start_value= @@global.wait_timeout;

View File

@@ -902,6 +902,13 @@ SELECT DATE_FORMAT('0000-00-11', '%W');
SELECT DATE_FORMAT('0000-00-11', '%a'); SELECT DATE_FORMAT('0000-00-11', '%a');
SELECT DATE_FORMAT('0000-00-11', '%w'); SELECT DATE_FORMAT('0000-00-11', '%w');
--echo #
--echo # Bug#12403504 AFTER FIX FOR #11889186 : ASSERTION FAILED: DELSUM+(INT) Y/4-TEMP > 0
--echo #
SELECT MAKEDATE(11111111,1);
SELECT WEEK(DATE_ADD(FROM_DAYS(1),INTERVAL 1 MONTH), 1);
--echo End of 5.1 tests --echo End of 5.1 tests
--echo # --echo #

View File

@@ -1,6 +1,9 @@
# This test uses grants, which can't get tested for embedded server # This test uses grants, which can't get tested for embedded server
-- source include/not_embedded.inc -- source include/not_embedded.inc
#Don't run this test when thread_pool active
--source include/not_threadpool.inc
# check that CSV engine was compiled in, as the result of the test depends # check that CSV engine was compiled in, as the result of the test depends
# on the presence of the log tables (which are CSV-based). # on the presence of the log tables (which are CSV-based).
--source include/have_csv.inc --source include/have_csv.inc

View File

@@ -2,6 +2,9 @@
# in the embedded server by default). So skip the test in embedded-server mode. # in the embedded server by default). So skip the test in embedded-server mode.
-- source include/not_embedded.inc -- source include/not_embedded.inc
#Don't run this test when thread_pool active
--source include/not_threadpool.inc
-- source include/testdb_only.inc -- source include/testdb_only.inc
--disable_warnings --disable_warnings

View File

@@ -9,6 +9,7 @@
-- source include/not_embedded.inc -- source include/not_embedded.inc
-- source include/have_debug_sync.inc -- source include/have_debug_sync.inc
-- source include/not_threadpool.inc
--disable_warnings --disable_warnings
SET DEBUG_SYNC = 'RESET'; SET DEBUG_SYNC = 'RESET';

View File

@@ -2,6 +2,8 @@
-- source include/not_embedded.inc -- source include/not_embedded.inc
# Test lists tables in Information_schema, and InnoDB adds some # Test lists tables in Information_schema, and InnoDB adds some
-- source include/have_innodb.inc -- source include/have_innodb.inc
# Don't test when thread_pool active
--source include/not_threadpool.inc
--disable_warnings --disable_warnings
DROP TABLE IF EXISTS t1,t2,test1,test2; DROP TABLE IF EXISTS t1,t2,test1,test2;

View File

@@ -3,6 +3,9 @@
# other platforms # other platforms
--source include/windows.inc --source include/windows.inc
# thread pool causes different results
-- source include/not_threadpool.inc
# Only run this test if named pipe is avaliable # Only run this test if named pipe is avaliable
let $nmp= query_get_value("SHOW VARIABLES LIKE 'named_pipe'", Value, 1); let $nmp= query_get_value("SHOW VARIABLES LIKE 'named_pipe'", Value, 1);
if ($nmp != ON){ if ($nmp != ON){

View File

@@ -1,3 +1,4 @@
--source include/not_threadpool.inc
# #
# Test the --thread-handler=no-threads option # Test the --thread-handler=no-threads option
# #

View File

@@ -2,6 +2,9 @@
# to optimize things we skip this test on all other platforms # to optimize things we skip this test on all other platforms
--source include/windows.inc --source include/windows.inc
# thread pool causes different results
-- source include/not_threadpool.inc
# Only run this test if shared memory is avaliable # Only run this test if shared memory is avaliable
let $shm= query_get_value("SHOW VARIABLES LIKE 'shared_memory'", Value, 1); let $shm= query_get_value("SHOW VARIABLES LIKE 'shared_memory'", Value, 1);
if ($shm != ON){ if ($shm != ON){

View File

@@ -354,21 +354,6 @@ DROP FUNCTION f1;
# End of 5.1 tests # End of 5.1 tests
#
# Bug#17954 Threads_connected > Threads_created
#
--disable_warnings
DROP VIEW IF EXISTS v1;
--enable_warnings
CREATE VIEW v1 AS SELECT VARIABLE_NAME AS NAME, CONVERT(VARIABLE_VALUE, UNSIGNED) AS VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS;
SELECT VALUE INTO @tc FROM v1 WHERE NAME = 'Threads_connected';
SELECT NAME FROM v1 WHERE NAME = 'Threads_created' AND VALUE < @tc;
DROP VIEW v1;
# Restore global concurrent_insert value. Keep in the end of the test file. # Restore global concurrent_insert value. Keep in the end of the test file.
--connection default --connection default
set @@global.concurrent_insert= @old_concurrent_insert; set @@global.concurrent_insert= @old_concurrent_insert;

View File

@@ -0,0 +1,54 @@
# This test requires that --log-output includes 'table', and the general
# log is on
# embedded server causes different stat
-- source include/not_embedded.inc
# thread pool causes different results
-- source include/not_threadpool.inc
# Save the initial number of concurrent sessions
--source include/count_sessions.inc
# Disable concurrent inserts to avoid sporadic test failures as it might
# affect the the value of variables used throughout the test case.
set @old_concurrent_insert= @@global.concurrent_insert;
set @@global.concurrent_insert= 0;
# Disable logging to table, since this will also cause table locking and unlocking, which will
# show up in SHOW STATUS and may cause sporadic failures
SET @old_log_output = @@global.log_output;
SET GLOBAL LOG_OUTPUT = 'FILE';
# PS causes different statistics
--disable_ps_protocol
flush status;
#
# Bug#17954 Threads_connected > Threads_created
#
--disable_warnings
DROP VIEW IF EXISTS v1;
--enable_warnings
CREATE VIEW v1 AS SELECT VARIABLE_NAME AS NAME, CONVERT(VARIABLE_VALUE, UNSIGNED) AS VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS;
SELECT VALUE INTO @tc FROM v1 WHERE NAME = 'Threads_connected';
SELECT NAME FROM v1 WHERE NAME = 'Threads_created' AND VALUE < @tc;
#SELECT * FROM INFORMATION_SCHEMA.GLOBAL_STATUS where variable_name like '%thread%';
#SELECT * FROM INFORMATION_SCHEMA.GLOBAL_STATUS;
#SELECT * FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES;
DROP VIEW v1;
# Restore global concurrent_insert value. Keep in the end of the test file.
--connection default
set @@global.concurrent_insert= @old_concurrent_insert;
SET GLOBAL log_output = @old_log_output;
# Wait till we reached the initial number of concurrent sessions
--source include/wait_until_count_sessions.inc

View File

@@ -146,6 +146,7 @@ void lf_pinbox_destroy(LF_PINBOX *pinbox)
*/ */
LF_PINS *_lf_pinbox_get_pins(LF_PINBOX *pinbox) LF_PINS *_lf_pinbox_get_pins(LF_PINBOX *pinbox)
{ {
struct st_my_thread_var *var;
uint32 pins, next, top_ver; uint32 pins, next, top_ver;
LF_PINS *el; LF_PINS *el;
/* /*
@@ -188,7 +189,12 @@ LF_PINS *_lf_pinbox_get_pins(LF_PINBOX *pinbox)
el->link= pins; el->link= pins;
el->purgatory_count= 0; el->purgatory_count= 0;
el->pinbox= pinbox; el->pinbox= pinbox;
el->stack_ends_here= & my_thread_var->stack_ends_here; var= my_thread_var;
/*
Threads that do not call my_thread_init() should still be
able to use the LF_HASH.
*/
el->stack_ends_here= (var ? & var->stack_ends_here : NULL);
return el; return el;
} }
@@ -327,34 +333,36 @@ static int match_pins(LF_PINS *el, void *addr)
*/ */
static void _lf_pinbox_real_free(LF_PINS *pins) static void _lf_pinbox_real_free(LF_PINS *pins)
{ {
int npins, alloca_size; int npins;
void *list, **addr; void *list;
void **addr= NULL;
void *first= NULL, *last= NULL; void *first= NULL, *last= NULL;
LF_PINBOX *pinbox= pins->pinbox; LF_PINBOX *pinbox= pins->pinbox;
npins= pinbox->pins_in_array+1; npins= pinbox->pins_in_array+1;
#ifdef HAVE_ALLOCA #ifdef HAVE_ALLOCA
alloca_size= sizeof(void *)*LF_PINBOX_PINS*npins; if (pins->stack_ends_here != NULL)
/* create a sorted list of pinned addresses, to speed up searches */
if (available_stack_size(&pinbox, *pins->stack_ends_here) > alloca_size)
{ {
struct st_harvester hv; int alloca_size= sizeof(void *)*LF_PINBOX_PINS*npins;
addr= (void **) alloca(alloca_size); /* create a sorted list of pinned addresses, to speed up searches */
hv.granary= addr; if (available_stack_size(&pinbox, *pins->stack_ends_here) > alloca_size)
hv.npins= npins; {
/* scan the dynarray and accumulate all pinned addresses */ struct st_harvester hv;
_lf_dynarray_iterate(&pinbox->pinarray, addr= (void **) alloca(alloca_size);
(lf_dynarray_func)harvest_pins, &hv); hv.granary= addr;
hv.npins= npins;
/* scan the dynarray and accumulate all pinned addresses */
_lf_dynarray_iterate(&pinbox->pinarray,
(lf_dynarray_func)harvest_pins, &hv);
npins= hv.granary-addr; npins= hv.granary-addr;
/* and sort them */ /* and sort them */
if (npins) if (npins)
qsort(addr, npins, sizeof(void *), (qsort_cmp)ptr_cmp); qsort(addr, npins, sizeof(void *), (qsort_cmp)ptr_cmp);
}
} }
else
#endif #endif
addr= 0;
list= pins->purgatory; list= pins->purgatory;
pins->purgatory= 0; pins->purgatory= 0;

View File

@@ -17,6 +17,16 @@
#include "mysys_err.h" #include "mysys_err.h"
#include <errno.h> #include <errno.h>
static void (*before_sync_wait)(void)= 0;
static void (*after_sync_wait)(void)= 0;
void thr_set_sync_wait_callback(void (*before_wait)(void),
void (*after_wait)(void))
{
before_sync_wait= before_wait;
after_sync_wait= after_wait;
}
/* /*
Sync data in file to disk Sync data in file to disk
@@ -46,6 +56,8 @@ int my_sync(File fd, myf my_flags)
DBUG_ENTER("my_sync"); DBUG_ENTER("my_sync");
DBUG_PRINT("my",("Fd: %d my_flags: %d", fd, my_flags)); DBUG_PRINT("my",("Fd: %d my_flags: %d", fd, my_flags));
if (before_sync_wait)
(*before_sync_wait)();
do do
{ {
#if defined(F_FULLFSYNC) #if defined(F_FULLFSYNC)
@@ -75,6 +87,8 @@ int my_sync(File fd, myf my_flags)
int er= errno; int er= errno;
if (!(my_errno= er)) if (!(my_errno= er))
my_errno= -1; /* Unknown error */ my_errno= -1; /* Unknown error */
if (after_sync_wait)
(*after_sync_wait)();
if ((my_flags & MY_IGNORE_BADFD) && if ((my_flags & MY_IGNORE_BADFD) &&
(er == EBADF || er == EINVAL || er == EROFS)) (er == EBADF || er == EINVAL || er == EROFS))
{ {
@@ -84,6 +98,11 @@ int my_sync(File fd, myf my_flags)
else if (my_flags & MY_WME) else if (my_flags & MY_WME)
my_error(EE_SYNC, MYF(ME_BELL+ME_WAITTANG), my_filename(fd), my_errno); my_error(EE_SYNC, MYF(ME_BELL+ME_WAITTANG), my_filename(fd), my_errno);
} }
else
{
if (after_sync_wait)
(*after_sync_wait)();
}
DBUG_RETURN(res); DBUG_RETURN(res);
} /* my_sync */ } /* my_sync */

View File

@@ -1745,11 +1745,20 @@ static void debug_sync_execute(THD *thd, st_debug_sync_action *action)
We don't use enter_cond()/exit_cond(). They do not save old We don't use enter_cond()/exit_cond(). They do not save old
mutex and cond. This would prohibit the use of DEBUG_SYNC mutex and cond. This would prohibit the use of DEBUG_SYNC
between other places of enter_cond() and exit_cond(). between other places of enter_cond() and exit_cond().
We need to check for existence of thd->mysys_var to also make
it possible to use DEBUG_SYNC framework in scheduler when this
variable has been set to NULL.
*/ */
old_mutex= thd->mysys_var->current_mutex; if (thd->mysys_var)
old_cond= thd->mysys_var->current_cond; {
thd->mysys_var->current_mutex= &debug_sync_global.ds_mutex; old_mutex= thd->mysys_var->current_mutex;
thd->mysys_var->current_cond= &debug_sync_global.ds_cond; old_cond= thd->mysys_var->current_cond;
thd->mysys_var->current_mutex= &debug_sync_global.ds_mutex;
thd->mysys_var->current_cond= &debug_sync_global.ds_cond;
}
else
old_mutex= NULL;
set_timespec(abstime, action->timeout); set_timespec(abstime, action->timeout);
DBUG_EXECUTE("debug_sync_exec", { DBUG_EXECUTE("debug_sync_exec", {
@@ -1804,11 +1813,16 @@ static void debug_sync_execute(THD *thd, st_debug_sync_action *action)
is locked. (See comment in THD::exit_cond().) is locked. (See comment in THD::exit_cond().)
*/ */
mysql_mutex_unlock(&debug_sync_global.ds_mutex); mysql_mutex_unlock(&debug_sync_global.ds_mutex);
mysql_mutex_lock(&thd->mysys_var->mutex); if (old_mutex)
thd->mysys_var->current_mutex= old_mutex; {
thd->mysys_var->current_cond= old_cond; mysql_mutex_lock(&thd->mysys_var->mutex);
thd_proc_info(thd, old_proc_info); thd->mysys_var->current_mutex= old_mutex;
mysql_mutex_unlock(&thd->mysys_var->mutex); thd->mysys_var->current_cond= old_cond;
thd_proc_info(thd, old_proc_info);
mysql_mutex_unlock(&thd->mysys_var->mutex);
}
else
thd_proc_info(thd, old_proc_info);
} }
else else
{ {

View File

@@ -39,7 +39,7 @@ class THD;
} while (0) } while (0)
/* Command line option --debug-sync-timeout. See mysqld.cc. */ /* Command line option --debug-sync-timeout. See mysqld.cc. */
extern uint opt_debug_sync_timeout; extern MYSQL_PLUGIN_IMPORT uint opt_debug_sync_timeout;
/* Default WAIT_FOR timeout if command line option is given without argument. */ /* Default WAIT_FOR timeout if command line option is given without argument. */
#define DEBUG_SYNC_DEFAULT_WAIT_TIMEOUT 300 #define DEBUG_SYNC_DEFAULT_WAIT_TIMEOUT 300

View File

@@ -51,6 +51,8 @@
#include "sp.h" #include "sp.h"
#include "set_var.h" #include "set_var.h"
#include "debug_sync.h" #include "debug_sync.h"
#include <mysql/plugin.h>
#include <mysql/service_thd_wait.h>
#ifdef NO_EMBEDDED_ACCESS_CHECKS #ifdef NO_EMBEDDED_ACCESS_CHECKS
#define sp_restore_security_context(A,B) while (0) {} #define sp_restore_security_context(A,B) while (0) {}
@@ -3889,6 +3891,7 @@ longlong Item_func_get_lock::val_int()
timed_cond.set_timeout(timeout * ULL(1000000000)); timed_cond.set_timeout(timeout * ULL(1000000000));
error= 0; error= 0;
thd_wait_begin(thd, THD_WAIT_USER_LOCK);
while (ull->locked && !thd->killed) while (ull->locked && !thd->killed)
{ {
DBUG_PRINT("info", ("waiting on lock")); DBUG_PRINT("info", ("waiting on lock"));
@@ -3900,6 +3903,7 @@ longlong Item_func_get_lock::val_int()
} }
error= 0; error= 0;
} }
thd_wait_end(thd);
if (ull->locked) if (ull->locked)
{ {
@@ -4117,6 +4121,7 @@ longlong Item_func_sleep::val_int()
thd->mysys_var->current_cond= &cond; thd->mysys_var->current_cond= &cond;
error= 0; error= 0;
thd_wait_begin(thd, THD_WAIT_SLEEP);
while (!thd->killed) while (!thd->killed)
{ {
error= timed_cond.wait(&cond, &LOCK_user_locks); error= timed_cond.wait(&cond, &LOCK_user_locks);
@@ -4124,6 +4129,7 @@ longlong Item_func_sleep::val_int()
break; break;
error= 0; error= 0;
} }
thd_wait_end(thd);
thd_proc_info(thd, 0); thd_proc_info(thd, 0);
mysql_mutex_unlock(&LOCK_user_locks); mysql_mutex_unlock(&LOCK_user_locks);
mysql_mutex_lock(&thd->mysys_var->mutex); mysql_mutex_lock(&thd->mysys_var->mutex);

View File

@@ -1591,6 +1591,11 @@ bool Item_func_from_days::get_date(MYSQL_TIME *ltime, uint fuzzy_date)
return 1; return 1;
bzero(ltime, sizeof(MYSQL_TIME)); bzero(ltime, sizeof(MYSQL_TIME));
get_date_from_daynr((long) value, &ltime->year, &ltime->month, &ltime->day); get_date_from_daynr((long) value, &ltime->year, &ltime->month, &ltime->day);
if ((null_value= (fuzzy_date & TIME_NO_ZERO_DATE) &&
(ltime->year == 0 || ltime->month == 0 || ltime->day == 0)))
return TRUE;
ltime->time_type= MYSQL_TIMESTAMP_DATE; ltime->time_type= MYSQL_TIMESTAMP_DATE;
return 0; return 0;
} }
@@ -2779,7 +2784,7 @@ String *Item_func_makedate::val_str(String *str)
long days; long days;
if (args[0]->null_value || args[1]->null_value || if (args[0]->null_value || args[1]->null_value ||
year < 0 || daynr <= 0) year < 0 || year > 9999 || daynr <= 0)
goto err; goto err;
if (year < 100) if (year < 100)
@@ -2822,7 +2827,7 @@ longlong Item_func_makedate::val_int()
long days; long days;
if (args[0]->null_value || args[1]->null_value || if (args[0]->null_value || args[1]->null_value ||
year < 0 || daynr <= 0) year < 0 || year > 9999 || daynr <= 0)
goto err; goto err;
if (year < 100) if (year < 100)

View File

@@ -5993,7 +5993,7 @@ int TC_LOG_MMAP::open(const char *opt_name)
{ {
pg->next=pg+1; pg->next=pg+1;
pg->waiters=0; pg->waiters=0;
pg->state=POOL; pg->state=PS_POOL;
mysql_mutex_init(key_PAGE_lock, &pg->lock, MY_MUTEX_INIT_FAST); mysql_mutex_init(key_PAGE_lock, &pg->lock, MY_MUTEX_INIT_FAST);
mysql_cond_init(key_PAGE_cond, &pg->cond, 0); mysql_cond_init(key_PAGE_cond, &pg->cond, 0);
pg->start=(my_xid *)(data + i*tc_log_page_size); pg->start=(my_xid *)(data + i*tc_log_page_size);
@@ -6167,7 +6167,7 @@ int TC_LOG_MMAP::log_xid(THD *thd, my_xid xid)
cookie= (ulong)((uchar *)p->ptr - data); // can never be zero cookie= (ulong)((uchar *)p->ptr - data); // can never be zero
*p->ptr++= xid; *p->ptr++= xid;
p->free--; p->free--;
p->state= DIRTY; p->state= PS_DIRTY;
/* to sync or not to sync - this is the question */ /* to sync or not to sync - this is the question */
mysql_mutex_unlock(&LOCK_active); mysql_mutex_unlock(&LOCK_active);
@@ -6179,13 +6179,13 @@ int TC_LOG_MMAP::log_xid(THD *thd, my_xid xid)
p->waiters++; p->waiters++;
/* /*
note - it must be while (), not do ... while () here note - it must be while (), not do ... while () here
as p->state may be not DIRTY when we come here as p->state may be not PS_DIRTY when we come here
*/ */
while (p->state == DIRTY && syncing) while (p->state == PS_DIRTY && syncing)
mysql_cond_wait(&p->cond, &LOCK_sync); mysql_cond_wait(&p->cond, &LOCK_sync);
p->waiters--; p->waiters--;
err= p->state == ERROR; err= p->state == PS_ERROR;
if (p->state != DIRTY) // page was synced if (p->state != PS_DIRTY) // page was synced
{ {
if (p->waiters == 0) if (p->waiters == 0)
mysql_cond_signal(&COND_pool); // in case somebody's waiting mysql_cond_signal(&COND_pool); // in case somebody's waiting
@@ -6223,7 +6223,7 @@ int TC_LOG_MMAP::sync()
pool_last->next=syncing; pool_last->next=syncing;
pool_last=syncing; pool_last=syncing;
syncing->next=0; syncing->next=0;
syncing->state= err ? ERROR : POOL; syncing->state= err ? PS_ERROR : PS_POOL;
mysql_cond_broadcast(&syncing->cond); // signal "sync done" mysql_cond_broadcast(&syncing->cond); // signal "sync done"
mysql_cond_signal(&COND_pool); // in case somebody's waiting mysql_cond_signal(&COND_pool); // in case somebody's waiting
mysql_mutex_unlock(&LOCK_pool); mysql_mutex_unlock(&LOCK_pool);

View File

@@ -63,9 +63,9 @@ class TC_LOG_MMAP: public TC_LOG
{ {
public: // only to keep Sun Forte on sol9x86 happy public: // only to keep Sun Forte on sol9x86 happy
typedef enum { typedef enum {
POOL, // page is in pool PS_POOL, // page is in pool
ERROR, // last sync failed PS_ERROR, // last sync failed
DIRTY // new xids added since last sync PS_DIRTY // new xids added since last sync
} PAGE_STATE; } PAGE_STATE;
private: private:

View File

@@ -18,6 +18,8 @@
#include "debug_sync.h" #include "debug_sync.h"
#include <hash.h> #include <hash.h>
#include <mysqld_error.h> #include <mysqld_error.h>
#include <mysql/plugin.h>
#include <mysql/service_thd_wait.h>
#ifdef HAVE_PSI_INTERFACE #ifdef HAVE_PSI_INTERFACE
static PSI_mutex_key key_MDL_map_mutex; static PSI_mutex_key key_MDL_map_mutex;
@@ -973,10 +975,14 @@ MDL_wait::timed_wait(THD *thd, struct timespec *abs_timeout,
old_msg= thd_enter_cond(thd, &m_COND_wait_status, &m_LOCK_wait_status, old_msg= thd_enter_cond(thd, &m_COND_wait_status, &m_LOCK_wait_status,
wait_state_name); wait_state_name);
thd_wait_begin(thd, THD_WAIT_META_DATA_LOCK);
while (!m_wait_status && !thd_killed(thd) && while (!m_wait_status && !thd_killed(thd) &&
wait_result != ETIMEDOUT && wait_result != ETIME) wait_result != ETIMEDOUT && wait_result != ETIME)
{
wait_result= mysql_cond_timedwait(&m_COND_wait_status, &m_LOCK_wait_status, wait_result= mysql_cond_timedwait(&m_COND_wait_status, &m_LOCK_wait_status,
abs_timeout); abs_timeout);
}
thd_wait_end(thd);
if (m_wait_status == EMPTY) if (m_wait_status == EMPTY)
{ {

View File

@@ -422,7 +422,7 @@ my_bool opt_super_large_pages= 0;
my_bool opt_myisam_use_mmap= 0; my_bool opt_myisam_use_mmap= 0;
uint opt_large_page_size= 0; uint opt_large_page_size= 0;
#if defined(ENABLED_DEBUG_SYNC) #if defined(ENABLED_DEBUG_SYNC)
uint opt_debug_sync_timeout= 0; MYSQL_PLUGIN_IMPORT uint opt_debug_sync_timeout= 0;
#endif /* defined(ENABLED_DEBUG_SYNC) */ #endif /* defined(ENABLED_DEBUG_SYNC) */
my_bool opt_old_style_user_limits= 0, trust_function_creators= 0; my_bool opt_old_style_user_limits= 0, trust_function_creators= 0;
/* /*
@@ -2008,6 +2008,36 @@ extern "C" sig_handler end_thread_signal(int sig __attribute__((unused)))
} }
/*
Decrease number of connections
SYNOPSIS
dec_connection_count()
*/
void dec_connection_count()
{
mysql_mutex_lock(&LOCK_connection_count);
--connection_count;
mysql_mutex_unlock(&LOCK_connection_count);
}
/*
Delete the THD object and decrease number of threads
SYNOPSIS
delete_thd()
thd Thread handler
*/
void delete_thd(THD *thd)
{
thread_count--;
delete thd;
}
/* /*
Unlink thd from global list of available connections and free thd Unlink thd from global list of available connections and free thd
@@ -2023,15 +2053,10 @@ void unlink_thd(THD *thd)
{ {
DBUG_ENTER("unlink_thd"); DBUG_ENTER("unlink_thd");
DBUG_PRINT("enter", ("thd: 0x%lx", (long) thd)); DBUG_PRINT("enter", ("thd: 0x%lx", (long) thd));
thd->cleanup();
mysql_mutex_lock(&LOCK_connection_count);
--connection_count;
mysql_mutex_unlock(&LOCK_connection_count);
dec_connection_count();
mysql_mutex_lock(&LOCK_thread_count); mysql_mutex_lock(&LOCK_thread_count);
thread_count--; delete_thd(thd);
delete thd;
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
@@ -4923,6 +4948,14 @@ static bool read_init_file(char *file_name)
} }
/**
Increment number of created threads
*/
void inc_thread_created(void)
{
thread_created++;
}
#ifndef EMBEDDED_LIBRARY #ifndef EMBEDDED_LIBRARY
/* /*

View File

@@ -216,6 +216,10 @@ extern char err_shared_dir[];
extern TYPELIB thread_handling_typelib; extern TYPELIB thread_handling_typelib;
extern my_decimal decimal_zero; extern my_decimal decimal_zero;
/*
THR_MALLOC is a key which will be used to set/get MEM_ROOT** for a thread,
using my_pthread_setspecific_ptr()/my_thread_getspecific_ptr().
*/
extern pthread_key(MEM_ROOT**,THR_MALLOC); extern pthread_key(MEM_ROOT**,THR_MALLOC);
#ifdef HAVE_PSI_INTERFACE #ifdef HAVE_PSI_INTERFACE
@@ -503,6 +507,10 @@ get_thread_running()
extern "C" THD *_current_thd_noinline(); extern "C" THD *_current_thd_noinline();
#define _current_thd() _current_thd_noinline() #define _current_thd() _current_thd_noinline()
#else #else
/*
THR_THD is a key which will be used to set/get THD* for a thread,
using my_pthread_setspecific_ptr()/my_thread_getspecific_ptr().
*/
extern pthread_key(THD*, THR_THD); extern pthread_key(THD*, THR_THD);
inline THD *_current_thd(void) inline THD *_current_thd(void)
{ {

View File

@@ -26,6 +26,8 @@
#include "rpl_utility.h" #include "rpl_utility.h"
#include "transaction.h" #include "transaction.h"
#include "sql_parse.h" // end_trans, ROLLBACK #include "sql_parse.h" // end_trans, ROLLBACK
#include <mysql/plugin.h>
#include <mysql/service_thd_wait.h>
static int count_relay_log_space(Relay_log_info* rli); static int count_relay_log_space(Relay_log_info* rli);
@@ -799,6 +801,7 @@ int Relay_log_info::wait_for_pos(THD* thd, String* log_name,
We are going to mysql_cond_(timed)wait(); if the SQL thread stops it We are going to mysql_cond_(timed)wait(); if the SQL thread stops it
will wake us up. will wake us up.
*/ */
thd_wait_begin(thd, THD_WAIT_BINLOG);
if (timeout > 0) if (timeout > 0)
{ {
/* /*
@@ -816,6 +819,7 @@ int Relay_log_info::wait_for_pos(THD* thd, String* log_name,
} }
else else
mysql_cond_wait(&data_cond, &data_lock); mysql_cond_wait(&data_cond, &data_lock);
thd_wait_end(thd);
DBUG_PRINT("info",("Got signal of master update or timed out")); DBUG_PRINT("info",("Got signal of master update or timed out"));
if (error == ETIMEDOUT || error == ETIME) if (error == ETIMEDOUT || error == ETIME)
{ {

View File

@@ -80,14 +80,26 @@ scheduler_functions *thread_scheduler= NULL;
*/ */
/**@{*/ /**@{*/
static void scheduler_wait_begin(void) { extern "C"
{
static void scheduler_wait_lock_begin(void) {
MYSQL_CALLBACK(thread_scheduler, MYSQL_CALLBACK(thread_scheduler,
thd_wait_begin, (current_thd, THD_WAIT_ROW_TABLE_LOCK)); thd_wait_begin, (current_thd, THD_WAIT_TABLE_LOCK));
} }
static void scheduler_wait_end(void) { static void scheduler_wait_lock_end(void) {
MYSQL_CALLBACK(thread_scheduler, thd_wait_end, (current_thd)); MYSQL_CALLBACK(thread_scheduler, thd_wait_end, (current_thd));
} }
static void scheduler_wait_sync_begin(void) {
MYSQL_CALLBACK(thread_scheduler,
thd_wait_begin, (current_thd, THD_WAIT_TABLE_LOCK));
}
static void scheduler_wait_sync_end(void) {
MYSQL_CALLBACK(thread_scheduler, thd_wait_end, (current_thd));
}
};
/**@}*/ /**@}*/
/** /**
@@ -98,7 +110,10 @@ static void scheduler_wait_end(void) {
mysqld.cc, so this init function will always be called. mysqld.cc, so this init function will always be called.
*/ */
static void scheduler_init() { static void scheduler_init() {
thr_set_lock_wait_callback(scheduler_wait_begin, scheduler_wait_end); thr_set_lock_wait_callback(scheduler_wait_lock_begin,
scheduler_wait_lock_end);
thr_set_sync_wait_callback(scheduler_wait_sync_begin,
scheduler_wait_sync_end);
} }
/* /*
@@ -137,10 +152,6 @@ void one_thread_scheduler()
thd_scheduler::thd_scheduler() thd_scheduler::thd_scheduler()
: m_psi(NULL), data(NULL) : m_psi(NULL), data(NULL)
{ {
#ifndef DBUG_OFF
dbug_explain[0]= '\0';
set_explain= FALSE;
#endif
} }

View File

@@ -72,11 +72,6 @@ enum scheduler_types
void one_thread_per_connection_scheduler(); void one_thread_per_connection_scheduler();
void one_thread_scheduler(); void one_thread_scheduler();
enum pool_command_op
{
NOT_IN_USE_OP= 0, NORMAL_OP= 1, CONNECT_OP, KILL_OP, DIE_OP
};
/* /*
To be used for pool-of-threads (implemeneted differently on various OSs) To be used for pool-of-threads (implemeneted differently on various OSs)
*/ */
@@ -97,15 +92,15 @@ public:
void *data; /* scheduler-specific data structure */ void *data; /* scheduler-specific data structure */
# ifndef DBUG_OFF
char dbug_explain[512];
bool set_explain;
# endif
thd_scheduler(); thd_scheduler();
~thd_scheduler(); ~thd_scheduler();
}; };
void *thd_get_scheduler_data(THD *thd);
void thd_set_scheduler_data(THD *thd, void *data);
PSI_thread* thd_get_psi(THD *thd);
void thd_set_psi(THD *thd, PSI_thread *psi);
extern scheduler_functions *thread_scheduler; extern scheduler_functions *thread_scheduler;
#endif #endif

View File

@@ -550,7 +550,7 @@ sp_head::operator delete(void *ptr, size_t size) throw()
sp_head::sp_head() sp_head::sp_head()
:Query_arena(&main_mem_root, INITIALIZED_FOR_SP), :Query_arena(&main_mem_root, STMT_INITIALIZED_FOR_SP),
m_flags(0), m_flags(0),
m_sp_cache_version(0), m_sp_cache_version(0),
unsafe_flags(0), unsafe_flags(0),
@@ -1208,7 +1208,7 @@ sp_head::execute(THD *thd, bool merge_da_on_success)
Query_arena *old_arena; Query_arena *old_arena;
/* per-instruction arena */ /* per-instruction arena */
MEM_ROOT execute_mem_root; MEM_ROOT execute_mem_root;
Query_arena execute_arena(&execute_mem_root, INITIALIZED_FOR_SP), Query_arena execute_arena(&execute_mem_root, STMT_INITIALIZED_FOR_SP),
backup_arena; backup_arena;
query_id_t old_query_id; query_id_t old_query_id;
TABLE *old_derived_tables; TABLE *old_derived_tables;
@@ -1489,7 +1489,7 @@ sp_head::execute(THD *thd, bool merge_da_on_success)
thd->m_reprepare_observer= save_reprepare_observer; thd->m_reprepare_observer= save_reprepare_observer;
thd->stmt_arena= old_arena; thd->stmt_arena= old_arena;
state= EXECUTED; state= STMT_EXECUTED;
/* /*
Restore the caller's original warning information area: Restore the caller's original warning information area:
@@ -1647,7 +1647,7 @@ sp_head::execute_trigger(THD *thd,
sp_rcontext *nctx = NULL; sp_rcontext *nctx = NULL;
bool err_status= FALSE; bool err_status= FALSE;
MEM_ROOT call_mem_root; MEM_ROOT call_mem_root;
Query_arena call_arena(&call_mem_root, Query_arena::INITIALIZED_FOR_SP); Query_arena call_arena(&call_mem_root, Query_arena::STMT_INITIALIZED_FOR_SP);
Query_arena backup_arena; Query_arena backup_arena;
DBUG_ENTER("sp_head::execute_trigger"); DBUG_ENTER("sp_head::execute_trigger");
@@ -1788,7 +1788,7 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount,
String binlog_buf(buf, sizeof(buf), &my_charset_bin); String binlog_buf(buf, sizeof(buf), &my_charset_bin);
bool err_status= FALSE; bool err_status= FALSE;
MEM_ROOT call_mem_root; MEM_ROOT call_mem_root;
Query_arena call_arena(&call_mem_root, Query_arena::INITIALIZED_FOR_SP); Query_arena call_arena(&call_mem_root, Query_arena::STMT_INITIALIZED_FOR_SP);
Query_arena backup_arena; Query_arena backup_arena;
DBUG_ENTER("sp_head::execute_function"); DBUG_ENTER("sp_head::execute_function");
DBUG_PRINT("info", ("function %s", m_name.str)); DBUG_PRINT("info", ("function %s", m_name.str));
@@ -2545,7 +2545,7 @@ sp_head::restore_thd_mem_root(THD *thd)
DBUG_ENTER("sp_head::restore_thd_mem_root"); DBUG_ENTER("sp_head::restore_thd_mem_root");
Item *flist= free_list; // The old list Item *flist= free_list; // The old list
set_query_arena(thd); // Get new free_list and mem_root set_query_arena(thd); // Get new free_list and mem_root
state= INITIALIZED_FOR_SP; state= STMT_INITIALIZED_FOR_SP;
DBUG_PRINT("info", ("mem_root 0x%lx returned from thd mem root 0x%lx", DBUG_PRINT("info", ("mem_root 0x%lx returned from thd mem root 0x%lx",
(ulong) &mem_root, (ulong) &thd->mem_root)); (ulong) &mem_root, (ulong) &thd->mem_root));
@@ -3009,7 +3009,7 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp,
(thd->stmt_da->sql_errno() != ER_CANT_REOPEN_TABLE && (thd->stmt_da->sql_errno() != ER_CANT_REOPEN_TABLE &&
thd->stmt_da->sql_errno() != ER_NO_SUCH_TABLE && thd->stmt_da->sql_errno() != ER_NO_SUCH_TABLE &&
thd->stmt_da->sql_errno() != ER_UPDATE_TABLE_USED)) thd->stmt_da->sql_errno() != ER_UPDATE_TABLE_USED))
thd->stmt_arena->state= Query_arena::EXECUTED; thd->stmt_arena->state= Query_arena::STMT_EXECUTED;
/* /*
Merge here with the saved parent's values Merge here with the saved parent's values

View File

@@ -560,7 +560,7 @@ public:
/// Should give each a name or type code for debugging purposes? /// Should give each a name or type code for debugging purposes?
sp_instr(uint ip, sp_pcontext *ctx) sp_instr(uint ip, sp_pcontext *ctx)
:Query_arena(0, INITIALIZED_FOR_SP), marked(0), m_ip(ip), m_ctx(ctx) :Query_arena(0, STMT_INITIALIZED_FOR_SP), marked(0), m_ip(ip), m_ctx(ctx)
{} {}
virtual ~sp_instr() virtual ~sp_instr()

View File

@@ -217,6 +217,252 @@ bool foreign_key_prefix(Key *a, Key *b)
** Thread specific functions ** Thread specific functions
****************************************************************************/ ****************************************************************************/
/**
Get reference to scheduler data object
@param thd THD object
@retval Scheduler data object on THD
*/
void *thd_get_scheduler_data(THD *thd)
{
return thd->scheduler.data;
}
/**
Set reference to Scheduler data object for THD object
@param thd THD object
@param psi Scheduler data object to set on THD
*/
void thd_set_scheduler_data(THD *thd, void *data)
{
thd->scheduler.data= data;
}
/**
Get reference to Performance Schema object for THD object
@param thd THD object
@retval Performance schema object for thread on THD
*/
PSI_thread *thd_get_psi(THD *thd)
{
return thd->scheduler.m_psi;
}
/**
Set reference to Performance Schema object for THD object
@param thd THD object
@param psi Performance schema object for thread
*/
void thd_set_psi(THD *thd, PSI_thread *psi)
{
thd->scheduler.m_psi= psi;
}
/**
Set the state on connection to killed
@param thd THD object
*/
void thd_set_killed(THD *thd)
{
thd->killed= THD::KILL_CONNECTION;
}
/**
Clear errors from the previous THD
@param thd THD object
*/
void thd_clear_errors(THD *thd)
{
my_errno= 0;
thd->mysys_var->abort= 0;
}
/**
Set thread stack in THD object
@param thd Thread object
@param stack_start Start of stack to set in THD object
*/
void thd_set_thread_stack(THD *thd, char *stack_start)
{
thd->thread_stack= stack_start;
}
/**
Lock connection data for the set of connections this connection
belongs to
@param thd THD object
*/
void thd_lock_thread_count(THD *)
{
mysql_mutex_lock(&LOCK_thread_count);
}
/**
Lock connection data for the set of connections this connection
belongs to
@param thd THD object
*/
void thd_unlock_thread_count(THD *)
{
mysql_cond_broadcast(&COND_thread_count);
mysql_mutex_unlock(&LOCK_thread_count);
}
/**
Close the socket used by this connection
@param thd THD object
*/
void thd_close_connection(THD *thd)
{
if (thd->net.vio)
vio_close(thd->net.vio);
}
/**
Get current THD object from thread local data
@retval The THD object for the thread, NULL if not connection thread
*/
THD *thd_get_current_thd()
{
return current_thd;
}
/**
Set up various THD data for a new connection
thd_new_connection_setup
@param thd THD object
@param stack_start Start of stack for connection
*/
void thd_new_connection_setup(THD *thd, char *stack_start)
{
#ifdef HAVE_PSI_INTERFACE
if (PSI_server)
thd_set_psi(thd,
PSI_server->new_thread(key_thread_one_connection,
thd,
thd_get_thread_id((MYSQL_THD)thd)));
#endif
thd->set_time();
thd->prior_thr_create_utime= thd->thr_create_utime= thd->start_utime=
my_micro_time();
threads.append(thd);
thd_unlock_thread_count(thd);
DBUG_PRINT("info", ("init new connection. thd: 0x%lx fd: %d",
(ulong)thd, thd->net.vio->sd));
thd_set_thread_stack(thd, stack_start);
}
/**
Lock data that needs protection in THD object
@param thd THD object
*/
void thd_lock_data(THD *thd)
{
mysql_mutex_lock(&thd->LOCK_thd_data);
}
/**
Unlock data that needs protection in THD object
@param thd THD object
*/
void thd_unlock_data(THD *thd)
{
mysql_mutex_unlock(&thd->LOCK_thd_data);
}
/**
Support method to check if connection has already started transcaction
@param client_cntx Low level client context
@retval TRUE if connection already started transaction
*/
bool thd_is_transaction_active(THD *thd)
{
return thd->transaction.is_active();
}
/**
Check if there is buffered data on the socket representing the connection
@param thd THD object
*/
int thd_connection_has_data(THD *thd)
{
Vio *vio= thd->net.vio;
return vio->has_data(vio);
}
/**
Set reading/writing on socket, used by SHOW PROCESSLIST
@param thd THD object
@param val Value to set it to (0 or 1)
*/
void thd_set_net_read_write(THD *thd, uint val)
{
thd->net.reading_or_writing= val;
}
/**
Set reference to mysys variable in THD object
@param thd THD object
@param mysys_var Reference to set
*/
void thd_set_mysys_var(THD *thd, st_my_thread_var *mysys_var)
{
thd->set_mysys_var(mysys_var);
}
/**
Get socket file descriptor for this connection
@param thd THD object
@retval Socket of the connection
*/
my_socket thd_get_fd(THD *thd)
{
return thd->net.vio->sd;
}
/**
Get thread attributes for connection threads
@retval Reference to thread attribute for connection threads
*/
pthread_attr_t *get_connection_attrib(void)
{
return &connection_attrib;
}
/**
Get max number of connections
@retval Max number of connections for MySQL Server
*/
ulong get_max_connections(void)
{
return max_connections;
}
/* /*
The following functions form part of the C plugin API The following functions form part of the C plugin API
*/ */
@@ -494,7 +740,7 @@ bool Drop_table_error_handler::handle_condition(THD *thd,
THD::THD() THD::THD()
:Statement(&main_lex, &main_mem_root, CONVENTIONAL_EXECUTION, :Statement(&main_lex, &main_mem_root, STMT_CONVENTIONAL_EXECUTION,
/* statement id */ 0), /* statement id */ 0),
rli_fake(0), rli_fake(0),
user_time(0), in_sub_stmt(0), user_time(0), in_sub_stmt(0),
@@ -1355,6 +1601,25 @@ bool THD::store_globals()
return 0; return 0;
} }
/*
Remove the thread specific info (THD and mem_root pointer) stored during
store_global call for this thread.
*/
bool THD::restore_globals()
{
/*
Assert that thread_stack is initialized: it's necessary to be able
to track stack overrun.
*/
DBUG_ASSERT(thread_stack);
/* Undocking the thread specific data. */
my_pthread_setspecific_ptr(THR_THD, NULL);
my_pthread_setspecific_ptr(THR_MALLOC, NULL);
return 0;
}
/* /*
Cleanup after query. Cleanup after query.
@@ -3298,7 +3563,7 @@ extern "C" void thd_pool_wait_end(MYSQL_THD thd);
thd_wait_end MUST be called immediately after waking up again. thd_wait_end MUST be called immediately after waking up again.
*/ */
extern "C" void thd_wait_begin(MYSQL_THD thd, thd_wait_type wait_type) extern "C" void thd_wait_begin(MYSQL_THD thd, int wait_type)
{ {
MYSQL_CALLBACK(thread_scheduler, thd_wait_begin, (thd, wait_type)); MYSQL_CALLBACK(thread_scheduler, thd_wait_begin, (thd, wait_type));
} }
@@ -3314,7 +3579,7 @@ extern "C" void thd_wait_end(MYSQL_THD thd)
MYSQL_CALLBACK(thread_scheduler, thd_wait_end, (thd)); MYSQL_CALLBACK(thread_scheduler, thd_wait_end, (thd));
} }
#else #else
extern "C" void thd_wait_begin(MYSQL_THD thd, thd_wait_type wait_type) extern "C" void thd_wait_begin(MYSQL_THD thd, int wait_type)
{ {
/* do NOTHING for the embedded library */ /* do NOTHING for the embedded library */
return; return;

View File

@@ -624,14 +624,14 @@ public:
/* /*
The states relfects three diffrent life cycles for three The states relfects three diffrent life cycles for three
different types of statements: different types of statements:
Prepared statement: INITIALIZED -> PREPARED -> EXECUTED. Prepared statement: STMT_INITIALIZED -> STMT_PREPARED -> STMT_EXECUTED.
Stored procedure: INITIALIZED_FOR_SP -> EXECUTED. Stored procedure: STMT_INITIALIZED_FOR_SP -> STMT_EXECUTED.
Other statements: CONVENTIONAL_EXECUTION never changes. Other statements: STMT_CONVENTIONAL_EXECUTION never changes.
*/ */
enum enum_state enum enum_state
{ {
INITIALIZED= 0, INITIALIZED_FOR_SP= 1, PREPARED= 2, STMT_INITIALIZED= 0, STMT_INITIALIZED_FOR_SP= 1, STMT_PREPARED= 2,
CONVENTIONAL_EXECUTION= 3, EXECUTED= 4, ERROR= -1 STMT_CONVENTIONAL_EXECUTION= 3, STMT_EXECUTED= 4, STMT_ERROR= -1
}; };
enum_state state; enum_state state;
@@ -654,13 +654,13 @@ public:
virtual Type type() const; virtual Type type() const;
virtual ~Query_arena() {}; virtual ~Query_arena() {};
inline bool is_stmt_prepare() const { return state == INITIALIZED; } inline bool is_stmt_prepare() const { return state == STMT_INITIALIZED; }
inline bool is_stmt_prepare_or_first_sp_execute() const inline bool is_stmt_prepare_or_first_sp_execute() const
{ return (int)state < (int)PREPARED; } { return (int)state < (int)STMT_PREPARED; }
inline bool is_stmt_prepare_or_first_stmt_execute() const inline bool is_stmt_prepare_or_first_stmt_execute() const
{ return (int)state <= (int)PREPARED; } { return (int)state <= (int)STMT_PREPARED; }
inline bool is_conventional() const inline bool is_conventional() const
{ return state == CONVENTIONAL_EXECUTION; } { return state == STMT_CONVENTIONAL_EXECUTION; }
inline void* alloc(size_t size) { return alloc_root(mem_root,size); } inline void* alloc(size_t size) { return alloc_root(mem_root,size); }
inline void* calloc(size_t size) inline void* calloc(size_t size)
@@ -2199,6 +2199,7 @@ public:
void cleanup(void); void cleanup(void);
void cleanup_after_query(); void cleanup_after_query();
bool store_globals(); bool store_globals();
bool restore_globals();
#ifdef SIGNAL_WITH_VIO_CLOSE #ifdef SIGNAL_WITH_VIO_CLOSE
inline void set_active_vio(Vio* vio) inline void set_active_vio(Vio* vio)
{ {

View File

@@ -707,6 +707,32 @@ pthread_handler_t handle_one_connection(void *arg)
return 0; return 0;
} }
bool thd_prepare_connection(THD *thd)
{
bool rc;
lex_start(thd);
rc= login_connection(thd);
MYSQL_AUDIT_NOTIFY_CONNECTION_CONNECT(thd);
if (rc)
return rc;
MYSQL_CONNECTION_START(thd->thread_id, &thd->security_ctx->priv_user[0],
(char *) thd->security_ctx->host_or_ip);
prepare_new_connection_state(thd);
return FALSE;
}
bool thd_is_connection_alive(THD *thd)
{
NET *net= &thd->net;
if (!net->error &&
net->vio != 0 &&
!(thd->killed == THD::KILL_CONNECTION))
return TRUE;
return FALSE;
}
void do_handle_one_connection(THD *thd_arg) void do_handle_one_connection(THD *thd_arg)
{ {
THD *thd= thd_arg; THD *thd= thd_arg;
@@ -749,22 +775,13 @@ void do_handle_one_connection(THD *thd_arg)
for (;;) for (;;)
{ {
NET *net= &thd->net;
bool rc; bool rc;
lex_start(thd); rc= thd_prepare_connection(thd);
rc= login_connection(thd);
MYSQL_AUDIT_NOTIFY_CONNECTION_CONNECT(thd);
if (rc) if (rc)
goto end_thread; goto end_thread;
MYSQL_CONNECTION_START(thd->thread_id, &thd->security_ctx->priv_user[0], while (thd_is_connection_alive(thd))
(char *) thd->security_ctx->host_or_ip);
prepare_new_connection_state(thd);
while (!net->error && net->vio != 0 &&
!(thd->killed == THD::KILL_CONNECTION))
{ {
mysql_audit_release(thd); mysql_audit_release(thd);
if (do_command(thd)) if (do_command(thd))

View File

@@ -35,6 +35,8 @@ void time_out_user_resource_limits(THD *thd, USER_CONN *uc);
void decrease_user_connections(USER_CONN *uc); void decrease_user_connections(USER_CONN *uc);
bool thd_init_client_charset(THD *thd, uint cs_number); bool thd_init_client_charset(THD *thd, uint cs_number);
bool setup_connection_thread_globals(THD *thd); bool setup_connection_thread_globals(THD *thd);
bool thd_prepare_connection(THD *thd);
bool thd_is_connection_alive(THD *thd);
int check_user(THD *thd, enum enum_server_command command, int check_user(THD *thd, enum enum_server_command command,
const char *passwd, uint passwd_len, const char *db, const char *passwd, uint passwd_len, const char *db,

View File

@@ -46,7 +46,7 @@ protected:
select_result *result; select_result *result;
public: public:
Server_side_cursor(MEM_ROOT *mem_root_arg, select_result *result_arg) Server_side_cursor(MEM_ROOT *mem_root_arg, select_result *result_arg)
:Query_arena(mem_root_arg, INITIALIZED), result(result_arg) :Query_arena(mem_root_arg, STMT_INITIALIZED), result(result_arg)
{} {}
virtual bool is_open() const= 0; virtual bool is_open() const= 0;

View File

@@ -2712,7 +2712,7 @@ void mysqld_stmt_reset(THD *thd, char *packet)
*/ */
reset_stmt_params(stmt); reset_stmt_params(stmt);
stmt->state= Query_arena::PREPARED; stmt->state= Query_arena::STMT_PREPARED;
general_log_print(thd, thd->command, NullS); general_log_print(thd, thd->command, NullS);
@@ -2831,7 +2831,7 @@ void mysql_stmt_get_longdata(THD *thd, char *packet, ulong packet_length)
if (param_number >= stmt->param_count) if (param_number >= stmt->param_count)
{ {
/* Error will be sent in execute call */ /* Error will be sent in execute call */
stmt->state= Query_arena::ERROR; stmt->state= Query_arena::STMT_ERROR;
stmt->last_errno= ER_WRONG_ARGUMENTS; stmt->last_errno= ER_WRONG_ARGUMENTS;
sprintf(stmt->last_error, ER(ER_WRONG_ARGUMENTS), sprintf(stmt->last_error, ER(ER_WRONG_ARGUMENTS),
"mysqld_stmt_send_long_data"); "mysqld_stmt_send_long_data");
@@ -2855,7 +2855,7 @@ void mysql_stmt_get_longdata(THD *thd, char *packet, ulong packet_length)
#endif #endif
if (thd->stmt_da->is_error()) if (thd->stmt_da->is_error())
{ {
stmt->state= Query_arena::ERROR; stmt->state= Query_arena::STMT_ERROR;
stmt->last_errno= thd->stmt_da->sql_errno(); stmt->last_errno= thd->stmt_da->sql_errno();
strncpy(stmt->last_error, thd->stmt_da->message(), MYSQL_ERRMSG_SIZE); strncpy(stmt->last_error, thd->stmt_da->message(), MYSQL_ERRMSG_SIZE);
} }
@@ -3010,7 +3010,7 @@ end:
Prepared_statement::Prepared_statement(THD *thd_arg) Prepared_statement::Prepared_statement(THD *thd_arg)
:Statement(NULL, &main_mem_root, :Statement(NULL, &main_mem_root,
INITIALIZED, ++thd_arg->statement_id_counter), STMT_INITIALIZED, ++thd_arg->statement_id_counter),
thd(thd_arg), thd(thd_arg),
result(thd_arg), result(thd_arg),
param_array(0), param_array(0),
@@ -3283,7 +3283,7 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len)
{ {
setup_set_params(); setup_set_params();
lex->context_analysis_only&= ~CONTEXT_ANALYSIS_ONLY_PREPARE; lex->context_analysis_only&= ~CONTEXT_ANALYSIS_ONLY_PREPARE;
state= Query_arena::PREPARED; state= Query_arena::STMT_PREPARED;
flags&= ~ (uint) IS_IN_USE; flags&= ~ (uint) IS_IN_USE;
/* /*
@@ -3401,7 +3401,7 @@ Prepared_statement::execute_loop(String *expanded_query,
int reprepare_attempt= 0; int reprepare_attempt= 0;
/* Check if we got an error when sending long data */ /* Check if we got an error when sending long data */
if (state == Query_arena::ERROR) if (state == Query_arena::STMT_ERROR)
{ {
my_message(last_errno, last_error, MYF(0)); my_message(last_errno, last_error, MYF(0));
return TRUE; return TRUE;
@@ -3464,7 +3464,7 @@ Prepared_statement::execute_server_runnable(Server_runnable *server_runnable)
Item_change_list save_change_list; Item_change_list save_change_list;
thd->change_list.move_elements_to(&save_change_list); thd->change_list.move_elements_to(&save_change_list);
state= CONVENTIONAL_EXECUTION; state= STMT_CONVENTIONAL_EXECUTION;
if (!(lex= new (mem_root) st_lex_local)) if (!(lex= new (mem_root) st_lex_local))
return TRUE; return TRUE;
@@ -3799,8 +3799,8 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor)
thd->set_statement(&stmt_backup); thd->set_statement(&stmt_backup);
thd->stmt_arena= old_stmt_arena; thd->stmt_arena= old_stmt_arena;
if (state == Query_arena::PREPARED) if (state == Query_arena::STMT_PREPARED)
state= Query_arena::EXECUTED; state= Query_arena::STMT_EXECUTED;
if (error == 0 && this->lex->sql_command == SQLCOM_CALL) if (error == 0 && this->lex->sql_command == SQLCOM_CALL)
{ {

View File

@@ -2407,12 +2407,11 @@ bool schema_table_store_record(THD *thd, TABLE *table)
} }
int make_table_list(THD *thd, SELECT_LEX *sel, static int make_table_list(THD *thd, SELECT_LEX *sel,
LEX_STRING *db_name, LEX_STRING *table_name) LEX_STRING *db_name, LEX_STRING *table_name)
{ {
Table_ident *table_ident; Table_ident *table_ident;
table_ident= new Table_ident(thd, *db_name, *table_name, 1); table_ident= new Table_ident(thd, *db_name, *table_name, 1);
sel->init_query();
if (!sel->add_table_to_list(thd, table_ident, 0, 0, TL_READ, MDL_SHARED_READ)) if (!sel->add_table_to_list(thd, table_ident, 0, 0, TL_READ, MDL_SHARED_READ))
return 1; return 1;
return 0; return 0;
@@ -2982,91 +2981,190 @@ make_table_name_list(THD *thd, List<LEX_STRING> *table_names, LEX *lex,
/** /**
@brief Fill I_S table for SHOW COLUMNS|INDEX commands Fill I_S table with data obtained by performing full-blown table open.
@param[in] thd thread handler @param thd Thread handler.
@param[in] tables TABLE_LIST for I_S table @param is_show_fields_or_keys Indicates whether it is a legacy SHOW
@param[in] schema_table pointer to I_S structure COLUMNS or SHOW KEYS statement.
@param[in] can_deadlock Indicates that deadlocks are possible @param table TABLE object for I_S table to be filled.
due to metadata locks, so to avoid @param schema_table I_S table description structure.
them we should not wait in case if @param orig_db_name Database name.
conflicting lock is present. @param orig_table_name Table name.
@param[in] open_tables_state_backup pointer to Open_tables_backup object @param open_tables_state_backup Open_tables_state object which is used
which is used to save|restore original to save/restore original status of
status of variables related to variables related to open tables state.
open tables state @param can_deadlock Indicates that deadlocks are possible
due to metadata locks, so to avoid
them we should not wait in case if
conflicting lock is present.
@return Operation status @retval FALSE - Success.
@retval 0 success @retval TRUE - Failure.
@retval 1 error
*/ */
static bool
static int fill_schema_table_by_open(THD *thd, bool is_show_fields_or_keys,
fill_schema_show_cols_or_idxs(THD *thd, TABLE_LIST *tables, TABLE *table, ST_SCHEMA_TABLE *schema_table,
ST_SCHEMA_TABLE *schema_table, LEX_STRING *orig_db_name,
bool can_deadlock, LEX_STRING *orig_table_name,
Open_tables_backup *open_tables_state_backup) Open_tables_backup *open_tables_state_backup,
bool can_deadlock)
{ {
LEX *lex= thd->lex; Query_arena i_s_arena(thd->mem_root,
bool res; Query_arena::STMT_CONVENTIONAL_EXECUTION),
LEX_STRING tmp_lex_string, tmp_lex_string1, *db_name, *table_name; backup_arena, *old_arena;
enum_sql_command save_sql_command= lex->sql_command; LEX *old_lex= thd->lex, temp_lex, *lex;
TABLE_LIST *show_table_list= tables->schema_select_lex->table_list.first; LEX_STRING db_name, table_name;
TABLE *table= tables->table; TABLE_LIST *table_list;
int error= 1; bool result= true;
DBUG_ENTER("fill_schema_show");
lex->all_selects_list= tables->schema_select_lex; DBUG_ENTER("fill_schema_table_by_open");
/* /*
Restore thd->temporary_tables to be able to process When a view is opened its structures are allocated on a permanent
temporary tables(only for 'show index' & 'show columns'). statement arena and linked into the LEX tree for the current statement
This should be changed when processing of temporary tables for (this happens even in cases when view is handled through TEMPTABLE
I_S tables will be done. algorithm).
To prevent this process from unnecessary hogging of memory in the permanent
arena of our I_S query and to avoid damaging its LEX we use temporary
arena and LEX for table/view opening.
Use temporary arena instead of statement permanent arena. Also make
it active arena and save original one for successive restoring.
*/ */
thd->temporary_tables= open_tables_state_backup->temporary_tables; old_arena= thd->stmt_arena;
thd->stmt_arena= &i_s_arena;
thd->set_n_backup_active_arena(&i_s_arena, &backup_arena);
/* Prepare temporary LEX. */
thd->lex= lex= &temp_lex;
lex_start(thd);
/* Disable constant subquery evaluation as we won't be locking tables. */
lex->context_analysis_only= CONTEXT_ANALYSIS_ONLY_VIEW;
/*
Some of process_table() functions rely on wildcard being passed from
old LEX (or at least being initialized).
*/
lex->wild= old_lex->wild;
/*
Since make_table_list() might change database and table name passed
to it we create copies of orig_db_name and orig_table_name here.
These copies are used for make_table_list() while unaltered values
are passed to process_table() functions.
*/
if (!thd->make_lex_string(&db_name, orig_db_name->str,
orig_db_name->length, FALSE) ||
!thd->make_lex_string(&table_name, orig_table_name->str,
orig_table_name->length, FALSE))
goto end;
/*
Create table list element for table to be open. Link it with the
temporary LEX. The latter is required to correctly open views and
produce table describing their structure.
*/
if (make_table_list(thd, &lex->select_lex, &db_name, &table_name))
goto end;
table_list= lex->select_lex.table_list.first;
if (is_show_fields_or_keys)
{
/*
Restore thd->temporary_tables to be able to process
temporary tables (only for 'show index' & 'show columns').
This should be changed when processing of temporary tables for
I_S tables will be done.
*/
thd->temporary_tables= open_tables_state_backup->temporary_tables;
}
else
{
/*
Apply optimization flags for table opening which are relevant for
this I_S table. We can't do this for SHOW COLUMNS/KEYS because of
backward compatibility.
*/
table_list->i_s_requested_object= schema_table->i_s_requested_object;
}
/* /*
Let us set fake sql_command so views won't try to merge Let us set fake sql_command so views won't try to merge
themselves into main statement. If we don't do this, themselves into main statement. If we don't do this,
SELECT * from information_schema.xxxx will cause problems. SELECT * from information_schema.xxxx will cause problems.
SQLCOM_SHOW_FIELDS is used because it satisfies 'only_view_structure()' SQLCOM_SHOW_FIELDS is used because it satisfies
'only_view_structure()'.
*/ */
lex->sql_command= SQLCOM_SHOW_FIELDS; lex->sql_command= SQLCOM_SHOW_FIELDS;
res= open_normal_and_derived_tables(thd, show_table_list, result= open_normal_and_derived_tables(thd, table_list,
(MYSQL_OPEN_IGNORE_FLUSH | (MYSQL_OPEN_IGNORE_FLUSH |
MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL | MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL |
(can_deadlock ? (can_deadlock ?
MYSQL_OPEN_FAIL_ON_MDL_CONFLICT : 0))); MYSQL_OPEN_FAIL_ON_MDL_CONFLICT : 0)));
lex->sql_command= save_sql_command; /*
Restore old value of sql_command back as it is being looked at in
process_table() function.
*/
lex->sql_command= old_lex->sql_command;
DEBUG_SYNC(thd, "after_open_table_ignore_flush"); DEBUG_SYNC(thd, "after_open_table_ignore_flush");
/* /*
get_all_tables() returns 1 on failure and 0 on success thus XXX: show_table_list has a flag i_is_requested,
return only these and not the result code of ::process_table() and when it's set, open_normal_and_derived_tables()
can return an error without setting an error message
in THD, which is a hack. This is why we have to
check for res, then for thd->is_error() and only then
for thd->main_da.sql_errno().
We should use show_table_list->alias instead of Again we don't do this for SHOW COLUMNS/KEYS because
show_table_list->table_name because table_name of backward compatibility.
could be changed during opening of I_S tables. It's safe
to use alias because alias contains original table name
in this case(this part of code is used only for
'show columns' & 'show statistics' commands).
*/ */
table_name= thd->make_lex_string(&tmp_lex_string1, show_table_list->alias, if (!is_show_fields_or_keys && result && thd->is_error() &&
strlen(show_table_list->alias), FALSE); thd->stmt_da->sql_errno() == ER_NO_SUCH_TABLE)
if (!show_table_list->view) {
db_name= thd->make_lex_string(&tmp_lex_string, show_table_list->db, /*
show_table_list->db_length, FALSE); Hide error for a non-existing table.
else For example, this error can occur when we use a where condition
db_name= &show_table_list->view_db; with a db name and table, but the table does not exist.
*/
result= false;
thd->clear_error();
}
else
{
result= schema_table->process_table(thd, table_list,
table, result,
orig_db_name,
orig_table_name);
}
error= test(schema_table->process_table(thd, show_table_list,
table, res, db_name, end:
table_name)); lex->unit.cleanup();
thd->temporary_tables= 0;
close_tables_for_reopen(thd, &show_table_list, /* Restore original LEX value, statement's arena and THD arena values. */
open_tables_state_backup->mdl_system_tables_svp); lex_end(thd->lex);
DBUG_RETURN(error);
if (i_s_arena.free_list)
i_s_arena.free_items();
/*
For safety reset list of open temporary tables before closing
all tables open within this Open_tables_state.
*/
thd->temporary_tables= NULL;
close_thread_tables(thd);
thd->mdl_context.rollback_to_savepoint(open_tables_state_backup->mdl_system_tables_svp);
thd->lex= old_lex;
thd->stmt_arena= old_arena;
thd->restore_active_arena(&i_s_arena, &backup_arena);
DBUG_RETURN(result);
} }
@@ -3477,10 +3575,8 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
{ {
LEX *lex= thd->lex; LEX *lex= thd->lex;
TABLE *table= tables->table; TABLE *table= tables->table;
SELECT_LEX *old_all_select_lex= lex->all_selects_list;
SELECT_LEX *lsel= tables->schema_select_lex; SELECT_LEX *lsel= tables->schema_select_lex;
ST_SCHEMA_TABLE *schema_table= tables->schema_table; ST_SCHEMA_TABLE *schema_table= tables->schema_table;
SELECT_LEX sel;
LOOKUP_FIELD_VALUES lookup_field_vals; LOOKUP_FIELD_VALUES lookup_field_vals;
LEX_STRING *db_name, *table_name; LEX_STRING *db_name, *table_name;
bool with_i_schema; bool with_i_schema;
@@ -3488,11 +3584,8 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
List<LEX_STRING> db_names; List<LEX_STRING> db_names;
List_iterator_fast<LEX_STRING> it(db_names); List_iterator_fast<LEX_STRING> it(db_names);
COND *partial_cond= 0; COND *partial_cond= 0;
uint derived_tables= lex->derived_tables;
int error= 1; int error= 1;
Open_tables_backup open_tables_state_backup; Open_tables_backup open_tables_state_backup;
uint8 save_context_analysis_only= lex->context_analysis_only;
Query_tables_list query_tables_list_backup;
#ifndef NO_EMBEDDED_ACCESS_CHECKS #ifndef NO_EMBEDDED_ACCESS_CHECKS
Security_context *sctx= thd->security_ctx; Security_context *sctx= thd->security_ctx;
#endif #endif
@@ -3511,15 +3604,6 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
*/ */
can_deadlock= thd->mdl_context.has_locks(); can_deadlock= thd->mdl_context.has_locks();
lex->context_analysis_only|= CONTEXT_ANALYSIS_ONLY_VIEW;
lex->reset_n_backup_query_tables_list(&query_tables_list_backup);
/*
Restore Query_tables_list::sql_command value, which was reset
above, as ST_SCHEMA_TABLE::process_table() functions often rely
that this value reflects which SHOW statement is executed.
*/
lex->sql_command= query_tables_list_backup.sql_command;
/* /*
We should not introduce deadlocks even if we already have some We should not introduce deadlocks even if we already have some
tables open and locked, since we won't lock tables which we will tables open and locked, since we won't lock tables which we will
@@ -3539,9 +3623,19 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
*/ */
if (lsel && lsel->table_list.first) if (lsel && lsel->table_list.first)
{ {
error= fill_schema_show_cols_or_idxs(thd, tables, schema_table, LEX_STRING db_name, table_name;
can_deadlock,
&open_tables_state_backup); db_name.str= lsel->table_list.first->db;
db_name.length= lsel->table_list.first->db_length;
table_name.str= lsel->table_list.first->table_name;
table_name.length= lsel->table_list.first->table_name_length;
error= fill_schema_table_by_open(thd, TRUE,
table, schema_table,
&db_name, &table_name,
&open_tables_state_backup,
can_deadlock);
goto err; goto err;
} }
@@ -3595,12 +3689,6 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
it.rewind(); /* To get access to new elements in basis list */ it.rewind(); /* To get access to new elements in basis list */
while ((db_name= it++)) while ((db_name= it++))
{ {
LEX_STRING orig_db_name;
/* db_name can be changed in make_table_list() func */
if (!thd->make_lex_string(&orig_db_name, db_name->str,
db_name->length, FALSE))
goto err;
#ifndef NO_EMBEDDED_ACCESS_CHECKS #ifndef NO_EMBEDDED_ACCESS_CHECKS
if (!(check_access(thd, SELECT_ACL, db_name->str, if (!(check_access(thd, SELECT_ACL, db_name->str,
&thd->col_access, NULL, 0, 1) || &thd->col_access, NULL, 0, 1) ||
@@ -3678,66 +3766,11 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
continue; continue;
} }
int res; if (fill_schema_table_by_open(thd, FALSE,
LEX_STRING tmp_lex_string; table, schema_table,
/* db_name, table_name,
Set the parent lex of 'sel' because it is needed by &open_tables_state_backup,
sel.init_query() which is called inside make_table_list. can_deadlock))
*/
sel.parent_lex= lex;
if (make_table_list(thd, &sel, db_name, table_name))
goto err;
TABLE_LIST *show_table_list= sel.table_list.first;
lex->all_selects_list= &sel;
lex->derived_tables= 0;
lex->sql_command= SQLCOM_SHOW_FIELDS;
show_table_list->i_s_requested_object=
schema_table->i_s_requested_object;
DEBUG_SYNC(thd, "before_open_in_get_all_tables");
res= open_normal_and_derived_tables(thd, show_table_list,
(MYSQL_OPEN_IGNORE_FLUSH |
MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL |
(can_deadlock ? MYSQL_OPEN_FAIL_ON_MDL_CONFLICT : 0)));
lex->sql_command= query_tables_list_backup.sql_command;
/*
XXX: show_table_list has a flag i_is_requested,
and when it's set, open_normal_and_derived_tables()
can return an error without setting an error message
in THD, which is a hack. This is why we have to
check for res, then for thd->is_error() only then
for thd->stmt_da->sql_errno().
*/
if (res && thd->is_error() &&
thd->stmt_da->sql_errno() == ER_NO_SUCH_TABLE)
{
/*
Hide error for not existing table.
This error can occur for example when we use
where condition with db name and table name and this
table does not exist.
*/
res= 0;
thd->clear_error();
}
else
{
/*
We should use show_table_list->alias instead of
show_table_list->table_name because table_name
could be changed during opening of I_S tables. It's safe
to use alias because alias contains original table name
in this case.
*/
thd->make_lex_string(&tmp_lex_string, show_table_list->alias,
strlen(show_table_list->alias), FALSE);
res= schema_table->process_table(thd, show_table_list, table,
res, &orig_db_name,
&tmp_lex_string);
close_tables_for_reopen(thd, &show_table_list,
open_tables_state_backup.mdl_system_tables_svp);
}
DBUG_ASSERT(!lex->query_tables_own_last);
if (res)
goto err; goto err;
} }
} }
@@ -3753,10 +3786,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
error= 0; error= 0;
err: err:
thd->restore_backup_open_tables_state(&open_tables_state_backup); thd->restore_backup_open_tables_state(&open_tables_state_backup);
lex->restore_backup_query_tables_list(&query_tables_list_backup);
lex->derived_tables= derived_tables;
lex->all_selects_list= old_all_select_lex;
lex->context_analysis_only= save_context_analysis_only;
DBUG_RETURN(error); DBUG_RETURN(error);
} }

View File

@@ -1992,7 +1992,8 @@ int open_table_from_share(THD *thd, TABLE_SHARE *share, const char *alias,
Query_arena *backup_stmt_arena_ptr= thd->stmt_arena; Query_arena *backup_stmt_arena_ptr= thd->stmt_arena;
Query_arena backup_arena; Query_arena backup_arena;
Query_arena part_func_arena(&outparam->mem_root, Query_arena::INITIALIZED); Query_arena part_func_arena(&outparam->mem_root,
Query_arena::STMT_INITIALIZED);
thd->set_n_backup_active_arena(&part_func_arena, &backup_arena); thd->set_n_backup_active_arena(&part_func_arena, &backup_arena);
thd->stmt_arena= &part_func_arena; thd->stmt_arena= &part_func_arena;
bool tmp; bool tmp;

View File

@@ -1270,7 +1270,7 @@ retry:
#endif /* UNIV_SYNC_DEBUG */ #endif /* UNIV_SYNC_DEBUG */
trx->op_info = "waiting in InnoDB queue"; trx->op_info = "waiting in InnoDB queue";
thd_wait_begin(trx->mysql_thd, THD_WAIT_ROW_TABLE_LOCK); thd_wait_begin(trx->mysql_thd, THD_WAIT_USER_LOCK);
os_event_wait(slot->event); os_event_wait(slot->event);
thd_wait_end(trx->mysql_thd); thd_wait_end(trx->mysql_thd);
@@ -1658,7 +1658,7 @@ srv_suspend_mysql_thread(
/* Suspend this thread and wait for the event. */ /* Suspend this thread and wait for the event. */
thd_wait_begin(trx->mysql_thd, THD_WAIT_ROW_TABLE_LOCK); thd_wait_begin(trx->mysql_thd, THD_WAIT_ROW_LOCK);
os_event_wait(event); os_event_wait(event);
thd_wait_end(trx->mysql_thd); thd_wait_end(trx->mysql_thd);

View File

@@ -27,6 +27,8 @@ int32 inserts= 0, N;
LF_ALLOCATOR lf_allocator; LF_ALLOCATOR lf_allocator;
LF_HASH lf_hash; LF_HASH lf_hash;
int with_my_thread_init=0;
/* /*
pin allocator - alloc and release an element in a loop pin allocator - alloc and release an element in a loop
*/ */
@@ -36,7 +38,8 @@ pthread_handler_t test_lf_pinbox(void *arg)
int32 x= 0; int32 x= 0;
LF_PINS *pins; LF_PINS *pins;
my_thread_init(); if (with_my_thread_init)
my_thread_init();
pins= lf_pinbox_get_pins(&lf_allocator.pinbox); pins= lf_pinbox_get_pins(&lf_allocator.pinbox);
@@ -49,7 +52,10 @@ pthread_handler_t test_lf_pinbox(void *arg)
pthread_mutex_lock(&mutex); pthread_mutex_lock(&mutex);
if (!--running_threads) pthread_cond_signal(&cond); if (!--running_threads) pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex); pthread_mutex_unlock(&mutex);
my_thread_end();
if (with_my_thread_init)
my_thread_end();
return 0; return 0;
} }
@@ -68,7 +74,8 @@ pthread_handler_t test_lf_alloc(void *arg)
int32 x,y= 0; int32 x,y= 0;
LF_PINS *pins; LF_PINS *pins;
my_thread_init(); if (with_my_thread_init)
my_thread_init();
pins= lf_alloc_get_pins(&lf_allocator); pins= lf_alloc_get_pins(&lf_allocator);
@@ -101,7 +108,9 @@ pthread_handler_t test_lf_alloc(void *arg)
} }
if (!--running_threads) pthread_cond_signal(&cond); if (!--running_threads) pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex); pthread_mutex_unlock(&mutex);
my_thread_end();
if (with_my_thread_init)
my_thread_end();
return 0; return 0;
} }
@@ -112,7 +121,8 @@ pthread_handler_t test_lf_hash(void *arg)
int32 x,y,z,sum= 0, ins= 0; int32 x,y,z,sum= 0, ins= 0;
LF_PINS *pins; LF_PINS *pins;
my_thread_init(); if (with_my_thread_init)
my_thread_init();
pins= lf_hash_get_pins(&lf_hash); pins= lf_hash_get_pins(&lf_hash);
@@ -152,14 +162,15 @@ pthread_handler_t test_lf_hash(void *arg)
} }
if (!--running_threads) pthread_cond_signal(&cond); if (!--running_threads) pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex); pthread_mutex_unlock(&mutex);
my_thread_end(); if (with_my_thread_init)
my_thread_end();
return 0; return 0;
} }
void do_tests() void do_tests()
{ {
plan(4); plan(7);
lf_alloc_init(&lf_allocator, sizeof(TLA), offsetof(TLA, not_used)); lf_alloc_init(&lf_allocator, sizeof(TLA), offsetof(TLA, not_used));
lf_hash_init(&lf_hash, sizeof(int), LF_HASH_UNIQUE, 0, sizeof(int), 0, lf_hash_init(&lf_hash, sizeof(int), LF_HASH_UNIQUE, 0, sizeof(int), 0,
@@ -168,9 +179,15 @@ void do_tests()
bad= my_atomic_initialize(); bad= my_atomic_initialize();
ok(!bad, "my_atomic_initialize() returned %d", bad); ok(!bad, "my_atomic_initialize() returned %d", bad);
test_concurrently("lf_pinbox", test_lf_pinbox, N= THREADS, CYCLES); with_my_thread_init= 1;
test_concurrently("lf_alloc", test_lf_alloc, N= THREADS, CYCLES); test_concurrently("lf_pinbox (with my_thread_init)", test_lf_pinbox, N= THREADS, CYCLES);
test_concurrently("lf_hash", test_lf_hash, N= THREADS, CYCLES/10); test_concurrently("lf_alloc (with my_thread_init)", test_lf_alloc, N= THREADS, CYCLES);
test_concurrently("lf_hash (with my_thread_init)", test_lf_hash, N= THREADS, CYCLES/10);
with_my_thread_init= 0;
test_concurrently("lf_pinbox (without my_thread_init)", test_lf_pinbox, N= THREADS, CYCLES);
test_concurrently("lf_alloc (without my_thread_init)", test_lf_alloc, N= THREADS, CYCLES);
test_concurrently("lf_hash (without my_thread_init)", test_lf_hash, N= THREADS, CYCLES/10);
lf_hash_destroy(&lf_hash); lf_hash_destroy(&lf_hash);
lf_alloc_destroy(&lf_allocator); lf_alloc_destroy(&lf_allocator);