summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBjorn Munch <bjorn.munch@oracle.com>2010-09-01 15:49:43 +0200
committerBjorn Munch <bjorn.munch@oracle.com>2010-09-01 15:49:43 +0200
commit71c0fde0975f262e729d0b4d084b14920c3e975d (patch)
treea0bd3f71fa30f2c02ec4d33b4d66656952002911
parent1f95aa82f1d1df134e9f900612d3588be259e16c (diff)
parent7bd808548ee52e597cb444a2ef36c593d81fce0b (diff)
downloadmariadb-git-71c0fde0975f262e729d0b4d084b14920c3e975d.tar.gz
merge from 5.5
-rw-r--r--client/mysqltest.cc4
-rw-r--r--include/Makefile.am2
-rw-r--r--include/mysql/plugin.h2
-rw-r--r--include/mysql/plugin_audit.h.pp21
-rw-r--r--include/mysql/plugin_ftparser.h.pp21
-rw-r--r--include/mysql/service_thd_wait.h83
-rw-r--r--include/mysql/service_thread_scheduler.h65
-rw-r--r--include/mysql/services.h2
-rw-r--r--include/service_versions.h3
-rw-r--r--include/thr_lock.h2
-rw-r--r--include/violite.h1
-rw-r--r--libservices/CMakeLists.txt6
-rw-r--r--libservices/Makefile.am4
-rw-r--r--libservices/my_thread_scheduler_service.c21
-rw-r--r--libservices/thd_wait_service.c19
-rw-r--r--mysql-test/r/delete.result9
-rw-r--r--mysql-test/r/func_group.result11
-rw-r--r--mysql-test/r/mysqld--help-notwin.result2
-rw-r--r--mysql-test/r/mysqld--help-win.result2
-rw-r--r--mysql-test/r/range.result13
-rw-r--r--mysql-test/suite/innodb/r/innodb_mysql.result58
-rw-r--r--mysql-test/suite/innodb/t/innodb_mysql.test24
-rw-r--r--mysql-test/suite/rpl/r/rpl_flush_logs.result12
-rw-r--r--mysql-test/suite/rpl/t/rpl_flush_logs.test25
-rw-r--r--mysql-test/t/delete.test13
-rw-r--r--mysql-test/t/func_group.test14
-rw-r--r--mysql-test/t/range.test12
-rw-r--r--mysys/my_init.c2
-rw-r--r--mysys/thr_lock.c31
-rw-r--r--sql/authors.h1
-rw-r--r--sql/item_sum.cc20
-rw-r--r--sql/item_sum.h1
-rw-r--r--sql/log.cc117
-rw-r--r--sql/mysqld.cc70
-rw-r--r--sql/mysqld.h6
-rw-r--r--sql/opt_range.cc4
-rw-r--r--sql/scheduler.cc167
-rw-r--r--sql/scheduler.h61
-rw-r--r--sql/sql_callback.h43
-rw-r--r--sql/sql_class.cc75
-rw-r--r--sql/sql_class.h7
-rw-r--r--sql/sql_connect.cc15
-rw-r--r--sql/sql_connect.h4
-rw-r--r--sql/sql_plugin_services.h16
-rw-r--r--sql/sql_select.cc60
-rw-r--r--sql/sql_show.cc19
-rw-r--r--sql/sql_yacc.yy18
-rw-r--r--sql/sys_vars.cc10
-rw-r--r--storage/innobase/buf/buf0flu.c6
-rw-r--r--storage/innobase/buf/buf0rea.c4
-rw-r--r--storage/innobase/srv/srv0srv.c6
-rw-r--r--vio/vio.c10
-rw-r--r--vio/vio_priv.h3
-rw-r--r--vio/viosocket.c4
-rw-r--r--vio/viossl.c5
55 files changed, 983 insertions, 253 deletions
diff --git a/client/mysqltest.cc b/client/mysqltest.cc
index b0e9a3d00be..d96ac057a50 100644
--- a/client/mysqltest.cc
+++ b/client/mysqltest.cc
@@ -5255,10 +5255,8 @@ void do_connect(struct st_command *command)
}
#endif
-#ifndef EMBEDDED_LIBRARY
if (opt_protocol)
mysql_options(&con_slot->mysql, MYSQL_OPT_PROTOCOL, (char*) &opt_protocol);
-#endif
#ifdef HAVE_SMEM
if (con_shm)
@@ -7992,10 +7990,8 @@ int main(int argc, char **argv)
mysql_options(&con->mysql, MYSQL_SET_CHARSET_DIR,
opt_charsets_dir);
-#ifndef EMBEDDED_LIBRARY
if (opt_protocol)
mysql_options(&con->mysql,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol);
-#endif
#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
diff --git a/include/Makefile.am b/include/Makefile.am
index e30588de065..5ddef2d381c 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -26,6 +26,8 @@ HEADERS_ABI = mysql.h mysql_com.h mysql_time.h \
pkginclude_HEADERS = $(HEADERS_ABI) my_dbug.h m_string.h my_sys.h \
my_xml.h mysql_embed.h mysql/services.h \
mysql/service_my_snprintf.h mysql/service_thd_alloc.h \
+ mysql/service_thread_scheduler.h \
+ mysql/service_thd_wait.h \
my_pthread.h my_no_pthread.h \
decimal.h errmsg.h my_global.h my_net.h \
my_getopt.h sslopt-longopts.h my_dir.h \
diff --git a/include/mysql/plugin.h b/include/mysql/plugin.h
index 15f7d785ead..43de7deef74 100644
--- a/include/mysql/plugin.h
+++ b/include/mysql/plugin.h
@@ -71,7 +71,7 @@ typedef struct st_mysql_xid MYSQL_XID;
Plugin API. Common for all plugin types.
*/
-#define MYSQL_PLUGIN_INTERFACE_VERSION 0x0101
+#define MYSQL_PLUGIN_INTERFACE_VERSION 0x0102
/*
The allowable types of plugins
diff --git a/include/mysql/plugin_audit.h.pp b/include/mysql/plugin_audit.h.pp
index 8481b2c92be..b48cbca2e87 100644
--- a/include/mysql/plugin_audit.h.pp
+++ b/include/mysql/plugin_audit.h.pp
@@ -31,6 +31,27 @@ void *thd_memdup(void* thd, const void* str, unsigned int size);
MYSQL_LEX_STRING *thd_make_lex_string(void* thd, MYSQL_LEX_STRING *lex_str,
const char *str, unsigned int size,
int allocate_lex_string);
+#include <mysql/service_thd_wait.h>
+typedef enum _thd_wait_type_e {
+ THD_WAIT_MUTEX= 1,
+ THD_WAIT_DISKIO= 2,
+ THD_WAIT_ROW_TABLE_LOCK= 3,
+ THD_WAIT_GLOBAL_LOCK= 4
+} thd_wait_type;
+extern struct thd_wait_service_st {
+ void (*thd_wait_begin_func)(void*, thd_wait_type);
+ void (*thd_wait_end_func)(void*);
+} *thd_wait_service;
+void thd_wait_begin(void* thd, thd_wait_type wait_type);
+void thd_wait_end(void* thd);
+#include <mysql/service_thread_scheduler.h>
+struct scheduler_functions;
+extern struct my_thread_scheduler_service {
+ int (*set)(struct scheduler_functions *scheduler);
+ int (*reset)();
+} *my_thread_scheduler_service;
+int my_thread_scheduler_set(struct scheduler_functions *scheduler);
+int my_thread_scheduler_reset();
struct st_mysql_xid {
long formatID;
long gtrid_length;
diff --git a/include/mysql/plugin_ftparser.h.pp b/include/mysql/plugin_ftparser.h.pp
index bc77ef48eb7..2c2c1adbf88 100644
--- a/include/mysql/plugin_ftparser.h.pp
+++ b/include/mysql/plugin_ftparser.h.pp
@@ -31,6 +31,27 @@ void *thd_memdup(void* thd, const void* str, unsigned int size);
MYSQL_LEX_STRING *thd_make_lex_string(void* thd, MYSQL_LEX_STRING *lex_str,
const char *str, unsigned int size,
int allocate_lex_string);
+#include <mysql/service_thd_wait.h>
+typedef enum _thd_wait_type_e {
+ THD_WAIT_MUTEX= 1,
+ THD_WAIT_DISKIO= 2,
+ THD_WAIT_ROW_TABLE_LOCK= 3,
+ THD_WAIT_GLOBAL_LOCK= 4
+} thd_wait_type;
+extern struct thd_wait_service_st {
+ void (*thd_wait_begin_func)(void*, thd_wait_type);
+ void (*thd_wait_end_func)(void*);
+} *thd_wait_service;
+void thd_wait_begin(void* thd, thd_wait_type wait_type);
+void thd_wait_end(void* thd);
+#include <mysql/service_thread_scheduler.h>
+struct scheduler_functions;
+extern struct my_thread_scheduler_service {
+ int (*set)(struct scheduler_functions *scheduler);
+ int (*reset)();
+} *my_thread_scheduler_service;
+int my_thread_scheduler_set(struct scheduler_functions *scheduler);
+int my_thread_scheduler_reset();
struct st_mysql_xid {
long formatID;
long gtrid_length;
diff --git a/include/mysql/service_thd_wait.h b/include/mysql/service_thd_wait.h
new file mode 100644
index 00000000000..2a8f5e610a3
--- /dev/null
+++ b/include/mysql/service_thd_wait.h
@@ -0,0 +1,83 @@
+/* Copyright (C) 2010, 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 MYSQL_SERVICE_THD_WAIT_INCLUDED
+#define MYSQL_SERVICE_THD_WAIT_INCLUDED
+
+/**
+ @file include/mysql/service_thd_wait.h
+ This service provides functions for plugins and storage engines to report
+ when they are going to sleep/stall.
+
+ SYNOPSIS
+ thd_wait_begin() - call just before a wait begins
+ thd Thread object
+ Use NULL if the thd is NOT known.
+ wait_type Type of wait
+ 1 -- short wait (e.g. for mutex)
+ 2 -- medium wait (e.g. for disk io)
+ 3 -- large wait (e.g. for locked row/table)
+ NOTES
+ This is used by the threadpool to have better knowledge of which
+ threads that currently are actively running on CPUs. When a thread
+ reports that it's going to sleep/stall, the threadpool scheduler is
+ free to start another thread in the pool most likely. The expected wait
+ time is simply an indication of how long the wait is expected to
+ become, the real wait time could be very different.
+
+ thd_wait_end() called immediately after the wait is complete
+
+ thd_wait_end() MUST be called if thd_wait_begin() was called.
+
+ Using thd_wait_...() service is optional but recommended. Using it will
+ improve performance as the thread pool will be more active at managing the
+ thread workload.
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum _thd_wait_type_e {
+ THD_WAIT_MUTEX= 1,
+ THD_WAIT_DISKIO= 2,
+ THD_WAIT_ROW_TABLE_LOCK= 3,
+ THD_WAIT_GLOBAL_LOCK= 4
+} thd_wait_type;
+
+extern struct thd_wait_service_st {
+ void (*thd_wait_begin_func)(MYSQL_THD, thd_wait_type);
+ void (*thd_wait_end_func)(MYSQL_THD);
+} *thd_wait_service;
+
+#ifdef MYSQL_DYNAMIC_PLUGIN
+
+#define thd_wait_begin(_THD, _WAIT_TYPE) \
+ thd_wait_service->thd_wait_begin_func(_THD, _WAIT_TYPE)
+#define thd_wait_end(_THD) thd_wait_service->thd_wait_end_func(_THD)
+
+#else
+
+void thd_wait_begin(MYSQL_THD thd, thd_wait_type wait_type);
+void thd_wait_end(MYSQL_THD thd);
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/include/mysql/service_thread_scheduler.h b/include/mysql/service_thread_scheduler.h
new file mode 100644
index 00000000000..a4396b721bd
--- /dev/null
+++ b/include/mysql/service_thread_scheduler.h
@@ -0,0 +1,65 @@
+/*
+ Copyright (C) 2010, 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 SERVICE_THREAD_SCHEDULER_INCLUDED
+#define SERVICE_THREAD_SCHEDULER_INCLUDED
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct scheduler_functions;
+
+extern struct my_thread_scheduler_service {
+ int (*set)(struct scheduler_functions *scheduler);
+ int (*reset)();
+} *my_thread_scheduler_service;
+
+#ifdef MYSQL_DYNAMIC_PLUGIN
+
+#define my_thread_scheduler_set(F) my_thread_scheduler_service->set((F))
+#define my_thread_scheduler_reset() my_thread_scheduler_service->reset()
+
+#else
+
+/**
+ Set the thread scheduler to use for the server.
+
+ @param scheduler Pointer to scheduler callbacks to use.
+ @retval 0 Scheduler installed correctly.
+ @retval 1 Invalid value (NULL) used for scheduler.
+*/
+int my_thread_scheduler_set(struct scheduler_functions *scheduler);
+
+/**
+ Restore the previous thread scheduler.
+
+ @note If no thread scheduler was installed previously with
+ thd_set_thread_scheduler, this function will report an error.
+
+ @retval 0 Scheduler installed correctly.
+ @retval 1 No scheduler installed.
+*/
+int my_thread_scheduler_reset();
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SERVICE_THREAD_SCHEDULER_INCLUDED */
diff --git a/include/mysql/services.h b/include/mysql/services.h
index 19003e66b96..6c67a582fb8 100644
--- a/include/mysql/services.h
+++ b/include/mysql/services.h
@@ -20,6 +20,8 @@ extern "C" {
#include <mysql/service_my_snprintf.h>
#include <mysql/service_thd_alloc.h>
+#include <mysql/service_thd_wait.h>
+#include <mysql/service_thread_scheduler.h>
#ifdef __cplusplus
}
diff --git a/include/service_versions.h b/include/service_versions.h
index 114957cdd86..4fd886c8a83 100644
--- a/include/service_versions.h
+++ b/include/service_versions.h
@@ -21,4 +21,5 @@
#define VERSION_my_snprintf 0x0100
#define VERSION_thd_alloc 0x0100
-
+#define VERSION_thd_wait 0x0100
+#define VERSION_my_thread_scheduler 0x0100
diff --git a/include/thr_lock.h b/include/thr_lock.h
index 5626c067e5e..91473737be3 100644
--- a/include/thr_lock.h
+++ b/include/thr_lock.h
@@ -155,6 +155,8 @@ void thr_downgrade_write_lock(THR_LOCK_DATA *data,
enum thr_lock_type new_lock_type);
my_bool thr_reschedule_write_lock(THR_LOCK_DATA *data,
ulong lock_wait_timeout);
+void thr_set_lock_wait_callback(void (*before_wait)(void),
+ void (*after_wait)(void));
#ifdef __cplusplus
}
#endif
diff --git a/include/violite.h b/include/violite.h
index 05ceaa272c1..f4083216894 100644
--- a/include/violite.h
+++ b/include/violite.h
@@ -217,6 +217,7 @@ struct st_vio
void (*timeout)(Vio*, unsigned int which, unsigned int timeout);
my_bool (*poll_read)(Vio *vio, uint timeout);
my_bool (*is_connected)(Vio*);
+ my_bool (*has_data) (Vio*);
#ifdef HAVE_OPENSSL
void *ssl_arg;
#endif
diff --git a/libservices/CMakeLists.txt b/libservices/CMakeLists.txt
index 79431ff65fe..396430fba12 100644
--- a/libservices/CMakeLists.txt
+++ b/libservices/CMakeLists.txt
@@ -15,7 +15,11 @@
INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include)
-SET(MYSQLSERVICES_SOURCES my_snprintf_service.c thd_alloc_service.c)
+SET(MYSQLSERVICES_SOURCES
+ my_snprintf_service.c
+ thd_alloc_service.c
+ thd_wait_service.c
+ my_thread_scheduler_service.c)
ADD_LIBRARY(mysqlservices ${MYSQLSERVICES_SOURCES})
INSTALL(TARGETS mysqlservices DESTINATION ${INSTALL_LIBDIR})
diff --git a/libservices/Makefile.am b/libservices/Makefile.am
index 642081859c1..d25c5c9680c 100644
--- a/libservices/Makefile.am
+++ b/libservices/Makefile.am
@@ -15,5 +15,7 @@
AM_CPPFLAGS = -I$(top_srcdir)/include
pkglib_LIBRARIES = libmysqlservices.a
-libmysqlservices_a_SOURCES = my_snprintf_service.c thd_alloc_service.c
+libmysqlservices_a_SOURCES = my_snprintf_service.c thd_alloc_service.c \
+ thd_wait_service.c \
+ my_thread_scheduler_service.c
EXTRA_DIST = CMakeLists.txt
diff --git a/libservices/my_thread_scheduler_service.c b/libservices/my_thread_scheduler_service.c
new file mode 100644
index 00000000000..dc8d40c6713
--- /dev/null
+++ b/libservices/my_thread_scheduler_service.c
@@ -0,0 +1,21 @@
+/*
+ Copyright (C) 2010, 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
+*/
+
+#include <service_versions.h>
+SERVICE_VERSION my_thread_scheduler_service=
+ (void*)VERSION_my_thread_scheduler;
diff --git a/libservices/thd_wait_service.c b/libservices/thd_wait_service.c
new file mode 100644
index 00000000000..3c87a2d0d1b
--- /dev/null
+++ b/libservices/thd_wait_service.c
@@ -0,0 +1,19 @@
+/*
+ Copyright (C) 2010, 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
+*/
+
+#include <service_versions.h>
+SERVICE_VERSION *thd_wait_service= (void*)VERSION_thd_wait;
diff --git a/mysql-test/r/delete.result b/mysql-test/r/delete.result
index 0c9b0d7d2e5..702b9348b7d 100644
--- a/mysql-test/r/delete.result
+++ b/mysql-test/r/delete.result
@@ -499,4 +499,13 @@ INDEX(a), INDEX(b), INDEX(c));
INSERT INTO t1 VALUES (1,2,3), (4,5,6), (7,8,9);
DELETE FROM t1 WHERE a = 10 OR b = 20 ORDER BY c LIMIT 1;
DROP TABLE t1;
+#
+# Bug #53034: Multiple-table DELETE statements not accepting
+# "Access compatibility" syntax
+#
+CREATE TABLE t1 (id INT);
+CREATE TABLE t2 LIKE t1;
+CREATE TABLE t3 LIKE t1;
+DELETE FROM t1.*, test.t2.*, a.* USING t1, t2, t3 AS a;
+DROP TABLE t1, t2, t3;
End of 5.1 tests
diff --git a/mysql-test/r/func_group.result b/mysql-test/r/func_group.result
index a9b3e98a26f..5f874f4665d 100644
--- a/mysql-test/r/func_group.result
+++ b/mysql-test/r/func_group.result
@@ -1713,6 +1713,17 @@ f1 f2 f3 f4 f1 = f2
NULL NULL NULL NULL NULL
drop table t1;
#
+# Bug #54465: assert: field_types == 0 || field_types[field_pos] ==
+# MYSQL_TYPE_LONGLONG
+#
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1), (2);
+SELECT MAX((SELECT 1 FROM t1 ORDER BY @var LIMIT 1)) m FROM t1 t2, t1
+ORDER BY t1.a;
+m
+1
+DROP TABLE t1;
+#
End of 5.1 tests
#
# Bug#55648: Server crash on MIN/MAX on maximum time value
diff --git a/mysql-test/r/mysqld--help-notwin.result b/mysql-test/r/mysqld--help-notwin.result
index 51703531d8b..025f67082ec 100644
--- a/mysql-test/r/mysqld--help-notwin.result
+++ b/mysql-test/r/mysqld--help-notwin.result
@@ -688,7 +688,7 @@ The following options may be given as the first argument:
How many threads we should keep in a cache for reuse
--thread-handling=name
Define threads usage for handling queries, one of
- one-thread-per-connection, no-threads
+ one-thread-per-connection, no-threads, loaded-dynamically
--thread-stack=# The stack size for each thread
--time-format=name The TIME format (ignored)
--timed-mutexes Specify whether to time mutexes (only InnoDB mutexes are
diff --git a/mysql-test/r/mysqld--help-win.result b/mysql-test/r/mysqld--help-win.result
index 661be6e5678..e1098b71e25 100644
--- a/mysql-test/r/mysqld--help-win.result
+++ b/mysql-test/r/mysqld--help-win.result
@@ -692,7 +692,7 @@ The following options may be given as the first argument:
How many threads we should keep in a cache for reuse
--thread-handling=name
Define threads usage for handling queries, one of
- one-thread-per-connection, no-threads
+ one-thread-per-connection, no-threads, loaded-dynamically
--thread-stack=# The stack size for each thread
--time-format=name The TIME format (ignored)
--timed-mutexes Specify whether to time mutexes (only InnoDB mutexes are
diff --git a/mysql-test/r/range.result b/mysql-test/r/range.result
index aa04bfc25ea..62acb2a7710 100644
--- a/mysql-test/r/range.result
+++ b/mysql-test/r/range.result
@@ -1653,4 +1653,17 @@ a b
0 0
1 1
DROP TABLE t1;
+#
+# Bug #54802: 'NOT BETWEEN' evaluation is incorrect
+#
+CREATE TABLE t1 (c_key INT, c_notkey INT, KEY(c_key));
+INSERT INTO t1 VALUES (1, 1), (2, 2), (3, 3);
+EXPLAIN SELECT * FROM t1 WHERE 2 NOT BETWEEN c_notkey AND c_key;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL c_key NULL NULL NULL 3 Using where
+SELECT * FROM t1 WHERE 2 NOT BETWEEN c_notkey AND c_key;
+c_key c_notkey
+1 1
+3 3
+DROP TABLE t1;
End of 5.1 tests
diff --git a/mysql-test/suite/innodb/r/innodb_mysql.result b/mysql-test/suite/innodb/r/innodb_mysql.result
index ff325b454ad..1adc16456ba 100644
--- a/mysql-test/suite/innodb/r/innodb_mysql.result
+++ b/mysql-test/suite/innodb/r/innodb_mysql.result
@@ -2549,6 +2549,64 @@ LOCK TABLES t1 READ;
ALTER TABLE t1 COMMENT 'test';
UNLOCK TABLES;
DROP TABLE t1;
+#
+# Bug#55656: mysqldump can be slower after bug #39653 fix
+#
+CREATE TABLE t1 (a INT , b INT, c INT, d INT,
+KEY (b), PRIMARY KEY (a,b)) ENGINE=INNODB;
+INSERT INTO t1 VALUES (1,1,1,1), (2,2,2,2), (3,3,3,3);
+EXPLAIN SELECT COUNT(*) FROM t1;
+id 1
+select_type SIMPLE
+table t1
+type index
+possible_keys NULL
+key b
+key_len 4
+ref NULL
+rows 3
+Extra Using index
+DROP INDEX b ON t1;
+CREATE INDEX b ON t1(a,b);
+EXPLAIN SELECT COUNT(*) FROM t1;
+id 1
+select_type SIMPLE
+table t1
+type index
+possible_keys NULL
+key b
+key_len 8
+ref NULL
+rows 3
+Extra Using index
+DROP INDEX b ON t1;
+CREATE INDEX b ON t1(a,b,c);
+EXPLAIN SELECT COUNT(*) FROM t1;
+id 1
+select_type SIMPLE
+table t1
+type index
+possible_keys NULL
+key b
+key_len 13
+ref NULL
+rows 3
+Extra Using index
+DROP INDEX b ON t1;
+CREATE INDEX b ON t1(a,b,c,d);
+EXPLAIN SELECT COUNT(*) FROM t1;
+id 1
+select_type SIMPLE
+table t1
+type index
+possible_keys NULL
+key PRIMARY
+key_len 8
+ref NULL
+rows 3
+Extra Using index
+DROP TABLE t1;
+#
End of 5.1 tests
#
# Test for bug #39932 "create table fails if column for FK is in different
diff --git a/mysql-test/suite/innodb/t/innodb_mysql.test b/mysql-test/suite/innodb/t/innodb_mysql.test
index 8564da6473a..6244670ef57 100644
--- a/mysql-test/suite/innodb/t/innodb_mysql.test
+++ b/mysql-test/suite/innodb/t/innodb_mysql.test
@@ -746,6 +746,30 @@ UNLOCK TABLES;
DROP TABLE t1;
+--echo #
+--echo # Bug#55656: mysqldump can be slower after bug #39653 fix
+--echo #
+
+CREATE TABLE t1 (a INT , b INT, c INT, d INT,
+ KEY (b), PRIMARY KEY (a,b)) ENGINE=INNODB;
+INSERT INTO t1 VALUES (1,1,1,1), (2,2,2,2), (3,3,3,3);
+--query_vertical EXPLAIN SELECT COUNT(*) FROM t1
+
+DROP INDEX b ON t1;
+CREATE INDEX b ON t1(a,b);
+--query_vertical EXPLAIN SELECT COUNT(*) FROM t1
+
+DROP INDEX b ON t1;
+CREATE INDEX b ON t1(a,b,c);
+--query_vertical EXPLAIN SELECT COUNT(*) FROM t1
+
+DROP INDEX b ON t1;
+CREATE INDEX b ON t1(a,b,c,d);
+--query_vertical EXPLAIN SELECT COUNT(*) FROM t1
+
+DROP TABLE t1;
+
+--echo #
--echo End of 5.1 tests
diff --git a/mysql-test/suite/rpl/r/rpl_flush_logs.result b/mysql-test/suite/rpl/r/rpl_flush_logs.result
index 7f50ce0cdd0..4c3352559c4 100644
--- a/mysql-test/suite/rpl/r/rpl_flush_logs.result
+++ b/mysql-test/suite/rpl/r/rpl_flush_logs.result
@@ -4,12 +4,8 @@ reset master;
reset slave;
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
start slave;
-# Make sure the 'master_log.err-old' file does not
-# exist before execute 'flush error logs' statement.
# Test if support 'flush error logs' statement.
flush error logs;
-# Check the 'master_log.err-old' file is created
-# after executed 'flush error logs' statement.
# Make sure binary logs was not be flushed
# after execute 'flush error logs' statement.
# Make sure relay logs was not be flushed
@@ -42,12 +38,8 @@ flush binary logs;
# after executed 'flush binary logs' statement.
# Make sure the 'slave-relay-bin.000007' file does not exist
# exist before execute 'flush error logs, relay logs' statement.
-# Make sure the 'master_log.err-old' file does not exist
-# before execute 'flush error logs, relay logs' statement.
# Test if support to combine all kinds of logs into one statement.
flush error logs, relay logs;
-# Check the 'master_log.err-old' file is created
-# after executed 'flush error logs, relay logs' statement.
# Make sure binary logs was not be flushed
# after execute 'flush error logs, relay logs' statement.
# Check the 'slave-relay-bin.000007' file is created after
@@ -55,12 +47,8 @@ flush error logs, relay logs;
# Make sure the 'slave-relay-bin.000008' and 'slave-relay-bin.000009'
# files do not exist before execute 'flush error logs, relay logs'
# statement.
-# Make sure the 'master_log.err-old' file does not exist
-# before execute 'flush logs' statement.
# Test if 'flush logs' statement works fine and flush all the logs.
flush logs;
-# Check the 'master_log.err-old' file is created
-# after executed 'flush logs' statement.
# Check 'master-bin.000003' is created
# after execute 'flush logs' statement.
# Check the 'slave-relay-bin.000008' and 'slave-relay-bin.000009'
diff --git a/mysql-test/suite/rpl/t/rpl_flush_logs.test b/mysql-test/suite/rpl/t/rpl_flush_logs.test
index 2118b48f946..5159acaae14 100644
--- a/mysql-test/suite/rpl/t/rpl_flush_logs.test
+++ b/mysql-test/suite/rpl/t/rpl_flush_logs.test
@@ -9,17 +9,10 @@
connection master;
# Test 'flush error logs' statement.
---echo # Make sure the 'master_log.err-old' file does not
---echo # exist before execute 'flush error logs' statement.
---error 1
-file_exists $MYSQLTEST_VARDIR/tmp/master_log.err-old;
--echo # Test if support 'flush error logs' statement.
flush error logs;
---echo # Check the 'master_log.err-old' file is created
---echo # after executed 'flush error logs' statement.
-file_exists $MYSQLTEST_VARDIR/tmp/master_log.err-old;
file_exists $MYSQLTEST_VARDIR/tmp/master_log.err;
--echo # Make sure binary logs was not be flushed
@@ -109,19 +102,10 @@ sync_slave_with_master;
file_exists $MYSQLTEST_VARDIR/mysqld.2/data/slave-relay-bin.000007;
connection master;
-remove_file $MYSQLTEST_VARDIR/tmp/master_log.err-old;
-
---echo # Make sure the 'master_log.err-old' file does not exist
---echo # before execute 'flush error logs, relay logs' statement.
---error 1
-file_exists $MYSQLTEST_VARDIR/tmp/master_log.err-old;
--echo # Test if support to combine all kinds of logs into one statement.
flush error logs, relay logs;
---echo # Check the 'master_log.err-old' file is created
---echo # after executed 'flush error logs, relay logs' statement.
-file_exists $MYSQLTEST_VARDIR/tmp/master_log.err-old;
file_exists $MYSQLTEST_VARDIR/tmp/master_log.err;
--echo # Make sure binary logs was not be flushed
@@ -145,19 +129,10 @@ file_exists $MYSQLTEST_VARDIR/mysqld.2/data/slave-relay-bin.000008;
file_exists $MYSQLTEST_VARDIR/mysqld.2/data/slave-relay-bin.000009;
connection master;
-remove_file $MYSQLTEST_VARDIR/tmp/master_log.err-old;
-
---echo # Make sure the 'master_log.err-old' file does not exist
---echo # before execute 'flush logs' statement.
---error 1
-file_exists $MYSQLTEST_VARDIR/tmp/master_log.err-old;
--echo # Test if 'flush logs' statement works fine and flush all the logs.
flush logs;
---echo # Check the 'master_log.err-old' file is created
---echo # after executed 'flush logs' statement.
-file_exists $MYSQLTEST_VARDIR/tmp/master_log.err-old;
file_exists $MYSQLTEST_VARDIR/tmp/master_log.err;
--echo # Check 'master-bin.000003' is created
diff --git a/mysql-test/t/delete.test b/mysql-test/t/delete.test
index a21fff60d33..15aade73ab7 100644
--- a/mysql-test/t/delete.test
+++ b/mysql-test/t/delete.test
@@ -540,4 +540,17 @@ DELETE FROM t1 WHERE a = 10 OR b = 20 ORDER BY c LIMIT 1;
DROP TABLE t1;
+--echo #
+--echo # Bug #53034: Multiple-table DELETE statements not accepting
+--echo # "Access compatibility" syntax
+--echo #
+
+CREATE TABLE t1 (id INT);
+CREATE TABLE t2 LIKE t1;
+CREATE TABLE t3 LIKE t1;
+
+DELETE FROM t1.*, test.t2.*, a.* USING t1, t2, t3 AS a;
+
+DROP TABLE t1, t2, t3;
+
--echo End of 5.1 tests
diff --git a/mysql-test/t/func_group.test b/mysql-test/t/func_group.test
index 04c52dd32bd..6d128be7f34 100644
--- a/mysql-test/t/func_group.test
+++ b/mysql-test/t/func_group.test
@@ -1082,6 +1082,20 @@ select a.f1 as a, b.f4 as b, a.f1 > b.f4 as gt,
from t1 a, t1 b;
select *, f1 = f2 from t1;
drop table t1;
+
+--echo #
+--echo # Bug #54465: assert: field_types == 0 || field_types[field_pos] ==
+--echo # MYSQL_TYPE_LONGLONG
+--echo #
+
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1), (2);
+
+SELECT MAX((SELECT 1 FROM t1 ORDER BY @var LIMIT 1)) m FROM t1 t2, t1
+ ORDER BY t1.a;
+
+DROP TABLE t1;
+
--echo #
--echo End of 5.1 tests
diff --git a/mysql-test/t/range.test b/mysql-test/t/range.test
index 5d5ad180f1a..0ad3d3e8504 100644
--- a/mysql-test/t/range.test
+++ b/mysql-test/t/range.test
@@ -1313,4 +1313,16 @@ SELECT * FROM t1 FORCE INDEX (PRIMARY)
DROP TABLE t1;
+--echo #
+--echo # Bug #54802: 'NOT BETWEEN' evaluation is incorrect
+--echo #
+
+CREATE TABLE t1 (c_key INT, c_notkey INT, KEY(c_key));
+INSERT INTO t1 VALUES (1, 1), (2, 2), (3, 3);
+
+EXPLAIN SELECT * FROM t1 WHERE 2 NOT BETWEEN c_notkey AND c_key;
+SELECT * FROM t1 WHERE 2 NOT BETWEEN c_notkey AND c_key;
+
+DROP TABLE t1;
+
--echo End of 5.1 tests
diff --git a/mysys/my_init.c b/mysys/my_init.c
index d2371278b0c..e3b189c27bb 100644
--- a/mysys/my_init.c
+++ b/mysys/my_init.c
@@ -477,7 +477,7 @@ static my_bool win32_init_tcp_ip()
{
if (win32_have_tcpip())
{
- WORD wVersionRequested = MAKEWORD( 2, 0 );
+ WORD wVersionRequested = MAKEWORD( 2, 2 );
WSADATA wsaData;
/* Be a good citizen: maybe another lib has already initialised
sockets, so dont clobber them unless necessary */
diff --git a/mysys/thr_lock.c b/mysys/thr_lock.c
index 5d870bbc151..d96d08ea0c3 100644
--- a/mysys/thr_lock.c
+++ b/mysys/thr_lock.c
@@ -91,6 +91,16 @@ enum thr_lock_type thr_upgraded_concurrent_insert_lock = TL_WRITE;
LIST *thr_lock_thread_list; /* List of threads in use */
ulong max_write_lock_count= ~(ulong) 0L;
+static void (*before_lock_wait)(void)= 0;
+static void (*after_lock_wait)(void)= 0;
+
+void thr_set_lock_wait_callback(void (*before_wait)(void),
+ void (*after_wait)(void))
+{
+ before_lock_wait= before_wait;
+ after_lock_wait= after_wait;
+}
+
static inline mysql_cond_t *get_cond(void)
{
return &my_thread_var->suspend;
@@ -431,6 +441,19 @@ wait_for_lock(struct st_lock_list *wait, THR_LOCK_DATA *data,
old_proc_info= proc_info_hook(NULL, "Waiting for table level lock",
__func__, __FILE__, __LINE__);
+ /*
+ Since before_lock_wait potentially can create more threads to
+ scheduler work for, we don't want to call the before_lock_wait
+ callback unless it will really start to wait.
+
+ For similar reasons, we do not want to call before_lock_wait and
+ after_lock_wait for each lap around the loop, so we restrict
+ ourselves to call it before_lock_wait once before starting to wait
+ and once after the thread has exited the wait loop.
+ */
+ if ((!thread_var->abort || in_wait_list) && before_lock_wait)
+ (*before_lock_wait)();
+
set_timespec(wait_timeout, lock_wait_timeout);
while (!thread_var->abort || in_wait_list)
{
@@ -462,6 +485,14 @@ wait_for_lock(struct st_lock_list *wait, THR_LOCK_DATA *data,
/* purecov: end */
}
}
+
+ /*
+ We call the after_lock_wait callback once the wait loop has
+ finished.
+ */
+ if (after_lock_wait)
+ (*after_lock_wait)();
+
DBUG_PRINT("thr_lock", ("aborted: %d in_wait_list: %d",
thread_var->abort, in_wait_list));
diff --git a/sql/authors.h b/sql/authors.h
index 5de2659f098..db0ab00fb86 100644
--- a/sql/authors.h
+++ b/sql/authors.h
@@ -93,6 +93,7 @@ struct show_table_authors_st show_table_authors[]= {
{ "Arjen Lentz", "Brisbane, Australia",
"Documentation (2001-2004), Dutch error messages, LOG2()" },
{ "Marc Liyanage", "", "Created Mac OS X packages" },
+ { "Kelly Long", "Denver, CO, USA", "Pool Of Threads" },
{ "Zarko Mocnik", "", "Sorting for Slovenian language" },
{ "Per-Erik Martin", "Uppsala, Sweden", "Stored Procedures (5.0)" },
{ "Alexis Mikhailov", "", "User-defined functions" },
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index bd6e96aedc6..b6e5d6d3182 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -434,26 +434,6 @@ void Item_sum::mark_as_sum_func()
}
-void Item_sum::make_field(Send_field *tmp_field)
-{
- if (args[0]->type() == Item::FIELD_ITEM && keep_field_type())
- {
- ((Item_field*) args[0])->field->make_field(tmp_field);
- /* For expressions only col_name should be non-empty string. */
- char *empty_string= (char*)"";
- tmp_field->db_name= empty_string;
- tmp_field->org_table_name= empty_string;
- tmp_field->table_name= empty_string;
- tmp_field->org_col_name= empty_string;
- tmp_field->col_name= name;
- if (maybe_null)
- tmp_field->flags&= ~NOT_NULL_FLAG;
- }
- else
- init_make_field(tmp_field, field_type());
-}
-
-
void Item_sum::print(String *str, enum_query_type query_type)
{
/* orig_args is not filled with valid values until fix_fields() */
diff --git a/sql/item_sum.h b/sql/item_sum.h
index 2a722b93165..06a8c2c58a4 100644
--- a/sql/item_sum.h
+++ b/sql/item_sum.h
@@ -427,7 +427,6 @@ public:
forced_const= TRUE;
}
virtual bool const_item() const { return forced_const; }
- void make_field(Send_field *field);
virtual void print(String *str, enum_query_type query_type);
void fix_num_length_and_dec();
diff --git a/sql/log.cc b/sql/log.cc
index 5ca22d154b1..88352706318 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -5447,70 +5447,93 @@ void sql_perror(const char *message)
}
+#ifdef __WIN__
+extern "C" my_bool reopen_fstreams(const char *filename,
+ FILE *outstream, FILE *errstream)
+{
+ int handle_fd;
+ int stream_fd;
+ HANDLE osfh;
+
+ DBUG_ASSERT(filename && (outstream || errstream));
+
+ if ((osfh= CreateFile(filename, GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE |
+ FILE_SHARE_DELETE, NULL,
+ OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL,
+ NULL)) == INVALID_HANDLE_VALUE)
+ return TRUE;
+
+ if ((handle_fd= _open_osfhandle((intptr_t)osfh,
+ _O_APPEND | _O_TEXT)) == -1)
+ {
+ CloseHandle(osfh);
+ return TRUE;
+ }
+
+ if (outstream)
+ {
+ stream_fd= _fileno(outstream);
+ if (_dup2(handle_fd, stream_fd) < 0)
+ {
+ CloseHandle(osfh);
+ return TRUE;
+ }
+ }
+
+ if (errstream)
+ {
+ stream_fd= _fileno(errstream);
+ if (_dup2(handle_fd, stream_fd) < 0)
+ {
+ CloseHandle(osfh);
+ return TRUE;
+ }
+ }
+
+ _close(handle_fd);
+ return FALSE;
+}
+#else
+extern "C" my_bool reopen_fstreams(const char *filename,
+ FILE *outstream, FILE *errstream)
+{
+ if (outstream && !freopen(filename, "a+", outstream))
+ return TRUE;
+
+ if (errstream && !freopen(filename, "a+", errstream))
+ return TRUE;
+
+ return FALSE;
+}
+#endif
+
+
/*
Unfortunately, there seems to be no good way
to restore the original streams upon failure.
*/
static bool redirect_std_streams(const char *file)
{
- if (freopen(file, "a+", stdout) && freopen(file, "a+", stderr))
- {
- setbuf(stderr, NULL);
- return FALSE;
- }
+ if (reopen_fstreams(file, stdout, stderr))
+ return TRUE;
- return TRUE;
+ setbuf(stderr, NULL);
+ return FALSE;
}
bool flush_error_log()
{
- bool result=0;
+ bool result= 0;
if (opt_error_log)
{
- char err_renamed[FN_REFLEN], *end;
- end= strmake(err_renamed,log_error_file,FN_REFLEN-5);
- strmov(end, "-old");
mysql_mutex_lock(&LOCK_error_log);
-#ifdef __WIN__
- char err_temp[FN_REFLEN+5];
- /*
- On Windows is necessary a temporary file for to rename
- the current error file.
- */
- strxmov(err_temp, err_renamed,"-tmp",NullS);
- my_delete(err_temp, MYF(0));
- if (freopen(err_temp,"a+",stdout))
- {
- int fd;
- size_t bytes;
- uchar buf[IO_SIZE];
-
- freopen(err_temp,"a+",stderr);
- setbuf(stderr, NULL);
- my_delete(err_renamed, MYF(0));
- my_rename(log_error_file, err_renamed, MYF(0));
- redirect_std_streams(log_error_file);
-
- if ((fd= my_open(err_temp, O_RDONLY, MYF(0))) >= 0)
- {
- while ((bytes= mysql_file_read(fd, buf, IO_SIZE, MYF(0))) &&
- bytes != MY_FILE_ERROR)
- my_fwrite(stderr, buf, bytes, MYF(0));
- mysql_file_close(fd, MYF(0));
- }
- my_delete(err_temp, MYF(0));
- }
- else
- result= 1;
-#else
- my_rename(log_error_file, err_renamed, MYF(0));
- if (redirect_std_streams(log_error_file))
- result= 1;
-#endif
+ if (redirect_std_streams(log_error_file))
+ result= 1;
mysql_mutex_unlock(&LOCK_error_log);
}
- return result;
+ return result;
}
void MYSQL_BIN_LOG::signal_update()
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index d144f7e82aa..6dd74eb299a 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -64,7 +64,9 @@
#include "events.h"
#include "sql_audit.h"
#include "probes_mysql.h"
+#include "scheduler.h"
#include "debug_sync.h"
+#include "sql_callback.h"
#ifdef WITH_PERFSCHEMA_STORAGE_ENGINE
#include "../storage/perfschema/pfs_server.h"
@@ -193,6 +195,9 @@ typedef fp_except fp_except_t;
# endif
#endif
+extern "C" my_bool reopen_fstreams(const char *filename,
+ FILE *outstream, FILE *errstream);
+
inline void setup_fpu()
{
#if defined(__FreeBSD__) && defined(HAVE_IEEEFP_H)
@@ -456,7 +461,7 @@ ulong slave_trans_retries;
uint slave_net_timeout;
ulong slave_exec_mode_options;
ulonglong slave_type_conversions_options;
-ulong thread_cache_size=0, thread_pool_size= 0;
+ulong thread_cache_size=0;
ulong binlog_cache_size=0;
ulonglong max_binlog_cache_size=0;
ulong query_cache_size=0;
@@ -898,8 +903,6 @@ my_bool opt_enable_shared_memory;
HANDLE smem_event_connect_request= 0;
#endif
-scheduler_functions thread_scheduler;
-
my_bool opt_use_ssl = 0;
char *opt_ssl_ca= NULL, *opt_ssl_capath= NULL, *opt_ssl_cert= NULL,
*opt_ssl_cipher= NULL, *opt_ssl_key= NULL;
@@ -1087,7 +1090,8 @@ static void close_connections(void)
continue;
tmp->killed= THD::KILL_CONNECTION;
- thread_scheduler.post_kill_notification(tmp);
+ MYSQL_CALLBACK(thread_scheduler, post_kill_notification, (tmp));
+ mysql_mutex_lock(&tmp->LOCK_thd_data);
if (tmp->mysys_var)
{
tmp->mysys_var->abort=1;
@@ -1100,6 +1104,7 @@ static void close_connections(void)
}
mysql_mutex_unlock(&tmp->mysys_var->mutex);
}
+ mysql_mutex_unlock(&tmp->LOCK_thd_data);
}
mysql_mutex_unlock(&LOCK_thread_count); // For unlink from list
@@ -1479,7 +1484,7 @@ void clean_up(bool print_message)
if (print_message && my_default_lc_messages && server_start_time)
sql_print_information(ER_DEFAULT(ER_SHUTDOWN_COMPLETE),my_progname);
cleanup_errmsgs();
- thread_scheduler.end();
+ MYSQL_CALLBACK(thread_scheduler, end, ());
finish_client_errs();
DBUG_PRINT("quit", ("Error messages freed"));
/* Tell main we are ready */
@@ -1752,7 +1757,7 @@ static void network_init(void)
DBUG_ENTER("network_init");
LINT_INIT(ret);
- if (thread_scheduler.init())
+ if (MYSQL_CALLBACK_ELSE(thread_scheduler, init, (), 0))
unireg_abort(1); /* purecov: inspected */
set_ports();
@@ -2000,7 +2005,7 @@ extern "C" sig_handler end_thread_signal(int sig __attribute__((unused)))
if (thd && ! thd->bootstrap)
{
statistic_increment(killed_threads, &LOCK_status);
- thread_scheduler.end_thread(thd,0); /* purecov: inspected */
+ MYSQL_CALLBACK(thread_scheduler, end_thread, (thd,0)); /* purecov: inspected */
}
DBUG_VOID_RETURN; /* purecov: deadcode */
}
@@ -2396,7 +2401,7 @@ and this may fail.\n\n");
(ulong) dflt_key_cache->key_cache_mem_size);
fprintf(stderr, "read_buffer_size=%ld\n", (long) global_system_variables.read_buff_size);
fprintf(stderr, "max_used_connections=%lu\n", max_used_connections);
- fprintf(stderr, "max_threads=%u\n", thread_scheduler.max_threads);
+ fprintf(stderr, "max_threads=%u\n", thread_scheduler->max_threads);
fprintf(stderr, "thread_count=%u\n", thread_count);
fprintf(stderr, "connection_count=%u\n", connection_count);
fprintf(stderr, "It is possible that mysqld could use up to \n\
@@ -2404,7 +2409,7 @@ key_buffer_size + (read_buffer_size + sort_buffer_size)*max_threads = %lu K\n\
bytes of memory\n", ((ulong) dflt_key_cache->key_cache_mem_size +
(global_system_variables.read_buff_size +
global_system_variables.sortbuff_size) *
- thread_scheduler.max_threads +
+ thread_scheduler->max_threads +
max_connections * sizeof(THD)) / 1024);
fprintf(stderr, "Hope that's ok; if not, decrease some variables in the equation.\n\n");
@@ -2651,7 +2656,7 @@ pthread_handler_t signal_hand(void *arg __attribute__((unused)))
This should actually be '+ max_number_of_slaves' instead of +10,
but the +10 should be quite safe.
*/
- init_thr_alarm(thread_scheduler.max_threads +
+ init_thr_alarm(thread_scheduler->max_threads +
global_system_variables.max_insert_delayed_threads + 10);
if (thd_lib_detected != THD_LIB_LT && (test_flags & TEST_SIGINT))
{
@@ -3738,13 +3743,15 @@ static int init_server_components()
opt_error_log= 0; // Too long file name
else
{
+ my_bool res;
#ifndef EMBEDDED_LIBRARY
- if (freopen(log_error_file, "a+", stdout))
+ res= reopen_fstreams(log_error_file, stdout, stderr);
+#else
+ res= reopen_fstreams(log_error_file, NULL, stderr);
#endif
- {
- if (freopen(log_error_file, "a+", stderr))
- setbuf(stderr, NULL);
- }
+
+ if (!res)
+ setbuf(stderr, NULL);
}
}
@@ -4353,23 +4360,6 @@ int mysqld_main(int argc, char **argv)
}
#endif
-#ifdef __WIN__
- /*
- Before performing any socket operation (like retrieving hostname
- in init_common_variables we have to call WSAStartup
- */
- {
- WSADATA WsaData;
- if (SOCKET_ERROR == WSAStartup (0x0101, &WsaData))
- {
- /* errors are not read yet, so we use english text here */
- my_message(ER_WSAS_FAILED, "WSAStartup Failed", MYF(0));
- /* Not enough initializations for unireg_abort() */
- return 1;
- }
- }
-#endif /* __WIN__ */
-
if (init_common_variables())
unireg_abort(1); // Will do exit
@@ -4457,8 +4447,8 @@ int mysqld_main(int argc, char **argv)
#ifdef __WIN__
if (!opt_console)
{
- freopen(log_error_file,"a+",stdout);
- freopen(log_error_file,"a+",stderr);
+ if (reopen_fstreams(log_error_file, stdout, stderr))
+ unireg_abort(1);
setbuf(stderr, NULL);
FreeConsole(); // Remove window
}
@@ -5028,7 +5018,7 @@ static void create_new_thread(THD *thd)
thread_count++;
- thread_scheduler.add_connection(thd);
+ MYSQL_CALLBACK(thread_scheduler, add_connection, (thd));
DBUG_VOID_RETURN;
}
@@ -7344,14 +7334,12 @@ static int get_options(int *argc_ptr, char ***argv_ptr)
return 1;
#ifdef EMBEDDED_LIBRARY
- one_thread_scheduler(&thread_scheduler);
+ one_thread_scheduler();
#else
if (thread_handling <= SCHEDULER_ONE_THREAD_PER_CONNECTION)
- one_thread_per_connection_scheduler(&thread_scheduler);
- else if (thread_handling == SCHEDULER_NO_THREADS)
- one_thread_scheduler(&thread_scheduler);
- else
- pool_of_threads_scheduler(&thread_scheduler); /* purecov: tested */
+ one_thread_per_connection_scheduler();
+ else /* thread_handling == SCHEDULER_NO_THREADS) */
+ one_thread_scheduler();
#endif
global_system_variables.engine_condition_pushdown=
diff --git a/sql/mysqld.h b/sql/mysqld.h
index 71b52416302..6e81c240f7d 100644
--- a/sql/mysqld.h
+++ b/sql/mysqld.h
@@ -28,7 +28,7 @@ class THD;
struct handlerton;
class Time_zone;
-class scheduler_functions;
+struct scheduler_functions;
typedef struct st_mysql_const_lex_string LEX_CSTRING;
typedef struct st_mysql_show_var SHOW_VAR;
@@ -175,7 +175,7 @@ extern ulong binlog_cache_size, open_files_limit;
extern ulonglong max_binlog_cache_size;
extern ulong max_binlog_size, max_relay_log_size;
extern ulong opt_binlog_rows_event_max_size;
-extern ulong rpl_recovery_rank, thread_cache_size, thread_pool_size;
+extern ulong rpl_recovery_rank, thread_cache_size;
extern ulong back_log;
extern char language[FN_REFLEN];
extern ulong server_id, concurrency;
@@ -207,7 +207,7 @@ extern my_bool old_mode;
extern LEX_STRING opt_init_connect, opt_init_slave;
extern int bootstrap_error;
extern I_List<THD> threads;
-extern scheduler_functions thread_scheduler;
+extern char err_shared_dir[];
extern TYPELIB thread_handling_typelib;
extern my_decimal decimal_zero;
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index af5b4b7c7d6..b9819def54d 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -5620,7 +5620,11 @@ static SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param,COND *cond)
SEL_TREE *tmp= get_full_func_mm_tree(param, cond_func,
field_item, (Item*)(intptr)i, inv);
if (inv)
+ {
tree= !tree ? tmp : tree_or(param, tree, tmp);
+ if (tree == NULL)
+ break;
+ }
else
tree= tree_and(param, tree, tmp);
}
diff --git a/sql/scheduler.cc b/sql/scheduler.cc
index 10009246428..d61a452b99e 100644
--- a/sql/scheduler.cc
+++ b/sql/scheduler.cc
@@ -25,55 +25,103 @@
#include "unireg.h" // REQUIRED: for other includes
#include "scheduler.h"
#include "sql_connect.h" // init_new_connection_handler_thread
+#include "scheduler.h"
+#include "sql_callback.h"
/*
- 'Dummy' functions to be used when we don't need any handling for a scheduler
- event
- */
+ End connection, in case when we are using 'no-threads'
+*/
-static bool init_dummy(void) {return 0;}
-static void post_kill_dummy(THD* thd) {}
-static void end_dummy(void) {}
-static bool end_thread_dummy(THD *thd, bool cache_thread) { return 0; }
+static bool no_threads_end(THD *thd, bool put_in_cache)
+{
+ unlink_thd(thd);
+ mysql_mutex_unlock(&LOCK_thread_count);
+ return 1; // Abort handle_one_connection
+}
-/*
- Initialize default scheduler with dummy functions so that setup functions
- only need to declare those that are relvant for their usage
+static scheduler_functions one_thread_scheduler_functions=
+{
+ 1, // max_threads
+ NULL, // init
+ init_new_connection_handler_thread, // init_new_connection_thread
+#ifndef EMBEDDED_LIBRARY
+ handle_connection_in_main_thread, // add_connection
+#else
+ NULL, // add_connection
+#endif // EMBEDDED_LIBRARY
+ NULL, // thd_wait_begin
+ NULL, // thd_wait_end
+ NULL, // post_kill_notification
+ no_threads_end, // end_thread
+ NULL, // end
+};
+
+#ifndef EMBEDDED_LIBRARY
+static scheduler_functions one_thread_per_connection_scheduler_functions=
+{
+ 0, // max_threads
+ NULL, // init
+ init_new_connection_handler_thread, // init_new_connection_thread
+ create_thread_to_handle_connection, // add_connection
+ NULL, // thd_wait_begin
+ NULL, // thd_wait_end
+ NULL, // post_kill_notification
+ one_thread_per_connection_end, // end_thread
+ NULL, // end
+};
+#endif // EMBEDDED_LIBRARY
+
+
+scheduler_functions *thread_scheduler= NULL;
+
+/** @internal
+ Helper functions to allow mysys to call the thread scheduler when
+ waiting for locks.
*/
-scheduler_functions::scheduler_functions()
- :init(init_dummy),
- init_new_connection_thread(init_new_connection_handler_thread),
- add_connection(0), // Must be defined
- post_kill_notification(post_kill_dummy),
- end_thread(end_thread_dummy), end(end_dummy)
-{}
+/**@{*/
+static void scheduler_wait_begin(void) {
+ MYSQL_CALLBACK(thread_scheduler,
+ thd_wait_begin, (current_thd, THD_WAIT_ROW_TABLE_LOCK));
+}
+
+static void scheduler_wait_end(void) {
+ MYSQL_CALLBACK(thread_scheduler, thd_wait_end, (current_thd));
+}
+/**@}*/
+/**
+ Common scheduler init function.
+
+ The scheduler is either initialized by calling
+ one_thread_scheduler() or one_thread_per_connection_scheduler() in
+ mysqld.cc, so this init function will always be called.
+ */
+static void scheduler_init() {
+ thr_set_lock_wait_callback(scheduler_wait_begin, scheduler_wait_end);
+}
/*
- End connection, in case when we are using 'no-threads'
+ Initialize scheduler for --thread-handling=one-thread-per-connection
*/
-static bool no_threads_end(THD *thd, bool put_in_cache)
+#ifndef EMBEDDED_LIBRARY
+void one_thread_per_connection_scheduler()
{
- unlink_thd(thd);
- mysql_mutex_unlock(&LOCK_thread_count);
- return 1; // Abort handle_one_connection
+ scheduler_init();
+ one_thread_per_connection_scheduler_functions.max_threads= max_connections;
+ thread_scheduler= &one_thread_per_connection_scheduler_functions;
}
-
+#endif
/*
Initailize scheduler for --thread-handling=no-threads
*/
-void one_thread_scheduler(scheduler_functions* func)
+void one_thread_scheduler()
{
- func->max_threads= 1;
-#ifndef EMBEDDED_LIBRARY
- func->add_connection= handle_connection_in_main_thread;
-#endif
- func->init_new_connection_thread= init_dummy;
- func->end_thread= no_threads_end;
+ scheduler_init();
+ thread_scheduler= &one_thread_scheduler_functions;
}
@@ -81,11 +129,58 @@ void one_thread_scheduler(scheduler_functions* func)
Initialize scheduler for --thread-handling=one-thread-per-connection
*/
-#ifndef EMBEDDED_LIBRARY
-void one_thread_per_connection_scheduler(scheduler_functions* func)
+/*
+ thd_scheduler keeps the link between THD and events.
+ It's embedded in the THD class.
+*/
+
+thd_scheduler::thd_scheduler()
+ : m_psi(NULL), data(NULL)
+{
+#ifndef DBUG_OFF
+ dbug_explain[0]= '\0';
+ set_explain= FALSE;
+#endif
+}
+
+
+thd_scheduler::~thd_scheduler()
+{
+}
+
+static scheduler_functions *saved_thread_scheduler;
+static uint saved_thread_handling;
+
+extern "C"
+int my_thread_scheduler_set(scheduler_functions *scheduler)
+{
+ DBUG_ASSERT(scheduler != 0);
+
+ if (scheduler == NULL)
+ return 1;
+
+ saved_thread_scheduler= thread_scheduler;
+ saved_thread_handling= thread_handling;
+ thread_scheduler= scheduler;
+ // Scheduler loaded dynamically
+ thread_handling= SCHEDULER_TYPES_COUNT;
+ return 0;
+}
+
+
+extern "C"
+int my_thread_scheduler_reset()
{
- func->max_threads= max_connections;
- func->add_connection= create_thread_to_handle_connection;
- func->end_thread= one_thread_per_connection_end;
+ DBUG_ASSERT(saved_thread_scheduler != NULL);
+
+ if (saved_thread_scheduler == NULL)
+ return 1;
+
+ thread_scheduler= saved_thread_scheduler;
+ thread_handling= saved_thread_handling;
+ saved_thread_scheduler= 0;
+ return 0;
}
-#endif /* EMBEDDED_LIBRARY */
+
+
+
diff --git a/sql/scheduler.h b/sql/scheduler.h
index e7916031a27..40f0e28bc2c 100644
--- a/sql/scheduler.h
+++ b/sql/scheduler.h
@@ -28,38 +28,77 @@ class THD;
/* Functions used when manipulating threads */
-class scheduler_functions
+struct scheduler_functions
{
-public:
uint max_threads;
bool (*init)(void);
bool (*init_new_connection_thread)(void);
void (*add_connection)(THD *thd);
+ void (*thd_wait_begin)(THD *thd, int wait_type);
+ void (*thd_wait_end)(THD *thd);
void (*post_kill_notification)(THD *thd);
bool (*end_thread)(THD *thd, bool cache_thread);
void (*end)(void);
- scheduler_functions();
};
+
+/**
+ Scheduler types enumeration.
+
+ The default of --thread-handling is the first one in the
+ thread_handling_names array, this array has to be consistent with
+ the order in this array, so to change default one has to change the
+ first entry in this enum and the first entry in the
+ thread_handling_names array.
+
+ @note The last entry of the enumeration is also used to mark the
+ thread handling as dynamic. In this case the name of the thread
+ handling is fetched from the name of the plugin that implements it.
+*/
enum scheduler_types
{
SCHEDULER_ONE_THREAD_PER_CONNECTION=0,
SCHEDULER_NO_THREADS,
- SCHEDULER_POOL_OF_THREADS
+ SCHEDULER_TYPES_COUNT
};
-void one_thread_per_connection_scheduler(scheduler_functions* func);
-void one_thread_scheduler(scheduler_functions* func);
+void one_thread_per_connection_scheduler();
+void one_thread_scheduler();
enum pool_command_op
{
NOT_IN_USE_OP= 0, NORMAL_OP= 1, CONNECT_OP, KILL_OP, DIE_OP
};
-#define HAVE_POOL_OF_THREADS 0 /* For easyer tests */
-#define pool_of_threads_scheduler(A) one_thread_per_connection_scheduler(A)
-
+/*
+ To be used for pool-of-threads (implemeneted differently on various OSs)
+*/
class thd_scheduler
-{};
+{
+public:
+ /*
+ Thread instrumentation for the user job.
+ This member holds the instrumentation while the user job is not run
+ by a thread.
+
+ Note that this member is not conditionally declared
+ (ifdef HAVE_PSI_INTERFACE), because doing so will change the binary
+ layout of THD, which is exposed to plugin code that may be compiled
+ differently.
+ */
+ PSI_thread *m_psi;
+
+ void *data; /* scheduler-specific data structure */
+
+# ifndef DBUG_OFF
+ char dbug_explain[512];
+ bool set_explain;
+# endif
-#endif /* SCHEDULER_INCLUDED */
+ thd_scheduler();
+ ~thd_scheduler();
+};
+
+extern scheduler_functions *thread_scheduler;
+
+#endif
diff --git a/sql/sql_callback.h b/sql/sql_callback.h
new file mode 100644
index 00000000000..430514d3d7e
--- /dev/null
+++ b/sql/sql_callback.h
@@ -0,0 +1,43 @@
+/*
+ Copyright (C) 2010, 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 SQL_CALLBACK_INCLUDED
+#define SQL_CALLBACK_INCLUDED
+
+/**
+ Macro used for an internal callback.
+
+ The macro will check that the object exists and that the function
+ is defined. If that is the case, it will call the function with the
+ given parameters.
+
+ If the object or the function is not defined, the callback will be
+ considered successful (nothing needed to be done) and will
+ therefore return no error.
+ */
+
+#define MYSQL_CALLBACK(OBJ, FUNC, PARAMS) \
+ do { \
+ if ((OBJ) && ((OBJ)->FUNC)) \
+ (OBJ)->FUNC PARAMS; \
+ } while (0)
+
+#define MYSQL_CALLBACK_ELSE(OBJ, FUNC, PARAMS, ELSE) \
+ (((OBJ) && ((OBJ)->FUNC)) ? (OBJ)->FUNC PARAMS : (ELSE))
+
+
+#endif /* SQL_CALLBACK_INCLUDED */
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index bde56777d52..f65e5c05826 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -57,6 +57,7 @@
#include "transaction.h"
#include "debug_sync.h"
#include "sql_parse.h" // is_update_query
+#include "sql_callback.h"
/*
The following is used to initialise Table_ident with a internal
@@ -1075,6 +1076,7 @@ THD::~THD()
DBUG_ENTER("~THD()");
/* Ensure that no one is using THD */
mysql_mutex_lock(&LOCK_thd_data);
+ mysys_var=0; // Safety (shouldn't be needed)
mysql_mutex_unlock(&LOCK_thd_data);
add_to_status(&global_status_var, &status_var);
@@ -1100,7 +1102,6 @@ THD::~THD()
my_free(db);
db= NULL;
free_root(&transaction.mem_root,MYF(0));
- mysys_var=0; // Safety (shouldn't be needed)
mysql_mutex_destroy(&LOCK_thd_data);
#ifndef DBUG_OFF
dbug_sentry= THD_SENTRY_GONE;
@@ -1189,7 +1190,7 @@ void THD::awake(THD::killed_state state_to_set)
{
thr_alarm_kill(thread_id);
if (!slave_thread)
- thread_scheduler.post_kill_notification(this);
+ MYSQL_CALLBACK(thread_scheduler, post_kill_notification, (this));
#ifdef SIGNAL_WITH_VIO_CLOSE
if (this != current_thd)
{
@@ -1258,6 +1259,15 @@ bool THD::store_globals()
if (my_pthread_setspecific_ptr(THR_THD, this) ||
my_pthread_setspecific_ptr(THR_MALLOC, &mem_root))
return 1;
+ /*
+ mysys_var is concurrently readable by a killer thread.
+ It is protected by LOCK_thd_data, it is not needed to lock while the
+ pointer is changing from NULL not non-NULL. If the kill thread reads
+ NULL it doesn't refer to anything, but if it is non-NULL we need to
+ ensure that the thread doesn't proceed to assign another thread to
+ have the mysys_var reference (which in fact refers to the worker
+ threads local storage with key THR_KEY_mysys.
+ */
mysys_var=my_thread_var;
/*
Let mysqld define the thread id (not mysys)
@@ -3187,6 +3197,60 @@ extern "C" bool thd_sqlcom_can_generate_row_events(const MYSQL_THD thd)
{
return sqlcom_can_generate_row_events(thd);
}
+
+#ifndef EMBEDDED_LIBRARY
+extern "C" void thd_pool_wait_begin(MYSQL_THD thd, int wait_type);
+extern "C" void thd_pool_wait_end(MYSQL_THD thd);
+
+/*
+ Interface for MySQL Server, plugins and storage engines to report
+ when they are going to sleep/stall.
+
+ SYNOPSIS
+ thd_wait_begin()
+ thd Thread object
+ wait_type Type of wait
+ 1 -- short wait (e.g. for mutex)
+ 2 -- medium wait (e.g. for disk io)
+ 3 -- large wait (e.g. for locked row/table)
+ NOTES
+ This is used by the threadpool to have better knowledge of which
+ threads that currently are actively running on CPUs. When a thread
+ reports that it's going to sleep/stall, the threadpool scheduler is
+ free to start another thread in the pool most likely. The expected wait
+ time is simply an indication of how long the wait is expected to
+ become, the real wait time could be very different.
+
+ 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)
+{
+ MYSQL_CALLBACK(thread_scheduler, thd_wait_begin, (thd, wait_type));
+}
+
+/**
+ Interface for MySQL Server, plugins and storage engines to report
+ when they waking up from a sleep/stall.
+
+ @param thd Thread handle
+*/
+extern "C" void thd_wait_end(MYSQL_THD thd)
+{
+ MYSQL_CALLBACK(thread_scheduler, thd_wait_end, (thd));
+}
+#else
+extern "C" void thd_wait_begin(MYSQL_THD thd, thd_wait_type wait_type)
+{
+ /* do NOTHING for the embedded library */
+ return;
+}
+
+extern "C" void thd_wait_end(MYSQL_THD thd)
+{
+ /* do NOTHING for the embedded library */
+ return;
+}
+#endif
#endif // INNODB_COMPATIBILITY_HOOKS */
/****************************************************************************
@@ -3370,6 +3434,13 @@ void THD::set_query_id(query_id_t new_query_id)
mysql_mutex_unlock(&LOCK_thd_data);
}
+/** Assign a new value to thd->mysys_var. */
+void THD::set_mysys_var(struct st_my_thread_var *new_mysys_var)
+{
+ mysql_mutex_lock(&LOCK_thd_data);
+ mysys_var= new_mysys_var;
+ mysql_mutex_unlock(&LOCK_thd_data);
+}
/**
Leave explicit LOCK TABLES or prelocked mode and restore value of
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 462fbf9a264..e86e42dc094 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -1634,6 +1634,10 @@ public:
xid_state.xid.null();
free_root(&mem_root,MYF(MY_KEEP_PREALLOC));
}
+ my_bool is_active()
+ {
+ return (all.ha_list != NULL);
+ }
st_transactions()
{
bzero((char*)this, sizeof(*this));
@@ -2664,7 +2668,7 @@ public:
virtual void set_statement(Statement *stmt);
/**
- Assign a new value to thd->query and thd->query_id.
+ Assign a new value to thd->query and thd->query_id and mysys_var.
Protected with LOCK_thd_data mutex.
*/
void set_query(char *query_arg, uint32 query_length_arg);
@@ -2677,6 +2681,7 @@ public:
open_tables= open_tables_arg;
mysql_mutex_unlock(&LOCK_thd_data);
}
+ void set_mysys_var(struct st_my_thread_var *new_mysys_var);
void enter_locked_tables_mode(enum_locked_tables_mode mode_arg)
{
DBUG_ASSERT(locked_tables_mode == LTM_NONE);
diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc
index 003203b5466..3ba6deed0a4 100644
--- a/sql/sql_connect.cc
+++ b/sql/sql_connect.cc
@@ -35,6 +35,7 @@
#include "hostname.h" // inc_host_errors, ip_to_hostname,
// reset_host_errors
#include "sql_acl.h" // acl_getroot, NO_ACCESS, SUPER_ACL
+#include "sql_callback.h"
#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
/*
@@ -966,7 +967,7 @@ bool setup_connection_thread_globals(THD *thd)
{
close_connection(thd, ER_OUT_OF_RESOURCES, 1);
statistic_increment(aborted_connects,&LOCK_status);
- thread_scheduler.end_thread(thd, 0);
+ MYSQL_CALLBACK(thread_scheduler, end_thread, (thd, 0));
return 1; // Error
}
return 0;
@@ -989,7 +990,7 @@ bool setup_connection_thread_globals(THD *thd)
*/
-static bool login_connection(THD *thd)
+bool login_connection(THD *thd)
{
NET *net= &thd->net;
int error;
@@ -1027,7 +1028,7 @@ static bool login_connection(THD *thd)
This mainly updates status variables
*/
-static void end_connection(THD *thd)
+void end_connection(THD *thd)
{
NET *net= &thd->net;
plugin_thdvar_cleanup(thd);
@@ -1068,7 +1069,7 @@ static void end_connection(THD *thd)
Initialize THD to handle queries
*/
-static void prepare_new_connection_state(THD* thd)
+void prepare_new_connection_state(THD* thd)
{
Security_context *sctx= thd->security_ctx;
@@ -1137,11 +1138,11 @@ void do_handle_one_connection(THD *thd_arg)
thd->thr_create_utime= my_micro_time();
- if (thread_scheduler.init_new_connection_thread())
+ if (MYSQL_CALLBACK_ELSE(thread_scheduler, init_new_connection_thread, (), 0))
{
close_connection(thd, ER_OUT_OF_RESOURCES, 1);
statistic_increment(aborted_connects,&LOCK_status);
- thread_scheduler.end_thread(thd,0);
+ MYSQL_CALLBACK(thread_scheduler, end_thread, (thd, 0));
return;
}
@@ -1195,7 +1196,7 @@ void do_handle_one_connection(THD *thd_arg)
end_thread:
close_connection(thd, 0, 1);
- if (thread_scheduler.end_thread(thd,1))
+ if (MYSQL_CALLBACK_ELSE(thread_scheduler, end_thread, (thd, 1), 0))
return; // Probably no-threads
/*
diff --git a/sql/sql_connect.h b/sql/sql_connect.h
index 2334b7303be..bfcc04ba093 100644
--- a/sql/sql_connect.h
+++ b/sql/sql_connect.h
@@ -40,4 +40,8 @@ int check_user(THD *thd, enum enum_server_command command,
const char *passwd, uint passwd_len, const char *db,
bool check_count);
+bool login_connection(THD *thd);
+void prepare_new_connection_state(THD* thd);
+void end_connection(THD *thd);
+
#endif /* SQL_CONNECT_INCLUDED */
diff --git a/sql/sql_plugin_services.h b/sql/sql_plugin_services.h
index 7491ddab79d..f39e22f1e21 100644
--- a/sql/sql_plugin_services.h
+++ b/sql/sql_plugin_services.h
@@ -36,9 +36,23 @@ static struct thd_alloc_service_st thd_alloc_handler= {
thd_make_lex_string
};
+static struct thd_wait_service_st thd_wait_handler= {
+ thd_wait_begin,
+ thd_wait_end
+};
+
+static struct my_thread_scheduler_service my_thread_scheduler_handler= {
+ my_thread_scheduler_set,
+ my_thread_scheduler_reset,
+};
+
+
static struct st_service_ref list_of_services[]=
{
{ "my_snprintf_service", VERSION_my_snprintf, &my_snprintf_handler },
- { "thd_alloc_service", VERSION_thd_alloc, &thd_alloc_handler }
+ { "thd_alloc_service", VERSION_thd_alloc, &thd_alloc_handler },
+ { "thd_wait_service", VERSION_thd_wait, &thd_wait_handler },
+ { "my_thread_scheduler_service",
+ VERSION_my_thread_scheduler, &my_thread_scheduler_handler },
};
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 2dabeeaa22e..29a78cb31dc 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -13243,6 +13243,34 @@ ok:
}
+/**
+ Find shortest key suitable for full table scan.
+
+ @param table Table to scan
+ @param usable_keys Allowed keys
+
+ @note
+ As far as
+ 1) clustered primary key entry data set is a set of all record
+ fields (key fields and not key fields) and
+ 2) secondary index entry data is a union of its key fields and
+ primary key fields (at least InnoDB and its derivatives don't
+ duplicate primary key fields there, even if the primary and
+ the secondary keys have a common subset of key fields),
+ then secondary index entry data is always a subset of primary key entry.
+ Unfortunately, key_info[nr].key_length doesn't show the length
+ of key/pointer pair but a sum of key field lengths only, thus
+ we can't estimate index IO volume comparing only this key_length
+ value of secondary keys and clustered PK.
+ So, try secondary keys first, and choose PK only if there are no
+ usable secondary covering keys or found best secondary key include
+ all table fields (i.e. same as PK):
+
+ @return
+ MAX_KEY no suitable key found
+ key index otherwise
+*/
+
uint find_shortest_key(TABLE *table, const key_map *usable_keys)
{
uint best= MAX_KEY;
@@ -13255,23 +13283,6 @@ uint find_shortest_key(TABLE *table, const key_map *usable_keys)
uint min_length= (uint) ~0;
for (uint nr=0; nr < table->s->keys ; nr++)
{
- /*
- As far as
- 1) clustered primary key entry data set is a set of all record
- fields (key fields and not key fields) and
- 2) secondary index entry data is a union of its key fields and
- primary key fields (at least InnoDB and its derivatives don't
- duplicate primary key fields there, even if the primary and
- the secondary keys have a common subset of key fields),
- then secondary index entry data is always a subset of primary key
- entry, and the PK is always longer.
- Unfortunately, key_info[nr].key_length doesn't show the length
- of key/pointer pair but a sum of key field lengths only, thus
- we can't estimate index IO volume comparing only this key_length
- value of seconday keys and clustered PK.
- So, try secondary keys first, and choose PK only if there are no
- usable secondary covering keys:
- */
if (nr == usable_clustered_pk)
continue;
if (usable_keys->is_set(nr))
@@ -13284,7 +13295,20 @@ uint find_shortest_key(TABLE *table, const key_map *usable_keys)
}
}
}
- return best != MAX_KEY ? best : usable_clustered_pk;
+ if (usable_clustered_pk != MAX_KEY)
+ {
+ /*
+ If the primary key is clustered and found shorter key covers all table
+ fields then primary key scan normally would be faster because amount of
+ data to scan is the same but PK is clustered.
+ It's safe to compare key parts with table fields since duplicate key
+ parts aren't allowed.
+ */
+ if (best == MAX_KEY ||
+ table->key_info[best].key_parts >= table->s->fields)
+ best= usable_clustered_pk;
+ }
+ return best;
}
/**
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 3f0c0b9eaf9..6b24e3db7bc 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -1815,6 +1815,7 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose)
if ((thd_info->db=tmp->db)) // Safe test
thd_info->db=thd->strdup(thd_info->db);
thd_info->command=(int) tmp->command;
+ mysql_mutex_lock(&tmp->LOCK_thd_data);
if ((mysys_var= tmp->mysys_var))
mysql_mutex_lock(&mysys_var->mutex);
thd_info->proc_info= (char*) (tmp->killed == THD::KILL_CONNECTION? "Killed" : 0);
@@ -1822,16 +1823,15 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose)
if (mysys_var)
mysql_mutex_unlock(&mysys_var->mutex);
- thd_info->start_time= tmp->start_time;
thd_info->query=0;
/* Lock THD mutex that protects its data when looking at it. */
- mysql_mutex_lock(&tmp->LOCK_thd_data);
if (tmp->query())
{
uint length= min(max_query_length, tmp->query_length());
thd_info->query= (char*) thd->strmake(tmp->query(),length);
}
mysql_mutex_unlock(&tmp->LOCK_thd_data);
+ thd_info->start_time= tmp->start_time;
thread_infos.append(thd_info);
}
}
@@ -1918,6 +1918,7 @@ int fill_schema_processlist(THD* thd, TABLE_LIST* tables, COND* cond)
table->field[3]->set_notnull();
}
+ mysql_mutex_lock(&tmp->LOCK_thd_data);
if ((mysys_var= tmp->mysys_var))
mysql_mutex_lock(&mysys_var->mutex);
/* COMMAND */
@@ -1938,6 +1939,7 @@ int fill_schema_processlist(THD* thd, TABLE_LIST* tables, COND* cond)
if (mysys_var)
mysql_mutex_unlock(&mysys_var->mutex);
+ mysql_mutex_unlock(&tmp->LOCK_thd_data);
/* INFO */
/* Lock THD mutex that protects its data when looking at it. */
@@ -7490,13 +7492,16 @@ int finalize_schema_table(st_plugin_int *plugin)
ST_SCHEMA_TABLE *schema_table= (ST_SCHEMA_TABLE *)plugin->data;
DBUG_ENTER("finalize_schema_table");
- if (schema_table && plugin->plugin->deinit)
+ if (schema_table)
{
- DBUG_PRINT("info", ("Deinitializing plugin: '%s'", plugin->name.str));
- if (plugin->plugin->deinit(NULL))
+ if (plugin->plugin->deinit)
{
- DBUG_PRINT("warning", ("Plugin '%s' deinit function returned error.",
- plugin->name.str));
+ DBUG_PRINT("info", ("Deinitializing plugin: '%s'", plugin->name.str));
+ if (plugin->plugin->deinit(NULL))
+ {
+ DBUG_PRINT("warning", ("Plugin '%s' deinit function returned error.",
+ plugin->name.str));
+ }
}
my_free(schema_table);
}
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 6a510c04054..cc0a7869b5b 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -1425,6 +1425,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%type <table>
table_ident table_ident_nodb references xid
+ table_ident_opt_wild
%type <simple_string>
remember_name remember_end opt_db text_or_password
@@ -10371,7 +10372,7 @@ table_alias_ref_list:
;
table_alias_ref:
- table_ident
+ table_ident_opt_wild
{
if (!Select->add_table_to_list(YYTHD, $1, NULL,
TL_OPTION_UPDATING | TL_OPTION_ALIAS,
@@ -12161,6 +12162,21 @@ table_ident:
}
;
+table_ident_opt_wild:
+ ident opt_wild
+ {
+ $$= new Table_ident($1);
+ if ($$ == NULL)
+ MYSQL_YYABORT;
+ }
+ | ident '.' ident opt_wild
+ {
+ $$= new Table_ident(YYTHD, $1,$3,0);
+ if ($$ == NULL)
+ MYSQL_YYABORT;
+ }
+ ;
+
table_ident_nodb:
ident
{
diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc
index f63a43ccd76..ca3447dcc82 100644
--- a/sql/sys_vars.cc
+++ b/sql/sys_vars.cc
@@ -1673,19 +1673,13 @@ static Sys_var_ulong Sys_trans_prealloc_size(
static const char *thread_handling_names[]=
{
- "one-thread-per-connection", "no-threads",
-#if HAVE_POOL_OF_THREADS == 1
- "pool-of-threads",
-#endif
+ "one-thread-per-connection", "no-threads", "loaded-dynamically",
0
};
static Sys_var_enum Sys_thread_handling(
"thread_handling",
"Define threads usage for handling queries, one of "
- "one-thread-per-connection, no-threads"
-#if HAVE_POOL_OF_THREADS == 1
- ", pool-of-threads"
-#endif
+ "one-thread-per-connection, no-threads, loaded-dynamically"
, READ_ONLY GLOBAL_VAR(thread_handling), CMD_LINE(REQUIRED_ARG),
thread_handling_names, DEFAULT(0));
diff --git a/storage/innobase/buf/buf0flu.c b/storage/innobase/buf/buf0flu.c
index 4131d863e6a..7b51fc60fcc 100644
--- a/storage/innobase/buf/buf0flu.c
+++ b/storage/innobase/buf/buf0flu.c
@@ -43,6 +43,8 @@ Created 11/11/1995 Heikki Tuuri
#include "log0log.h"
#include "os0file.h"
#include "trx0sys.h"
+#include "mysql/plugin.h"
+#include "mysql/service_thd_wait.h"
/**********************************************************************
These statistics are generated for heuristics used in estimating the
@@ -1744,10 +1746,14 @@ buf_flush_wait_batch_end(
buf_pool = buf_pool_from_array(i);
+ thd_wait_begin(NULL, THD_WAIT_DISKIO);
os_event_wait(buf_pool->no_flush[type]);
+ thd_wait_end(NULL);
}
} else {
+ thd_wait_begin(NULL, THD_WAIT_DISKIO);
os_event_wait(buf_pool->no_flush[type]);
+ thd_wait_end(NULL);
}
}
diff --git a/storage/innobase/buf/buf0rea.c b/storage/innobase/buf/buf0rea.c
index 99a56bf91bc..82b45172988 100644
--- a/storage/innobase/buf/buf0rea.c
+++ b/storage/innobase/buf/buf0rea.c
@@ -37,6 +37,8 @@ Created 11/5/1995 Heikki Tuuri
#include "os0file.h"
#include "srv0start.h"
#include "srv0srv.h"
+#include "mysql/plugin.h"
+#include "mysql/service_thd_wait.h"
/** The linear read-ahead area size */
#define BUF_READ_AHEAD_LINEAR_AREA BUF_READ_AHEAD_AREA
@@ -135,6 +137,7 @@ buf_read_page_low(
ut_ad(buf_page_in_file(bpage));
+ thd_wait_begin(NULL, THD_WAIT_DISKIO);
if (zip_size) {
*err = fil_io(OS_FILE_READ | wake_later,
sync, space, zip_size, offset, 0, zip_size,
@@ -146,6 +149,7 @@ buf_read_page_low(
sync, space, 0, offset, 0, UNIV_PAGE_SIZE,
((buf_block_t*) bpage)->frame, bpage);
}
+ thd_wait_end(NULL);
ut_a(*err == DB_SUCCESS);
if (sync) {
diff --git a/storage/innobase/srv/srv0srv.c b/storage/innobase/srv/srv0srv.c
index bea8d7f8fdc..b2da43c188b 100644
--- a/storage/innobase/srv/srv0srv.c
+++ b/storage/innobase/srv/srv0srv.c
@@ -84,6 +84,8 @@ Created 10/8/1995 Heikki Tuuri
#include "ha_prototypes.h"
#include "trx0i_s.h"
#include "os0sync.h" /* for HAVE_ATOMIC_BUILTINS */
+#include "mysql/plugin.h"
+#include "mysql/service_thd_wait.h"
/* This is set to TRUE if the MySQL user has set it in MySQL; currently
affects only FOREIGN KEY definition parsing */
@@ -1232,7 +1234,9 @@ retry:
trx->op_info = "waiting in InnoDB queue";
+ thd_wait_begin(trx->mysql_thd, THD_WAIT_ROW_TABLE_LOCK);
os_event_wait(slot->event);
+ thd_wait_end(trx->mysql_thd);
trx->op_info = "";
@@ -1597,7 +1601,9 @@ srv_suspend_mysql_thread(
/* Suspend this thread and wait for the event. */
+ thd_wait_begin(trx->mysql_thd, THD_WAIT_ROW_TABLE_LOCK);
os_event_wait(event);
+ thd_wait_end(trx->mysql_thd);
/* After resuming, reacquire the data dictionary latch if
necessary. */
diff --git a/vio/vio.c b/vio/vio.c
index 67704a56b22..48f103c33e8 100644
--- a/vio/vio.c
+++ b/vio/vio.c
@@ -44,6 +44,11 @@ static my_bool no_poll_read(Vio *vio __attribute__((unused)),
#endif
+static my_bool has_no_data(Vio *vio __attribute__((unused)))
+{
+ return FALSE;
+}
+
/*
* Helper to fill most of the Vio* with defaults.
*/
@@ -83,6 +88,7 @@ static void vio_init(Vio* vio, enum enum_vio_type type,
vio->poll_read =no_poll_read;
vio->is_connected =vio_is_connected_pipe;
+ vio->has_data =has_no_data;
vio->timeout=vio_win32_timeout;
/* Set default timeout */
@@ -110,6 +116,7 @@ static void vio_init(Vio* vio, enum enum_vio_type type,
vio->poll_read =no_poll_read;
vio->is_connected =vio_is_connected_shared_memory;
+ vio->has_data =has_no_data;
/* Currently, shared memory is on Windows only, hence the below is ok*/
vio->timeout= vio_win32_timeout;
@@ -137,6 +144,7 @@ static void vio_init(Vio* vio, enum enum_vio_type type,
vio->timeout =vio_timeout;
vio->poll_read =vio_poll_read;
vio->is_connected =vio_is_connected;
+ vio->has_data =vio_ssl_has_data;
DBUG_VOID_RETURN;
}
#endif /* HAVE_OPENSSL */
@@ -155,6 +163,8 @@ static void vio_init(Vio* vio, enum enum_vio_type type,
vio->timeout =vio_timeout;
vio->poll_read =vio_poll_read;
vio->is_connected =vio_is_connected;
+ vio->has_data= (flags & VIO_BUFFERED_READ) ?
+ vio_buff_has_data : has_no_data;
DBUG_VOID_RETURN;
}
diff --git a/vio/vio_priv.h b/vio/vio_priv.h
index 69eb26083d6..1bfb857b039 100644
--- a/vio/vio_priv.h
+++ b/vio/vio_priv.h
@@ -49,6 +49,7 @@ int vio_close_shared_memory(Vio * vio);
#endif
void vio_timeout(Vio *vio,uint which, uint timeout);
+my_bool vio_buff_has_data(Vio *vio);
#ifdef HAVE_OPENSSL
#include "my_net.h" /* needed because of struct in_addr */
@@ -62,5 +63,7 @@ void vio_ssl_delete(Vio *vio);
int vio_ssl_blocking(Vio *vio, my_bool set_blocking_mode, my_bool *old_mode);
+my_bool vio_ssl_has_data(Vio *vio);
+
#endif /* HAVE_OPENSSL */
#endif /* VIO_PRIV_INCLUDED */
diff --git a/vio/viosocket.c b/vio/viosocket.c
index 9c0243db4f3..163eb279d45 100644
--- a/vio/viosocket.c
+++ b/vio/viosocket.c
@@ -98,6 +98,10 @@ size_t vio_read_buff(Vio *vio, uchar* buf, size_t size)
#undef VIO_UNBUFFERED_READ_MIN_SIZE
}
+my_bool vio_buff_has_data(Vio *vio)
+{
+ return (vio->read_pos != vio->read_end);
+}
size_t vio_write(Vio * vio, const uchar* buf, size_t size)
{
diff --git a/vio/viossl.c b/vio/viossl.c
index 79f358b047c..5cb5f36f20d 100644
--- a/vio/viossl.c
+++ b/vio/viossl.c
@@ -244,6 +244,9 @@ int vio_ssl_blocking(Vio *vio __attribute__((unused)),
return (set_blocking_mode ? 0 : 1);
}
-
+my_bool vio_ssl_has_data(Vio *vio)
+{
+ return SSL_pending(vio->ssl_arg) > 0 ? TRUE : FALSE;
+}
#endif /* HAVE_OPENSSL */