From 78ea8ad425f2dc650b07e33d4724bbb21a9d1f17 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Mon, 10 Aug 2020 18:03:05 +0000 Subject: [PATCH 01/70] MDEV-23378 - fix an alleged memory "leak" in threadpool. Implement a workaround to shut the "memory not freed" message. --- sql/threadpool_generic.cc | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/sql/threadpool_generic.cc b/sql/threadpool_generic.cc index 02eb336facb..78b57340a6b 100644 --- a/sql/threadpool_generic.cc +++ b/sql/threadpool_generic.cc @@ -1084,7 +1084,10 @@ void thread_group_destroy(thread_group_t *thread_group) #endif if (my_atomic_add32(&shutdown_group_count, -1) == 1) + { my_free(all_groups); + all_groups= 0; + } } /** @@ -1677,6 +1680,14 @@ TP_pool_generic::~TP_pool_generic() { thread_group_close(&all_groups[i]); } + + /* + Wait until memory occupied by all_groups is freed. + */ + int timeout_ms=5000; + while(all_groups && timeout_ms--) + my_sleep(1000); + threadpool_started= false; DBUG_VOID_RETURN; } From caf105905af16a840c16cd4bc728f4b14bb76f1a Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Tue, 11 Aug 2020 10:33:10 +0400 Subject: [PATCH 02/70] Fixing sporading builtbot test failures happening at '00:00:00' sharp Some tests relied on the fact that DATETIME->DATE conversion always produce a truncation (with a warning). This is not the case when the SQL statement is executed at current time '00:00:00' sharp. Adding a new SET TIMESTAMP statements to make sure time is not '00:00:00'. --- mysql-test/r/type_date.result | 2 ++ mysql-test/r/type_datetime.result | 4 ++++ mysql-test/t/type_date.test | 6 ++++++ mysql-test/t/type_datetime.test | 5 +++++ 4 files changed, 17 insertions(+) diff --git a/mysql-test/r/type_date.result b/mysql-test/r/type_date.result index 1a5a1d1c756..c945591fa07 100644 --- a/mysql-test/r/type_date.result +++ b/mysql-test/r/type_date.result @@ -429,6 +429,7 @@ select @a; # # BUG LP:1008487 virtual bool Item_cache::is_expensive(): Assertion `example' failed # +SET TIMESTAMP=UNIX_TIMESTAMP('2012-01-01 00:00:01'); create table t1(a date,key(a)); insert into t1 values ('2012-01-01'),('2012-02-02'); explain @@ -440,6 +441,7 @@ id select_type table type possible_keys key key_len ref rows Extra select 1 from t1 as t1_0 inner join t1 as t2 on (t1_0.a <=> now()) join t1 on 1; 1 drop table t1; +SET TIMESTAMP=DEFAULT; # # MDEV-9521 Least function returns 0000-00-00 for null date columns instead of null # MDEV-9972 Least function retuns date in date time format diff --git a/mysql-test/r/type_datetime.result b/mysql-test/r/type_datetime.result index 3468ff67b53..26e852f116c 100644 --- a/mysql-test/r/type_datetime.result +++ b/mysql-test/r/type_datetime.result @@ -57,6 +57,7 @@ select * from t1; t 0000-00-00 00:00:00 drop table t1; +SET TIMESTAMP=UNIX_TIMESTAMP('2020-08-11 00:00:01'); CREATE TABLE t1 (a timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, b date, c time, d datetime); insert into t1 (b,c,d) values(now(),curtime(),now()); Warnings: @@ -65,6 +66,7 @@ select date_format(a,"%Y-%m-%d")=b,right(a+0,6)=c+0,a=d+0 from t1; date_format(a,"%Y-%m-%d")=b right(a+0,6)=c+0 a=d+0 1 1 1 drop table t1; +SET TIMESTAMP=DEFAULT; CREATE TABLE t1 (a datetime not null); insert into t1 values (0); select * from t1 where a is null; @@ -298,8 +300,10 @@ f2 f3 select f2 from t1 where DATE(f2) between "2001-4-15" AND "01-4-15"; f2 2001-04-15 00:00:00 +SET timestamp=UNIX_TIMESTAMP('2001-01-01 00:00:01'); SELECT 1 from dual where NOW() BETWEEN CURRENT_DATE() - INTERVAL 1 DAY AND CURRENT_DATE(); 1 +SET timestamp=DEFAULT; drop table t1; create table t1 (f1 date); insert into t1 values('01-01-01'),('01-01-02'),('01-01-03'); diff --git a/mysql-test/t/type_date.test b/mysql-test/t/type_date.test index c86bc730392..91f4a8250f6 100644 --- a/mysql-test/t/type_date.test +++ b/mysql-test/t/type_date.test @@ -369,12 +369,18 @@ select @a; --echo # --echo # BUG LP:1008487 virtual bool Item_cache::is_expensive(): Assertion `example' failed --echo # + +# Set timestamp to make sure DATETIME->DATE truncation happens. +# Otherwise, the warning would disappear at '00:00:00' sharp, +# and a different execution plan would be chosen. +SET TIMESTAMP=UNIX_TIMESTAMP('2012-01-01 00:00:01'); create table t1(a date,key(a)); insert into t1 values ('2012-01-01'),('2012-02-02'); explain select 1 from t1 as t1_0 inner join t1 as t2 on (t1_0.a <=> now()) join t1 on 1; select 1 from t1 as t1_0 inner join t1 as t2 on (t1_0.a <=> now()) join t1 on 1; drop table t1; +SET TIMESTAMP=DEFAULT; --echo # --echo # MDEV-9521 Least function returns 0000-00-00 for null date columns instead of null diff --git a/mysql-test/t/type_datetime.test b/mysql-test/t/type_datetime.test index 447a5d4b192..f2ef5030a6a 100644 --- a/mysql-test/t/type_datetime.test +++ b/mysql-test/t/type_datetime.test @@ -32,10 +32,12 @@ drop table t1; # Test insert of now() and curtime() # +SET TIMESTAMP=UNIX_TIMESTAMP('2020-08-11 00:00:01'); CREATE TABLE t1 (a timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, b date, c time, d datetime); insert into t1 (b,c,d) values(now(),curtime(),now()); select date_format(a,"%Y-%m-%d")=b,right(a+0,6)=c+0,a=d+0 from t1; drop table t1; +SET TIMESTAMP=DEFAULT; # # Test of datetime and not null @@ -201,6 +203,7 @@ drop table t1; # # Bug#16377: Wrong DATE/DATETIME comparison in BETWEEN function. # + create table t1 (f1 date, f2 datetime, f3 timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP); insert into t1 values('2001-01-01','2001-01-01 01:01:01','2001-01-01 01:01:01'); insert into t1 values('2001-02-05','2001-02-05 00:00:00','2001-02-05 01:01:01'); @@ -214,7 +217,9 @@ select f1, f2, f3 from t1 where cast(f1 as datetime) between f2 and select f2 from t1 where '2001-04-10 12:34:56' between f2 and '01-05-01'; select f2, f3 from t1 where '01-03-10' between f2 and f3; select f2 from t1 where DATE(f2) between "2001-4-15" AND "01-4-15"; +SET timestamp=UNIX_TIMESTAMP('2001-01-01 00:00:01'); SELECT 1 from dual where NOW() BETWEEN CURRENT_DATE() - INTERVAL 1 DAY AND CURRENT_DATE(); +SET timestamp=DEFAULT; drop table t1; # From 57d1a5fa8ed925b03d28aea3fab82de0823e68a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Mon, 10 Aug 2020 11:44:42 +0300 Subject: [PATCH 03/70] MDEV-22543 : Galera SST donation fails, FLUSH TABLES WITH READ LOCK times out During SST we need to let FTWRL to use normal timeout method even when client is disconnected. --- mysql-test/suite/galera/r/mdev-22543.result | 17 ++++++ mysql-test/suite/galera/t/mdev-22543.test | 58 +++++++++++++++++++++ sql/mdl.cc | 25 ++++++--- sql/wsrep_sst.cc | 13 ++++- sql/wsrep_sst.h | 2 + 5 files changed, 106 insertions(+), 9 deletions(-) create mode 100644 mysql-test/suite/galera/r/mdev-22543.result create mode 100644 mysql-test/suite/galera/t/mdev-22543.test diff --git a/mysql-test/suite/galera/r/mdev-22543.result b/mysql-test/suite/galera/r/mdev-22543.result new file mode 100644 index 00000000000..02f2b632b32 --- /dev/null +++ b/mysql-test/suite/galera/r/mdev-22543.result @@ -0,0 +1,17 @@ +connection node_1; +connection node_2; +connection node_1; +CREATE TABLE t1 (f1 INT PRIMARY KEY, f2 INT); +INSERT INTO t1 VALUES (1, 1); +SET DEBUG_SYNC = "before_lock_tables_takes_lock SIGNAL sync_point_reached WAIT_FOR sync_point_continue"; +UPDATE t1 SET f2 = 2 WHERE f1 = 1; +connection node_1_ctrl; +SET DEBUG_SYNC = "now WAIT_FOR sync_point_reached"; +connection node_2; +connection node_1_ctrl; +SET DEBUG_SYNC = "now SIGNAL sync_point_continue"; +connection node_1; +SET DEBUG_SYNC = "RESET"; +connection node_2; +connection node_1; +DROP TABLE t1; diff --git a/mysql-test/suite/galera/t/mdev-22543.test b/mysql-test/suite/galera/t/mdev-22543.test new file mode 100644 index 00000000000..53662e36942 --- /dev/null +++ b/mysql-test/suite/galera/t/mdev-22543.test @@ -0,0 +1,58 @@ +# The test verifies that the FLUSH TABLES WITH READ LOCK does not +# time out if it needs to wait for another MDL lock for short duration +# during SST donation. + +--source include/galera_cluster.inc +--source include/have_debug.inc +--source include/have_debug_sync.inc + +--let $node_1 = node_1 +--let $node_2 = node_2 +--source include/auto_increment_offset_save.inc + +--let $galera_connection_name = node_1_ctrl +--let $galera_server_number = 1 +--source include/galera_connect.inc + +# +# Run UPDATE on node_1 and make it block before table locks are taken. +# This should block FTWRL. +# +--connection node_1 +CREATE TABLE t1 (f1 INT PRIMARY KEY, f2 INT); +INSERT INTO t1 VALUES (1, 1); +SET DEBUG_SYNC = "before_lock_tables_takes_lock SIGNAL sync_point_reached WAIT_FOR sync_point_continue"; +--send UPDATE t1 SET f2 = 2 WHERE f1 = 1 + +--connection node_1_ctrl +SET DEBUG_SYNC = "now WAIT_FOR sync_point_reached"; + +# +# Restart node_2, force SST. +# +--connection node_2 +--source include/shutdown_mysqld.inc +--remove_file $MYSQLTEST_VARDIR/mysqld.2/data/grastate.dat +# Restart without waiting. The UPDATE should block FTWRL on node_1, +# so the SST cannot be completed and node_2 cannot join before +# UPDATE connection is signalled to continue. +--exec echo "restart:$start_mysqld_params" > $_expect_file_name +# If the bug is present, FTWRL times out on node_1 in couple of +# seconds and node_2 fails to join. +--sleep 10 + +--connection node_1_ctrl +SET DEBUG_SYNC = "now SIGNAL sync_point_continue"; + +--connection node_1 +--reap +SET DEBUG_SYNC = "RESET"; + +--connection node_2 +--enable_reconnect +--source include/wait_until_connected_again.inc + +--connection node_1 +DROP TABLE t1; + +--source include/auto_increment_offset_restore.inc diff --git a/sql/mdl.cc b/sql/mdl.cc index 9eeb82eeffd..14a1f17fe86 100644 --- a/sql/mdl.cc +++ b/sql/mdl.cc @@ -25,6 +25,7 @@ #include #include "wsrep_mysqld.h" #include "wsrep_thd.h" +#include "wsrep_sst.h" #ifdef HAVE_PSI_INTERFACE static PSI_mutex_key key_MDL_wait_LOCK_wait_status; @@ -2137,18 +2138,26 @@ MDL_context::acquire_lock(MDL_request *mdl_request, double lock_wait_timeout) wait_status= m_wait.timed_wait(m_owner, &abs_shortwait, FALSE, mdl_request->key.get_wait_state_name()); + THD* thd= m_owner->get_thd(); + if (wait_status != MDL_wait::EMPTY) break; /* Check if the client is gone while we were waiting. */ - if (! thd_is_connected(m_owner->get_thd())) + if (! thd_is_connected(thd)) { - /* - * The client is disconnected. Don't wait forever: - * assume it's the same as a wait timeout, this - * ensures all error handling is correct. - */ - wait_status= MDL_wait::TIMEOUT; - break; +#if defined(WITH_WSREP) && !defined(EMBEDDED_LIBRARY) + // During SST client might not be connected + if (!wsrep_is_sst_progress()) +#endif + { + /* + * The client is disconnected. Don't wait forever: + * assume it's the same as a wait timeout, this + * ensures all error handling is correct. + */ + wait_status= MDL_wait::TIMEOUT; + break; + } } mysql_prlock_wrlock(&lock->m_rwlock); diff --git a/sql/wsrep_sst.cc b/sql/wsrep_sst.cc index 9472d66f4d3..a6accd52910 100644 --- a/sql/wsrep_sst.cc +++ b/sql/wsrep_sst.cc @@ -192,6 +192,7 @@ bool wsrep_before_SE() static bool sst_complete = false; static bool sst_needed = false; +static bool sst_in_progress = false; #define WSREP_EXTEND_TIMEOUT_INTERVAL 30 #define WSREP_TIMEDWAIT_SECONDS 10 @@ -1542,7 +1543,10 @@ static void* sst_donor_thread (void* a) char out_buf[out_len]; wsrep_uuid_t ret_uuid= WSREP_UUID_UNDEFINED; - wsrep_seqno_t ret_seqno= WSREP_SEQNO_UNDEFINED; // seqno of complete SST + // seqno of complete SST + wsrep_seqno_t ret_seqno= WSREP_SEQNO_UNDEFINED; + // SST is now in progress + sst_in_progress= true; wsp::thd thd(FALSE); // we turn off wsrep_on for this THD so that it can // operate with wsrep_ready == OFF @@ -1644,6 +1648,8 @@ wait_signal: wsrep->sst_sent (wsrep, &state_id, -err); proc.wait(); + sst_in_progress= false; + return NULL; } @@ -1818,3 +1824,8 @@ void wsrep_SE_initialized() { SE_initialized = true; } + +bool wsrep_is_sst_progress() +{ + return (sst_in_progress); +} diff --git a/sql/wsrep_sst.h b/sql/wsrep_sst.h index 063cab5f0f1..5a749d529fb 100644 --- a/sql/wsrep_sst.h +++ b/sql/wsrep_sst.h @@ -74,12 +74,14 @@ extern void wsrep_SE_init_grab(); /*! grab init critical section */ extern void wsrep_SE_init_wait(); /*! wait for SE init to complete */ extern void wsrep_SE_init_done(); /*! signal that SE init is complte */ extern void wsrep_SE_initialized(); /*! mark SE initialization complete */ +extern bool wsrep_is_sst_progress(); #else #define wsrep_SE_initialized() do { } while(0) #define wsrep_SE_init_grab() do { } while(0) #define wsrep_SE_init_done() do { } while(0) #define wsrep_sst_continue() (0) +#define wsrep_is_sst_progress() (0) #endif /* WITH_WSREP */ #endif /* WSREP_SST_H */ From 7ad4709a3b621c6fe56d653a2bb5018bf4234875 Mon Sep 17 00:00:00 2001 From: Julius Goryavsky Date: Tue, 4 Aug 2020 14:25:58 +0200 Subject: [PATCH 04/70] MDEV-21526: mysqld_multi no longer works with different server binaries The problem is caused by the fact that adding the --defaults-group-suffix option to fix MDEV-18863 causes mysqld to read all options from the appropriate sections of the config file, including options specific to mysqld_multi. Reading unknown options (which are not supported by mysqld) causes mysqld to terminate with an error. However, the MDEV-18863 problem has been completely fixed by passing options on the command line, and now there is no need to specify the --defaults-group-suffix option (we just need to give priority to options passed through the command line, so as not to break MDEV-18863). --- scripts/mysqld_multi.sh | 14 +------------- scripts/wsrep_sst_mariabackup.sh | 25 +++++++++++++++++-------- scripts/wsrep_sst_rsync.sh | 8 +++++--- scripts/wsrep_sst_xtrabackup-v2.sh | 3 ++- 4 files changed, 25 insertions(+), 25 deletions(-) diff --git a/scripts/mysqld_multi.sh b/scripts/mysqld_multi.sh index 5f359551f0d..3aad68ffb6e 100644 --- a/scripts/mysqld_multi.sh +++ b/scripts/mysqld_multi.sh @@ -308,9 +308,7 @@ sub report_mysqlds sub start_mysqlds() { - my (@groups, $com, $tmp, $i, @options, $j, $mysqld_found, $suffix_found, $info_sent); - - $suffix_found= 0; + my (@groups, $com, $tmp, $i, @options, $j, $mysqld_found, $info_sent); if (!$opt_no_log) { @@ -349,10 +347,6 @@ sub start_mysqlds() $options[$j]= quote_shell_word($options[$j]); $tmp.= " $options[$j]"; } - elsif ("--defaults-group-suffix=" eq substr($options[$j], 0, 24)) - { - $suffix_found= 1; - } else { $options[$j]= quote_shell_word($options[$j]); @@ -369,12 +363,6 @@ sub start_mysqlds() $info_sent= 1; } - if (!$suffix_found) - { - $com.= " --defaults-group-suffix="; - $com.= substr($groups[$i],6); - } - $com.= $tmp; if ($opt_wsrep_new_cluster) { diff --git a/scripts/wsrep_sst_mariabackup.sh b/scripts/wsrep_sst_mariabackup.sh index a2d10beee06..2fce421e4eb 100644 --- a/scripts/wsrep_sst_mariabackup.sh +++ b/scripts/wsrep_sst_mariabackup.sh @@ -713,7 +713,8 @@ INNODB_DATA_HOME_DIR=${INNODB_DATA_HOME_DIR:-""} if [ ! -z "$INNODB_DATA_HOME_DIR_ARG" ]; then INNODB_DATA_HOME_DIR=$INNODB_DATA_HOME_DIR_ARG fi -# if INNODB_DATA_HOME_DIR env. variable is not set, try to get it from my.cnf +# if no command line arg and INNODB_DATA_HOME_DIR environment variable +# is not set, try to get it from my.cnf: if [ -z "$INNODB_DATA_HOME_DIR" ]; then INNODB_DATA_HOME_DIR=$(parse_cnf mysqld$WSREP_SST_OPT_SUFFIX_VALUE innodb-data-home-dir '') fi @@ -961,17 +962,25 @@ then ib_home_dir=$INNODB_DATA_HOME_DIR - # Try to set ib_log_dir from the command line: - ib_log_dir=$INNODB_LOG_GROUP_HOME_ARG - if [ -z "$ib_log_dir" ]; then - ib_log_dir=$(parse_cnf mysqld$WSREP_SST_OPT_SUFFIX_VALUE innodb-log-group-home-dir "") + WSREP_LOG_DIR=${WSREP_LOG_DIR:-""} + # Try to set WSREP_LOG_DIR from the command line: + if [ ! -z "$INNODB_LOG_GROUP_HOME_ARG" ]; then + WSREP_LOG_DIR=$INNODB_LOG_GROUP_HOME_ARG fi - if [ -z "$ib_log_dir" ]; then - ib_log_dir=$(parse_cnf --mysqld innodb-log-group-home-dir "") + # if no command line arg and WSREP_LOG_DIR is not set, + # try to get it from my.cnf: + if [ -z "$WSREP_LOG_DIR" ]; then + WSREP_LOG_DIR=$(parse_cnf mysqld$WSREP_SST_OPT_SUFFIX_VALUE innodb-log-group-home-dir '') + fi + if [ -z "$WSREP_LOG_DIR" ]; then + WSREP_LOG_DIR=$(parse_cnf --mysqld innodb-log-group-home-dir '') fi + ib_log_dir=$WSREP_LOG_DIR + # Try to set ib_undo_dir from the command line: - ib_undo_dir=$INNODB_UNDO_DIR_ARG + ib_undo_dir=${INNODB_UNDO_DIR_ARG:-""} + # if no command line arg then try to get it from my.cnf: if [ -z "$ib_undo_dir" ]; then ib_undo_dir=$(parse_cnf mysqld$WSREP_SST_OPT_SUFFIX_VALUE innodb-undo-directory "") fi diff --git a/scripts/wsrep_sst_rsync.sh b/scripts/wsrep_sst_rsync.sh index 8fbb32135d7..890cd213b42 100644 --- a/scripts/wsrep_sst_rsync.sh +++ b/scripts/wsrep_sst_rsync.sh @@ -112,10 +112,11 @@ fi WSREP_LOG_DIR=${WSREP_LOG_DIR:-""} # Try to set WSREP_LOG_DIR from the command line: -if [ -z "$WSREP_LOG_DIR" ]; then +if [ ! -z "$INNODB_LOG_GROUP_HOME_ARG" ]; then WSREP_LOG_DIR=$INNODB_LOG_GROUP_HOME_ARG fi -# if WSREP_LOG_DIR env. variable is not set, try to get it from my.cnf +# if no command line arg and WSREP_LOG_DIR is not set, +# try to get it from my.cnf: if [ -z "$WSREP_LOG_DIR" ]; then WSREP_LOG_DIR=$(parse_cnf mysqld$WSREP_SST_OPT_SUFFIX_VALUE innodb-log-group-home-dir '') fi @@ -136,7 +137,8 @@ INNODB_DATA_HOME_DIR=${INNODB_DATA_HOME_DIR:-""} if [ ! -z "$INNODB_DATA_HOME_DIR_ARG" ]; then INNODB_DATA_HOME_DIR=$INNODB_DATA_HOME_DIR_ARG fi -# if INNODB_DATA_HOME_DIR env. variable is not set, try to get it from my.cnf +# if no command line arg and INNODB_DATA_HOME_DIR environment variable +# is not set, try to get it from my.cnf: if [ -z "$INNODB_DATA_HOME_DIR" ]; then INNODB_DATA_HOME_DIR=$(parse_cnf mysqld$WSREP_SST_OPT_SUFFIX_VALUE innodb-data-home-dir '') fi diff --git a/scripts/wsrep_sst_xtrabackup-v2.sh b/scripts/wsrep_sst_xtrabackup-v2.sh index 75601e5c180..8fbbeda170c 100644 --- a/scripts/wsrep_sst_xtrabackup-v2.sh +++ b/scripts/wsrep_sst_xtrabackup-v2.sh @@ -904,7 +904,8 @@ INNODB_DATA_HOME_DIR=${INNODB_DATA_HOME_DIR:-""} if [ ! -z "$INNODB_DATA_HOME_DIR_ARG" ]; then INNODB_DATA_HOME_DIR=$INNODB_DATA_HOME_DIR_ARG fi -# if INNODB_DATA_HOME_DIR env. variable is not set, try to get it from my.cnf +# if no command line arg and INNODB_DATA_HOME_DIR environment variable +# is not set, try to get it from my.cnf: if [ -z "$INNODB_DATA_HOME_DIR" ]; then INNODB_DATA_HOME_DIR=$(parse_cnf mysqld$WSREP_SST_OPT_SUFFIX_VALUE innodb-data-home-dir '') fi From 31aef3ae99dff6b7154cf288b3dc508d367f19f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 11 Aug 2020 15:48:58 +0300 Subject: [PATCH 05/70] Fix GCC 10.2.0 -Og -Wmaybe-uninitialized For some reason, GCC emits more -Wmaybe-uninitialized warnings when using the flag -Og than when using -O2. Many of the warnings look genuine. --- extra/mariabackup/backup_copy.cc | 2 +- plugin/server_audit/server_audit.c | 62 ++++++++++++++++-------------- sql/item.cc | 4 +- sql/item_geofunc.cc | 17 ++++---- sql/mysqld.cc | 56 ++++++++++++--------------- sql/sql_time.cc | 2 +- storage/innobase/fts/fts0que.cc | 2 +- storage/maria/ma_create.c | 3 +- storage/maria/ma_loghandler.c | 3 +- storage/myisam/mi_create.c | 3 +- strings/ctype-ucs2.c | 2 +- 11 files changed, 78 insertions(+), 78 deletions(-) diff --git a/extra/mariabackup/backup_copy.cc b/extra/mariabackup/backup_copy.cc index 6f9452ef76c..1cde4a4cf13 100644 --- a/extra/mariabackup/backup_copy.cc +++ b/extra/mariabackup/backup_copy.cc @@ -1786,7 +1786,7 @@ apply_log_finish() bool copy_back() { - bool ret; + bool ret = false; datadir_iter_t *it = NULL; datadir_node_t node; char *dst_dir; diff --git a/plugin/server_audit/server_audit.c b/plugin/server_audit/server_audit.c index 8e468cf486d..1061c207a75 100644 --- a/plugin/server_audit/server_audit.c +++ b/plugin/server_audit/server_audit.c @@ -1428,7 +1428,6 @@ static size_t escape_string_hide_passwords(const char *str, unsigned int len, const char *res_start= result; const char *res_end= result + result_len - 2; size_t d_len; - char b_char; while (len) { @@ -1466,27 +1465,28 @@ static size_t escape_string_hide_passwords(const char *str, unsigned int len, if (*next_s) { - memmove(result + d_len, "*****", 5); + const char b_char= *next_s++; + memset(result + d_len, '*', 5); result+= d_len + 5; - b_char= *(next_s++); + + while (*next_s) + { + if (*next_s == b_char) + { + ++next_s; + break; + } + if (*next_s == '\\') + { + if (next_s[1]) + next_s++; + } + next_s++; + } } else result+= d_len; - while (*next_s) - { - if (*next_s == b_char) - { - ++next_s; - break; - } - if (*next_s == '\\') - { - if (next_s[1]) - next_s++; - } - next_s++; - } len-= (uint)(next_s - str); str= next_s; continue; @@ -1494,19 +1494,23 @@ static size_t escape_string_hide_passwords(const char *str, unsigned int len, no_password: if (result >= res_end) break; - if ((b_char= escaped_char(*str))) - { - if (result+1 >= res_end) - break; - *(result++)= '\\'; - *(result++)= b_char; - } - else if (is_space(*str)) - *(result++)= ' '; else - *(result++)= *str; - str++; - len--; + { + const char b_char= escaped_char(*str); + if (b_char) + { + if (result+1 >= res_end) + break; + *(result++)= '\\'; + *(result++)= b_char; + } + else if (is_space(*str)) + *(result++)= ' '; + else + *(result++)= *str; + str++; + len--; + } } *result= 0; return result - res_start; diff --git a/sql/item.cc b/sql/item.cc index 140eb5244ec..e001178f8b6 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -1,6 +1,6 @@ /* Copyright (c) 2000, 2018, Oracle and/or its affiliates. - Copyright (c) 2010, 2018, MariaDB Corporation + Copyright (c) 2010, 2020, MariaDB Corporation. 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 @@ -7212,7 +7212,6 @@ Item *find_producing_item(Item *item, st_select_lex *sel) DBUG_ASSERT(item->type() == Item::FIELD_ITEM || (item->type() == Item::REF_ITEM && ((Item_ref *) item)->ref_type() == Item_ref::VIEW_REF)); - Item *producing_item; Item_field *field_item= NULL; Item_equal *item_equal= item->get_item_equal(); table_map tab_map= sel->master_unit()->derived->table->map; @@ -7234,6 +7233,7 @@ Item *find_producing_item(Item *item, st_select_lex *sel) List_iterator_fast li(sel->item_list); if (field_item) { + Item *producing_item= NULL; uint field_no= field_item->field->field_index; for (uint i= 0; i <= field_no; i++) producing_item= li++; diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc index 645a3668ed8..0db8d7075f6 100644 --- a/sql/item_geofunc.cc +++ b/sql/item_geofunc.cc @@ -2389,12 +2389,15 @@ double Item_func_distance::val_real() MBR mbr1, mbr2; const char *c_end; - - if ((null_value= (args[0]->null_value || args[1]->null_value || - !(g1= Geometry::construct(&buffer1, res1->ptr(), res1->length())) || - !(g2= Geometry::construct(&buffer2, res2->ptr(), res2->length())) || - g1->get_mbr(&mbr1, &c_end) || - g2->get_mbr(&mbr2, &c_end)))) + if (args[0]->null_value || args[1]->null_value) + goto mem_error; + g1= Geometry::construct(&buffer1, res1->ptr(), res1->length()); + if (!g1) + goto mem_error; + g2= Geometry::construct(&buffer2, res2->ptr(), res2->length()); + if (!g2) + goto mem_error; + if (g1->get_mbr(&mbr1, &c_end) || g2->get_mbr(&mbr2, &c_end)) goto mem_error; mbr1.add_mbr(&mbr2); @@ -2543,7 +2546,7 @@ String *Item_func_pointonsurface::val_str(String *str) Geometry *g; MBR mbr; const char *c_end; - double UNINIT_VAR(px), UNINIT_VAR(py), x0, y0; + double UNINIT_VAR(px), UNINIT_VAR(py), x0, UNINIT_VAR(y0); String *result= 0; const Gcalc_scan_iterator::point *pprev= NULL; uint32 srid; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 44f8558e474..5991ef5f7b0 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -6620,13 +6620,11 @@ void handle_connections_sockets() MYSQL_SOCKET sock= mysql_socket_invalid(); MYSQL_SOCKET new_sock= mysql_socket_invalid(); uint error_count=0; - CONNECT *connect; struct sockaddr_storage cAddr; int ip_flags __attribute__((unused))=0; int socket_flags __attribute__((unused))= 0; int extra_ip_flags __attribute__((unused))=0; int flags=0,retval; - bool is_unix_sock; #ifdef HAVE_POLL int socket_count= 0; struct pollfd fds[3]; // for ip_sock, unix_sock and extra_ip_sock @@ -6826,41 +6824,37 @@ void handle_connections_sockets() DBUG_PRINT("info", ("Creating CONNECT for new connection")); - if ((connect= new CONNECT())) + if (CONNECT *connect= new CONNECT()) { - is_unix_sock= (mysql_socket_getfd(sock) == - mysql_socket_getfd(unix_sock)); + const bool is_unix_sock= (mysql_socket_getfd(sock) == + mysql_socket_getfd(unix_sock)); - if (!(connect->vio= - mysql_socket_vio_new(new_sock, - is_unix_sock ? VIO_TYPE_SOCKET : - VIO_TYPE_TCPIP, - is_unix_sock ? VIO_LOCALHOST: 0))) + if ((connect->vio= + mysql_socket_vio_new(new_sock, + is_unix_sock ? VIO_TYPE_SOCKET : + VIO_TYPE_TCPIP, + is_unix_sock ? VIO_LOCALHOST: 0))) { - delete connect; - connect= 0; // Error handling below + if (is_unix_sock) + connect->host= my_localhost; + + if (mysql_socket_getfd(sock) == mysql_socket_getfd(extra_ip_sock)) + { + connect->extra_port= 1; + connect->scheduler= extra_thread_scheduler; + } + create_new_thread(connect); + continue; } + + delete connect; } - if (!connect) - { - /* Connect failure */ - (void) mysql_socket_shutdown(new_sock, SHUT_RDWR); - (void) mysql_socket_close(new_sock); - statistic_increment(aborted_connects,&LOCK_status); - statistic_increment(connection_errors_internal, &LOCK_status); - continue; - } - - if (is_unix_sock) - connect->host= my_localhost; - - if (mysql_socket_getfd(sock) == mysql_socket_getfd(extra_ip_sock)) - { - connect->extra_port= 1; - connect->scheduler= extra_thread_scheduler; - } - create_new_thread(connect); + /* Connect failure */ + (void) mysql_socket_shutdown(new_sock, SHUT_RDWR); + (void) mysql_socket_close(new_sock); + statistic_increment(aborted_connects,&LOCK_status); + statistic_increment(connection_errors_internal, &LOCK_status); } sd_notify(0, "STOPPING=1\n" "STATUS=Shutdown in progress\n"); diff --git a/sql/sql_time.cc b/sql/sql_time.cc index 7f5919007e8..b92b35a3abb 100644 --- a/sql/sql_time.cc +++ b/sql/sql_time.cc @@ -358,7 +358,7 @@ static bool number_to_time_with_warn(bool neg, ulonglong nr, ulong sec_part, int was_cut; longlong res; enum_field_types f_type; - bool have_warnings; + bool have_warnings= false; if (fuzzydate & TIME_TIME_ONLY) { diff --git a/storage/innobase/fts/fts0que.cc b/storage/innobase/fts/fts0que.cc index 81018f57619..6396dad4aa5 100644 --- a/storage/innobase/fts/fts0que.cc +++ b/storage/innobase/fts/fts0que.cc @@ -2742,7 +2742,7 @@ fts_query_phrase_search( /* Ignore empty strings. */ if (num_token > 0) { - fts_string_t* token; + fts_string_t* token = NULL; fts_fetch_t fetch; trx_t* trx = query->trx; fts_ast_oper_t oper = query->oper; diff --git a/storage/maria/ma_create.c b/storage/maria/ma_create.c index 2c9c15d8a2a..bca7ad94f85 100644 --- a/storage/maria/ma_create.c +++ b/storage/maria/ma_create.c @@ -75,7 +75,7 @@ int maria_create(const char *name, enum data_file_type datafile_type, uint max_field_lengths, extra_header_size, column_nr; uint internal_table= flags & HA_CREATE_INTERNAL_TABLE; ulong reclength, real_reclength,min_pack_length; - char kfilename[FN_REFLEN], klinkname[FN_REFLEN], *klinkname_ptr; + char kfilename[FN_REFLEN], klinkname[FN_REFLEN], *klinkname_ptr= NullS; char dfilename[FN_REFLEN], dlinkname[FN_REFLEN], *dlinkname_ptr= 0; ulong pack_reclength; ulonglong tot_length,max_rows, tmp; @@ -889,7 +889,6 @@ int maria_create(const char *name, enum data_file_type datafile_type, fn_format(kfilename, name, "", MARIA_NAME_IEXT, MY_UNPACK_FILENAME | MY_RETURN_REAL_PATH | (have_iext ? MY_REPLACE_EXT : MY_APPEND_EXT)); - klinkname_ptr= NullS; /* Replace the current file. Don't sync dir now if the data file has the same path. diff --git a/storage/maria/ma_loghandler.c b/storage/maria/ma_loghandler.c index 9fe746a167b..b98fbe29e1f 100644 --- a/storage/maria/ma_loghandler.c +++ b/storage/maria/ma_loghandler.c @@ -3614,7 +3614,8 @@ my_bool translog_init_with_table(const char *directory, int old_log_was_recovered= 0, logs_found= 0; uint old_flags= flags; uint32 start_file_num= 1; - TRANSLOG_ADDRESS sure_page, last_page, last_valid_page, checkpoint_lsn; + TRANSLOG_ADDRESS UNINIT_VAR(sure_page), last_page, last_valid_page, + checkpoint_lsn; my_bool version_changed= 0; DBUG_ENTER("translog_init_with_table"); diff --git a/storage/myisam/mi_create.c b/storage/myisam/mi_create.c index fd230698acc..9f17a9b2de9 100644 --- a/storage/myisam/mi_create.c +++ b/storage/myisam/mi_create.c @@ -46,7 +46,7 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, uint aligned_key_start, block_length, res; uint internal_table= flags & HA_CREATE_INTERNAL_TABLE; ulong reclength, real_reclength,min_pack_length; - char kfilename[FN_REFLEN],klinkname[FN_REFLEN], *klinkname_ptr; + char kfilename[FN_REFLEN],klinkname[FN_REFLEN], *klinkname_ptr= 0; char dfilename[FN_REFLEN],dlinkname[FN_REFLEN], *dlinkname_ptr= 0; ulong pack_reclength; ulonglong tot_length,max_rows, tmp; @@ -622,7 +622,6 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, fn_format(kfilename, name, "", MI_NAME_IEXT, MY_UNPACK_FILENAME | MY_RETURN_REAL_PATH | (have_iext ? MY_REPLACE_EXT : MY_APPEND_EXT)); - klinkname_ptr= 0; /* Replace the current file */ create_flag=(flags & HA_CREATE_KEEP_FILES) ? 0 : MY_DELETE_OLD; } diff --git a/strings/ctype-ucs2.c b/strings/ctype-ucs2.c index f229bbf7323..c5182911c4a 100644 --- a/strings/ctype-ucs2.c +++ b/strings/ctype-ucs2.c @@ -827,7 +827,7 @@ my_strtoll10_mb2(CHARSET_INFO *cs __attribute__((unused)), const char *nptr, char **endptr, int *error) { const uchar *s, *end, *start, *n_end, *true_end; - uchar c; + uchar UNINIT_VAR(c); unsigned long i, j, k; ulonglong li; int negative; From de8d57e5220ccfab31db4da86167f441df78869b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 11 Aug 2020 15:49:37 +0300 Subject: [PATCH 06/70] MDEV-23447 SIGSEGV in fil_system_t::keyrotate_next() fil_system_t::keyrotate_next(): If space && space->is_in_rotation_list does not hold, iterate from the start of the list. In debug builds, we would typically have hit SIGSEGV because the iterator would have wrapped a null pointer. It might also be that we are dereferencing a stale pointer. There is no test case, because the encryption is very nondeterministic in nature, due to the use of background threads. This scenario can be hit by setting the following: SET GLOBAL innodb_encryption_threads=5; SET GLOBAL innodb_encryption_rotate_key_age=0; --- storage/innobase/fil/fil0crypt.cc | 35 ++++++++++++++++++------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/storage/innobase/fil/fil0crypt.cc b/storage/innobase/fil/fil0crypt.cc index c687c53ac14..09f2730edec 100644 --- a/storage/innobase/fil/fil0crypt.cc +++ b/storage/innobase/fil/fil0crypt.cc @@ -1388,29 +1388,34 @@ the encryption parameters were changed inline fil_space_t *fil_system_t::keyrotate_next(fil_space_t *space, bool recheck, bool encrypt) { - ut_ad(mutex_own(&fil_system->mutex)); + ut_ad(mutex_own(&mutex)); sized_ilist::iterator it= - space ? space : fil_system->rotation_list.begin(); + space && space->is_in_rotation_list ? space : rotation_list.begin(); const sized_ilist::iterator end= - fil_system->rotation_list.end(); + rotation_list.end(); if (space) { - while (++it != end && (!UT_LIST_GET_LEN(it->chain) || it->is_stopping())); + const bool released= !--space->n_pending_ops; - /* If one of the encryption threads already started the encryption - of the table then don't remove the unencrypted spaces from rotation list - - If there is a change in innodb_encrypt_tables variables value then - don't remove the last processed tablespace from the rotation list. */ - if (!--space->n_pending_ops && - (!recheck || space->crypt_data) && !encrypt == !srv_encrypt_tables && - space->is_in_rotation_list) + if (space->is_in_rotation_list) { - ut_a(!fil_system->rotation_list.empty()); - fil_system->rotation_list.remove(*space); - space->is_in_rotation_list= false; + while (++it != end && + (!UT_LIST_GET_LEN(it->chain) || it->is_stopping())); + + /* If one of the encryption threads already started the encryption + of the table then don't remove the unencrypted spaces from rotation list + + If there is a change in innodb_encrypt_tables variables value then + don't remove the last processed tablespace from the rotation list. */ + if (released && (!recheck || space->crypt_data) && + !encrypt == !srv_encrypt_tables) + { + ut_a(!rotation_list.empty()); + rotation_list.remove(*space); + space->is_in_rotation_list= false; + } } } From 7f03b1d78f2aab738e38a1e33ac887757604585a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Tue, 11 Aug 2020 16:23:10 +0300 Subject: [PATCH 07/70] Fix test galera_ist_progress in 10.4 --- .../suite/galera/r/galera_ist_progress.result | 17 ++++++++++++++--- .../suite/galera/t/galera_ist_progress.test | 13 +++++++------ 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/mysql-test/suite/galera/r/galera_ist_progress.result b/mysql-test/suite/galera/r/galera_ist_progress.result index 9fc7febbea5..9233d95b970 100644 --- a/mysql-test/suite/galera/r/galera_ist_progress.result +++ b/mysql-test/suite/galera/r/galera_ist_progress.result @@ -1,6 +1,12 @@ +connection node_2; +connection node_1; +connection node_2; SET GLOBAL wsrep_provider_options = 'gmcast.isolate = 1'; +connection node_1; +connection node_2; SET SESSION wsrep_on = OFF; SET SESSION wsrep_on = ON; +connection node_1; CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB; INSERT INTO t1 VALUES (1); INSERT INTO t1 VALUES (2); @@ -12,8 +18,13 @@ INSERT INTO t1 VALUES (7); INSERT INTO t1 VALUES (8); INSERT INTO t1 VALUES (9); INSERT INTO t1 VALUES (10); +connection node_2; SET GLOBAL wsrep_provider_options = 'gmcast.isolate = 0'; -include/assert_grep.inc [Receiving IST: 11 writesets, seqnos] -include/assert_grep.inc [Receiving IST\.\.\. 0\.0% \( 0/11 events\) complete] -include/assert_grep.inc [Receiving IST\.\.\.100\.0% \(11/11 events\) complete] +connection node_1; +connection node_2; +connection node_1; +include/assert_grep.inc [Receiving IST: 13 writesets, seqnos 3-15] +include/assert_grep.inc [Receiving IST\.\.\. 0\.0% \( 0/13 events\) complete] +include/assert_grep.inc [Receiving IST\.\.\.100\.0% \(13/13 events\) complete] +connection node_1; DROP TABLE t1; diff --git a/mysql-test/suite/galera/t/galera_ist_progress.test b/mysql-test/suite/galera/t/galera_ist_progress.test index dd93161eab8..3d7c53bd1eb 100644 --- a/mysql-test/suite/galera/t/galera_ist_progress.test +++ b/mysql-test/suite/galera/t/galera_ist_progress.test @@ -5,6 +5,7 @@ --source include/galera_cluster.inc # This could cause out of storage if run /dev/shm --source include/big_test.inc +--source include/force_restart.inc # Isolate node #2 --connection node_2 @@ -58,16 +59,16 @@ SET GLOBAL wsrep_provider_options = 'gmcast.isolate = 0'; --let $assert_file = $MYSQLTEST_VARDIR/log/mysqld.2.err --let $assert_only_after = Need state transfer ---let $assert_text = Receiving IST: 1[13] writesets ---let $assert_select = Receiving IST: 1[13] writesets +--let $assert_text = Receiving IST: 13 writesets, seqnos 3-15 +--let $assert_select = Receiving IST: 13 writesets, seqnos 3-15 --source include/assert_grep.inc ---let $assert_text = Receiving IST\.\.\. 0\.0% \( 0/11 events\) complete ---let $assert_select = Receiving IST\.\.\. 0\.0% \( 0/11 events\) complete +--let $assert_text = Receiving IST\.\.\. 0\.0% \( 0/13 events\) complete +--let $assert_select = Receiving IST\.\.\. 0\.0% \( 0/13 events\) complete --source include/assert_grep.inc ---let $assert_text = Receiving IST\.\.\.100\.0% \(11/11 events\) complete ---let $assert_select = Receiving IST\.\.\.100\.0% \(11/11 events\) complete +--let $assert_text = Receiving IST\.\.\.100\.0% \(13/13 events\) complete +--let $assert_select = Receiving IST\.\.\.100\.0% \(13/13 events\) complete --source include/assert_grep.inc # Cleanup From 863e28ff3ed0a5859561c397cbfb492170989ddd Mon Sep 17 00:00:00 2001 From: Anel Husakovic Date: Fri, 7 Aug 2020 17:03:17 +0200 Subject: [PATCH 08/70] MDEV-22066: out-of-source build fails with WITHOUT_SERVER=ON Patch 4aaa38d26ed95127b842410 is replacing `my_config.h` with `my_global.h` which is included in in-source build, but not for out-of-source build tree. Closes #1466 --- plugin/handler_socket/CMakeLists.txt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/plugin/handler_socket/CMakeLists.txt b/plugin/handler_socket/CMakeLists.txt index 329ff58d7f2..5a1925b40e0 100644 --- a/plugin/handler_socket/CMakeLists.txt +++ b/plugin/handler_socket/CMakeLists.txt @@ -1,7 +1,8 @@ -IF(WIN32) +IF(WIN32 OR WITHOUT_SERVER) # Handlersocket does not compile on Windows, compiles but does - # not start on FreeBSD. + # not start on FreeBSD. + # It is a server plugin and disable it explicitly here. RETURN() ENDIF() From c96be848d3bbb668d27645c36ca66c697fdc2752 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 11 Aug 2020 18:52:38 +0300 Subject: [PATCH 09/70] MDEV-14119 Assertion cmp_rec_rec() in ALTER TABLE innobase_pk_order_preserved(): Treat an added AUTO_INCREMENT column in the same way as an added existing column. In either case, the column values are not guaranteed to be constant, and thus the ordering may change if such a column is added before any existing PRIMARY KEY columns. prepare_inplace_alter_table_dict(): Initialize dict_table_t::persistent_autoinc before invoking innobase_pk_order_preserved(). --- .../innodb/include/alter_table_pk_no_sort.inc | 7 +++++++ mysql-test/suite/innodb/r/alter_table.result | 7 +++++++ .../suite/innodb/r/innodb-index-debug.result | 5 +++++ mysql-test/suite/innodb/r/innodb-index.result | 5 +++++ mysql-test/suite/innodb/t/alter_table.test | 9 +++++++++ storage/innobase/handler/handler0alter.cc | 18 +++++++++++------- 6 files changed, 44 insertions(+), 7 deletions(-) diff --git a/mysql-test/suite/innodb/include/alter_table_pk_no_sort.inc b/mysql-test/suite/innodb/include/alter_table_pk_no_sort.inc index 6a2fcd15be0..61e304a7626 100644 --- a/mysql-test/suite/innodb/include/alter_table_pk_no_sort.inc +++ b/mysql-test/suite/innodb/include/alter_table_pk_no_sort.inc @@ -263,3 +263,10 @@ create table t1(o1 int, o2 int, o3 int, primary key(o1,o2,o3)) engine = innodb; insert into t1 values(1,1,2),(2,2,1); alter table t1 drop primary key, add primary key(o1), lock=none; drop table t1; + +# pk(o1,o2) to pk(o1,o2,autoinc) must not sort +create table t1(o1 int, o2 int, primary key(o1,o2)) engine = innodb; +insert into t1 values(1,1),(2,1); +alter table t1 drop primary key, add column a int unique auto_increment, +add primary key(o1,o2,a), algorithm=inplace; +drop table t1; diff --git a/mysql-test/suite/innodb/r/alter_table.result b/mysql-test/suite/innodb/r/alter_table.result index e47bfb90152..94262ac29c3 100644 --- a/mysql-test/suite/innodb/r/alter_table.result +++ b/mysql-test/suite/innodb/r/alter_table.result @@ -53,3 +53,10 @@ ALTER TABLE t1 DROP a; ERROR HY000: Cannot drop index 'a': needed in a foreign key constraint ALTER TABLE t1 ADD c INT; DROP TABLE t1, tx; +# +# MDEV-14119 Assertion cmp_rec_rec() on ALTER TABLE +# +CREATE TABLE t1(a INT NOT NULL UNIQUE) ENGINE=InnoDB; +INSERT INTO t1 SELECT * FROM seq_1_to_128; +ALTER TABLE t1 ADD b TINYINT AUTO_INCREMENT PRIMARY KEY, DROP KEY a; +DROP TABLE t1; diff --git a/mysql-test/suite/innodb/r/innodb-index-debug.result b/mysql-test/suite/innodb/r/innodb-index-debug.result index b1f8c9ad3cc..bf2abce989c 100644 --- a/mysql-test/suite/innodb/r/innodb-index-debug.result +++ b/mysql-test/suite/innodb/r/innodb-index-debug.result @@ -323,4 +323,9 @@ create table t1(o1 int, o2 int, o3 int, primary key(o1,o2,o3)) engine = innodb; insert into t1 values(1,1,2),(2,2,1); alter table t1 drop primary key, add primary key(o1), lock=none; drop table t1; +create table t1(o1 int, o2 int, primary key(o1,o2)) engine = innodb; +insert into t1 values(1,1),(2,1); +alter table t1 drop primary key, add column a int unique auto_increment, +add primary key(o1,o2,a), algorithm=inplace; +drop table t1; SET DEBUG_DBUG = @saved_debug_dbug; diff --git a/mysql-test/suite/innodb/r/innodb-index.result b/mysql-test/suite/innodb/r/innodb-index.result index bdc16ad7692..5e91efb7062 100644 --- a/mysql-test/suite/innodb/r/innodb-index.result +++ b/mysql-test/suite/innodb/r/innodb-index.result @@ -1903,6 +1903,11 @@ create table t1(o1 int, o2 int, o3 int, primary key(o1,o2,o3)) engine = innodb; insert into t1 values(1,1,2),(2,2,1); alter table t1 drop primary key, add primary key(o1), lock=none; drop table t1; +create table t1(o1 int, o2 int, primary key(o1,o2)) engine = innodb; +insert into t1 values(1,1),(2,1); +alter table t1 drop primary key, add column a int unique auto_increment, +add primary key(o1,o2,a), algorithm=inplace; +drop table t1; # # MDEV-15325 Incomplete validation of missing tablespace during recovery # diff --git a/mysql-test/suite/innodb/t/alter_table.test b/mysql-test/suite/innodb/t/alter_table.test index d0943e7d407..6bc30d2e8ee 100644 --- a/mysql-test/suite/innodb/t/alter_table.test +++ b/mysql-test/suite/innodb/t/alter_table.test @@ -1,4 +1,5 @@ --source include/have_innodb.inc +--source include/have_sequence.inc # # MDEV-11995 ALTER TABLE proceeds despite reporting ER_TOO_LONG_KEY error # @@ -59,3 +60,11 @@ ALTER TABLE t1 ADD b INT; ALTER TABLE t1 DROP a; ALTER TABLE t1 ADD c INT; DROP TABLE t1, tx; + +--echo # +--echo # MDEV-14119 Assertion cmp_rec_rec() on ALTER TABLE +--echo # +CREATE TABLE t1(a INT NOT NULL UNIQUE) ENGINE=InnoDB; +INSERT INTO t1 SELECT * FROM seq_1_to_128; +ALTER TABLE t1 ADD b TINYINT AUTO_INCREMENT PRIMARY KEY, DROP KEY a; +DROP TABLE t1; diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index 782b0d9efb2..0f5ac81f663 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -3362,7 +3362,11 @@ innobase_pk_order_preserved( if (old_pk_column) { new_field_order = old_field; } else if (innobase_pk_col_is_existing(new_col_no, col_map, - old_n_cols)) { + old_n_cols) + || new_clust_index->table->persistent_autoinc + == new_field + 1) { + /* Adding an existing column or an AUTO_INCREMENT + column may change the existing ordering. */ new_field_order = old_n_uniq + existing_field_count++; } else { /* Skip newly added column. */ @@ -4913,12 +4917,6 @@ index_created: user_table); dict_index_t* new_clust_index = dict_table_get_first_index( ctx->new_table); - ctx->skip_pk_sort = innobase_pk_order_preserved( - ctx->col_map, clust_index, new_clust_index); - - DBUG_EXECUTE_IF("innodb_alter_table_pk_assert_no_sort", - DBUG_ASSERT(ctx->skip_pk_sort);); - DBUG_ASSERT(!ctx->new_table->persistent_autoinc); if (const Field* ai = altered_table->found_next_number_field) { const unsigned col_no = innodb_col_no(ai); @@ -4937,6 +4935,12 @@ index_created: } } + ctx->skip_pk_sort = innobase_pk_order_preserved( + ctx->col_map, clust_index, new_clust_index); + + DBUG_EXECUTE_IF("innodb_alter_table_pk_assert_no_sort", + DBUG_ASSERT(ctx->skip_pk_sort);); + if (ctx->online) { /* Allocate a log for online table rebuild. */ rw_lock_x_lock(&clust_index->lock); From 01738d08f30315f10c14faa605d0087e54156cd0 Mon Sep 17 00:00:00 2001 From: Eugene Kosov Date: Tue, 11 Aug 2020 20:12:30 +0300 Subject: [PATCH 10/70] add debug assertion to ilist --- include/ilist.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/include/ilist.h b/include/ilist.h index 722677f9057..4b89efe7717 100644 --- a/include/ilist.h +++ b/include/ilist.h @@ -26,8 +26,7 @@ template struct ilist_node { ilist_node() #ifndef DBUG_OFF - : - next(NULL), prev(NULL) + : next(NULL), prev(NULL) #endif { } @@ -70,11 +69,12 @@ public: typedef T *pointer; typedef T &reference; - Iterator(ListNode *node) : node_(node) {} + Iterator(ListNode *node) : node_(node) { assert(node_); } Iterator &operator++() { node_= node_->next; + assert(node_); return *this; } Iterator operator++(int) @@ -87,6 +87,7 @@ public: Iterator &operator--() { node_= node_->prev; + assert(node_); return *this; } Iterator operator--(int) From 5a4ae142f48bcf9e11becfd4c98d72de338bba6a Mon Sep 17 00:00:00 2001 From: Eugene Kosov Date: Wed, 12 Aug 2020 10:24:09 +0300 Subject: [PATCH 11/70] replace assert() with DBUG_ASSERT() --- include/ilist.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/include/ilist.h b/include/ilist.h index 4b89efe7717..dc75d6907ce 100644 --- a/include/ilist.h +++ b/include/ilist.h @@ -18,6 +18,8 @@ #pragma once +#include "my_dbug.h" + #include #include @@ -69,12 +71,12 @@ public: typedef T *pointer; typedef T &reference; - Iterator(ListNode *node) : node_(node) { assert(node_); } + Iterator(ListNode *node) : node_(node) { DBUG_ASSERT(node_); } Iterator &operator++() { node_= node_->next; - assert(node_); + DBUG_ASSERT(node_); return *this; } Iterator operator++(int) @@ -87,7 +89,7 @@ public: Iterator &operator--() { node_= node_->prev; - assert(node_); + DBUG_ASSERT(node_); return *this; } Iterator operator--(int) From 4387e3a13bba61313a1637f63253e01e6edbce0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 12 Aug 2020 13:08:17 +0300 Subject: [PATCH 12/70] Use DBUG_ASSERT(ptr != NULL) to ease merging to 10.3 In 10.3, DBUG_ASSERT() may expand to something that includes __builtin_expect(), which expects integer arguments, not pointers. To avoid any compiler warnings, let us use an explicit rather than implicit comparison to the null pointer. --- include/ilist.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/ilist.h b/include/ilist.h index dc75d6907ce..ed1d978a0d6 100644 --- a/include/ilist.h +++ b/include/ilist.h @@ -71,12 +71,12 @@ public: typedef T *pointer; typedef T &reference; - Iterator(ListNode *node) : node_(node) { DBUG_ASSERT(node_); } + Iterator(ListNode *node) : node_(node) { DBUG_ASSERT(node_ != NULL); } Iterator &operator++() { node_= node_->next; - DBUG_ASSERT(node_); + DBUG_ASSERT(node_ != NULL); return *this; } Iterator operator++(int) From 18f374cb20a8d3ec8d8349be40a8659d18ee7678 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 12 Aug 2020 13:12:51 +0300 Subject: [PATCH 13/70] MDEV-23439 Assertion size == space->size failed in buf_read_ahead_random The debug assertion is bogus, and we had removed it in commit b1ab211dee599eabd9a5b886fafa3adea29ae041 (MDEV-15053) in the MariaDB Server 10.5 branch. For a small data file, fil_space_extend_must_retry() would always allocate a minimum size of 4*innodb_page_size. It is possible that random read-ahead will be triggered for a smaller file than this. In the observed case, the read-ahead was triggered for a 6-page file that used ROW_FORMAT=COMPRESSED with 8KiB page size. So, the desired file size was 49152 bytes, but the actual size was 65536 bytes. --- storage/innobase/buf/buf0rea.cc | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/storage/innobase/buf/buf0rea.cc b/storage/innobase/buf/buf0rea.cc index d6f096fc80e..ad583e577c4 100644 --- a/storage/innobase/buf/buf0rea.cc +++ b/storage/innobase/buf/buf0rea.cc @@ -280,23 +280,6 @@ buf_read_ahead_random( * buf_read_ahead_random_area; if (fil_space_t* space = fil_space_acquire(page_id.space())) { -#ifdef UNIV_DEBUG - if (srv_file_per_table) { - ulint size = 0; - - for (const fil_node_t* node = - UT_LIST_GET_FIRST(space->chain); - node != NULL; - node = UT_LIST_GET_NEXT(chain, node)) { - - size += ulint(os_file_get_size(node->handle) - / page_size.physical()); - } - - ut_ad(size == space->size); - } -#endif /* UNIV_DEBUG */ - high = space->max_page_number_for_io(high); fil_space_release(space); } else { From efd8af535a4fa4aa3dd89a325340b6eb648e1bc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 12 Aug 2020 18:21:53 +0300 Subject: [PATCH 14/70] MDEV-19526 heap number overflow on innodb_page_size=64k InnoDB only reserves 13 bits for the heap number in the record header, limiting the heap number to be at most 8191. But, when using innodb_page_size=64k and secondary index records of 7 bytes each, it is possible to exceed the maximum heap number. btr_cur_optimistic_insert(): Let the operation fail if the maximum number of records would be exceeded. page_mem_alloc_heap(): Move to the same compilation unit with the only caller, and let the operation fail if the maximum heap number has been allocated already. --- mysql-test/suite/innodb/r/innodb-64k.result | 7 +++ mysql-test/suite/innodb/t/innodb-64k.test | 10 +++++ storage/innobase/btr/btr0cur.cc | 18 +++++--- storage/innobase/include/page0page.h | 17 +------- storage/innobase/page/page0cur.cc | 47 +++++++++++++++++++++ storage/innobase/page/page0page.cc | 40 +----------------- storage/xtradb/btr/btr0cur.cc | 18 +++++--- storage/xtradb/include/page0page.h | 17 +------- storage/xtradb/page/page0cur.cc | 47 +++++++++++++++++++++ storage/xtradb/page/page0page.cc | 40 +----------------- 10 files changed, 139 insertions(+), 122 deletions(-) diff --git a/mysql-test/suite/innodb/r/innodb-64k.result b/mysql-test/suite/innodb/r/innodb-64k.result index dc938f236cd..0ecc1b7096b 100644 --- a/mysql-test/suite/innodb/r/innodb-64k.result +++ b/mysql-test/suite/innodb/r/innodb-64k.result @@ -1084,3 +1084,10 @@ update t2 set col145=@b; COMMIT; drop table t2; DROP TABLE t1; +# +# MDEV-19526 heap number overflow +# +CREATE TABLE t1(a SMALLINT NOT NULL UNIQUE AUTO_INCREMENT, KEY(a)) +ENGINE=InnoDB; +INSERT INTO t1 (a) SELECT seq FROM seq_1_to_8191; +DROP TABLE t1; diff --git a/mysql-test/suite/innodb/t/innodb-64k.test b/mysql-test/suite/innodb/t/innodb-64k.test index 0498544279b..50dc1535aa6 100644 --- a/mysql-test/suite/innodb/t/innodb-64k.test +++ b/mysql-test/suite/innodb/t/innodb-64k.test @@ -2,6 +2,7 @@ # Tests for setting innodb-page-size=64k; --source include/have_innodb.inc --source include/have_innodb_64k.inc +--source include/have_sequence.inc call mtr.add_suppression("InnoDB: Warning: innodb_page_size has been changed from default value *"); call mtr.add_suppression("InnoDB: Resizing redo log from *"); @@ -650,6 +651,15 @@ COMMIT; drop table t2; DROP TABLE t1; + +--echo # +--echo # MDEV-19526 heap number overflow +--echo # +CREATE TABLE t1(a SMALLINT NOT NULL UNIQUE AUTO_INCREMENT, KEY(a)) +ENGINE=InnoDB; +INSERT INTO t1 (a) SELECT seq FROM seq_1_to_8191; +DROP TABLE t1; + # # restore environment to the state it was before this test execution # diff --git a/storage/innobase/btr/btr0cur.cc b/storage/innobase/btr/btr0cur.cc index 7b2fbfa0f0e..8e1a7200ab3 100644 --- a/storage/innobase/btr/btr0cur.cc +++ b/storage/innobase/btr/btr0cur.cc @@ -3,7 +3,7 @@ Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2008, Google Inc. Copyright (c) 2012, Facebook Inc. -Copyright (c) 2015, 2017, MariaDB Corporation. +Copyright (c) 2015, 2020, MariaDB Corporation. Portions of this file contain modifications contributed and copyrighted by Google, Inc. Those modifications are gratefully acknowledged and are described @@ -1433,17 +1433,23 @@ fail_err: } ulint max_size = page_get_max_insert_size_after_reorganize(page, 1); + if (max_size < rec_size) { + goto fail; + } + + const ulint n_recs = page_get_n_recs(page); + if (UNIV_UNLIKELY(n_recs >= 8189)) { + ut_ad(srv_page_size == 65536); + goto fail; + } if (page_has_garbage(page)) { - if ((max_size < rec_size - || max_size < BTR_CUR_PAGE_REORGANIZE_LIMIT) - && page_get_n_recs(page) > 1 + if (max_size < BTR_CUR_PAGE_REORGANIZE_LIMIT + && n_recs > 1 && page_get_max_insert_size(page, 1) < rec_size) { goto fail; } - } else if (max_size < rec_size) { - goto fail; } /* If there have been many consecutive inserts to the diff --git a/storage/innobase/include/page0page.h b/storage/innobase/include/page0page.h index 64ae31905b4..5e9081476ce 100644 --- a/storage/innobase/include/page0page.h +++ b/storage/innobase/include/page0page.h @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2013, 2018, MariaDB Corporation. +Copyright (c) 2013, 2020, MariaDB Corporation. 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 @@ -759,21 +759,6 @@ page_mem_alloc_free( free record list */ ulint need); /*!< in: number of bytes allocated */ /************************************************************//** -Allocates a block of memory from the heap of an index page. -@return pointer to start of allocated buffer, or NULL if allocation fails */ -UNIV_INTERN -byte* -page_mem_alloc_heap( -/*================*/ - page_t* page, /*!< in/out: index page */ - page_zip_des_t* page_zip,/*!< in/out: compressed page with enough - space available for inserting the record, - or NULL */ - ulint need, /*!< in: total number of bytes needed */ - ulint* heap_no);/*!< out: this contains the heap number - of the allocated record - if allocation succeeds */ -/************************************************************//** Puts a record to free list. */ UNIV_INLINE void diff --git a/storage/innobase/page/page0cur.cc b/storage/innobase/page/page0cur.cc index e9ac4b4bb04..94e861ab554 100644 --- a/storage/innobase/page/page0cur.cc +++ b/storage/innobase/page/page0cur.cc @@ -2,6 +2,7 @@ Copyright (c) 1994, 2013, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2012, Facebook Inc. +Copyright (c) 2020, MariaDB Corporation. 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 @@ -941,6 +942,52 @@ page_cur_parse_insert_rec( return(ptr + end_seg_len); } +/************************************************************//** +Allocates a block of memory from the heap of an index page. +@return pointer to start of allocated buffer, or NULL if allocation fails */ +static +byte* +page_mem_alloc_heap( +/*================*/ + page_t* page, /*!< in/out: index page */ + page_zip_des_t* page_zip,/*!< in/out: compressed page with enough + space available for inserting the record, + or NULL */ + ulint need, /*!< in: total number of bytes needed */ + ulint* heap_no)/*!< out: this contains the heap number + of the allocated record + if allocation succeeds */ +{ + byte* block; + ulint avl_space; + + ut_ad(page && heap_no); + + avl_space = page_get_max_insert_size(page, 1); + + if (avl_space >= need) { + const ulint h = page_dir_get_n_heap(page); + if (UNIV_UNLIKELY(h >= 8191)) { + /* At the minimum record size of 5+2 bytes, + we can only reach this condition when using + innodb_page_size=64k. */ + ut_ad(srv_page_size == 65536); + return(NULL); + } + *heap_no = h; + + block = page_header_get_ptr(page, PAGE_HEAP_TOP); + + page_header_set_ptr(page, page_zip, PAGE_HEAP_TOP, + block + need); + page_dir_set_n_heap(page, page_zip, 1 + *heap_no); + + return(block); + } + + return(NULL); +} + /***********************************************************//** Inserts a record next to page cursor on an uncompressed page. Returns pointer to inserted record if succeed, i.e., enough diff --git a/storage/innobase/page/page0page.cc b/storage/innobase/page/page0page.cc index ac16d71322a..1d9e4a97782 100644 --- a/storage/innobase/page/page0page.cc +++ b/storage/innobase/page/page0page.cc @@ -2,7 +2,7 @@ Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2012, Facebook Inc. -Copyright (c) 2018, MariaDB Corporation. +Copyright (c) 2018, 2020, MariaDB Corporation. 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 @@ -235,44 +235,6 @@ page_set_max_trx_id( } } -/************************************************************//** -Allocates a block of memory from the heap of an index page. -@return pointer to start of allocated buffer, or NULL if allocation fails */ -UNIV_INTERN -byte* -page_mem_alloc_heap( -/*================*/ - page_t* page, /*!< in/out: index page */ - page_zip_des_t* page_zip,/*!< in/out: compressed page with enough - space available for inserting the record, - or NULL */ - ulint need, /*!< in: total number of bytes needed */ - ulint* heap_no)/*!< out: this contains the heap number - of the allocated record - if allocation succeeds */ -{ - byte* block; - ulint avl_space; - - ut_ad(page && heap_no); - - avl_space = page_get_max_insert_size(page, 1); - - if (avl_space >= need) { - block = page_header_get_ptr(page, PAGE_HEAP_TOP); - - page_header_set_ptr(page, page_zip, PAGE_HEAP_TOP, - block + need); - *heap_no = page_dir_get_n_heap(page); - - page_dir_set_n_heap(page, page_zip, 1 + *heap_no); - - return(block); - } - - return(NULL); -} - #ifndef UNIV_HOTBACKUP /**********************************************************//** Writes a log record of page creation. */ diff --git a/storage/xtradb/btr/btr0cur.cc b/storage/xtradb/btr/btr0cur.cc index 5235fe434a9..7d97881f552 100644 --- a/storage/xtradb/btr/btr0cur.cc +++ b/storage/xtradb/btr/btr0cur.cc @@ -3,7 +3,7 @@ Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2008, Google Inc. Copyright (c) 2012, Facebook Inc. -Copyright (c) 2015, 2017, MariaDB Corporation. +Copyright (c) 2015, 2020, MariaDB Corporation. Portions of this file contain modifications contributed and copyrighted by Google, Inc. Those modifications are gratefully acknowledged and are described @@ -1542,17 +1542,23 @@ fail_err: } ulint max_size = page_get_max_insert_size_after_reorganize(page, 1); + if (max_size < rec_size) { + goto fail; + } + + const ulint n_recs = page_get_n_recs(page); + if (UNIV_UNLIKELY(n_recs >= 8189)) { + ut_ad(srv_page_size == 65536); + goto fail; + } if (page_has_garbage(page)) { - if ((max_size < rec_size - || max_size < BTR_CUR_PAGE_REORGANIZE_LIMIT) - && page_get_n_recs(page) > 1 + if (max_size < BTR_CUR_PAGE_REORGANIZE_LIMIT + && n_recs > 1 && page_get_max_insert_size(page, 1) < rec_size) { goto fail; } - } else if (max_size < rec_size) { - goto fail; } /* If there have been many consecutive inserts to the diff --git a/storage/xtradb/include/page0page.h b/storage/xtradb/include/page0page.h index 2efc2d302a1..b377aa68ac7 100644 --- a/storage/xtradb/include/page0page.h +++ b/storage/xtradb/include/page0page.h @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2013, 2018, MariaDB Corporation. +Copyright (c) 2013, 2020, MariaDB Corporation. 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 @@ -749,21 +749,6 @@ page_mem_alloc_free( free record list */ ulint need); /*!< in: number of bytes allocated */ /************************************************************//** -Allocates a block of memory from the heap of an index page. -@return pointer to start of allocated buffer, or NULL if allocation fails */ -UNIV_INTERN -byte* -page_mem_alloc_heap( -/*================*/ - page_t* page, /*!< in/out: index page */ - page_zip_des_t* page_zip,/*!< in/out: compressed page with enough - space available for inserting the record, - or NULL */ - ulint need, /*!< in: total number of bytes needed */ - ulint* heap_no);/*!< out: this contains the heap number - of the allocated record - if allocation succeeds */ -/************************************************************//** Puts a record to free list. */ UNIV_INLINE void diff --git a/storage/xtradb/page/page0cur.cc b/storage/xtradb/page/page0cur.cc index e9ac4b4bb04..94e861ab554 100644 --- a/storage/xtradb/page/page0cur.cc +++ b/storage/xtradb/page/page0cur.cc @@ -2,6 +2,7 @@ Copyright (c) 1994, 2013, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2012, Facebook Inc. +Copyright (c) 2020, MariaDB Corporation. 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 @@ -941,6 +942,52 @@ page_cur_parse_insert_rec( return(ptr + end_seg_len); } +/************************************************************//** +Allocates a block of memory from the heap of an index page. +@return pointer to start of allocated buffer, or NULL if allocation fails */ +static +byte* +page_mem_alloc_heap( +/*================*/ + page_t* page, /*!< in/out: index page */ + page_zip_des_t* page_zip,/*!< in/out: compressed page with enough + space available for inserting the record, + or NULL */ + ulint need, /*!< in: total number of bytes needed */ + ulint* heap_no)/*!< out: this contains the heap number + of the allocated record + if allocation succeeds */ +{ + byte* block; + ulint avl_space; + + ut_ad(page && heap_no); + + avl_space = page_get_max_insert_size(page, 1); + + if (avl_space >= need) { + const ulint h = page_dir_get_n_heap(page); + if (UNIV_UNLIKELY(h >= 8191)) { + /* At the minimum record size of 5+2 bytes, + we can only reach this condition when using + innodb_page_size=64k. */ + ut_ad(srv_page_size == 65536); + return(NULL); + } + *heap_no = h; + + block = page_header_get_ptr(page, PAGE_HEAP_TOP); + + page_header_set_ptr(page, page_zip, PAGE_HEAP_TOP, + block + need); + page_dir_set_n_heap(page, page_zip, 1 + *heap_no); + + return(block); + } + + return(NULL); +} + /***********************************************************//** Inserts a record next to page cursor on an uncompressed page. Returns pointer to inserted record if succeed, i.e., enough diff --git a/storage/xtradb/page/page0page.cc b/storage/xtradb/page/page0page.cc index 16587f872ef..ee31c9dbd87 100644 --- a/storage/xtradb/page/page0page.cc +++ b/storage/xtradb/page/page0page.cc @@ -2,7 +2,7 @@ Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2012, Facebook Inc. -Copyright (c) 2018, MariaDB Corporation. +Copyright (c) 2018, 2020, MariaDB Corporation. 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 @@ -240,44 +240,6 @@ page_set_max_trx_id( } } -/************************************************************//** -Allocates a block of memory from the heap of an index page. -@return pointer to start of allocated buffer, or NULL if allocation fails */ -UNIV_INTERN -byte* -page_mem_alloc_heap( -/*================*/ - page_t* page, /*!< in/out: index page */ - page_zip_des_t* page_zip,/*!< in/out: compressed page with enough - space available for inserting the record, - or NULL */ - ulint need, /*!< in: total number of bytes needed */ - ulint* heap_no)/*!< out: this contains the heap number - of the allocated record - if allocation succeeds */ -{ - byte* block; - ulint avl_space; - - ut_ad(page && heap_no); - - avl_space = page_get_max_insert_size(page, 1); - - if (avl_space >= need) { - block = page_header_get_ptr(page, PAGE_HEAP_TOP); - - page_header_set_ptr(page, page_zip, PAGE_HEAP_TOP, - block + need); - *heap_no = page_dir_get_n_heap(page); - - page_dir_set_n_heap(page, page_zip, 1 + *heap_no); - - return(block); - } - - return(NULL); -} - #ifndef UNIV_HOTBACKUP /**********************************************************//** Writes a log record of page creation. */ From 101ce10d0ddda1e38806b8d2c491298482e7ab78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 12 Aug 2020 18:35:21 +0300 Subject: [PATCH 15/70] MDEV-20672 Inconsistent usage message for innodb_compression_algorithm The usage message for the innodb_compression_algorithm system variable did not list snappy, which was added as an optional compression algorithm in MariaDB 10.1.3 and might actually work since commit 90c52e5291b3ad0935df7da56ec0fcbf530733b4 (MDEV-12615) in MariaDB 10.1.24. Unfortunately, we will include also unavailable compression algorithms in the list, because ENUM parameters allow numeric values, and we do not want innodb_compression_algorithm=3 to change meaning depending on the way how the source code was compiled. --- mysql-test/suite/sys_vars/r/sysvars_innodb.result | 2 +- storage/innobase/handler/ha_innodb.cc | 2 +- storage/xtradb/handler/ha_innodb.cc | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mysql-test/suite/sys_vars/r/sysvars_innodb.result b/mysql-test/suite/sys_vars/r/sysvars_innodb.result index d5d49a9b193..3877164bde3 100644 --- a/mysql-test/suite/sys_vars/r/sysvars_innodb.result +++ b/mysql-test/suite/sys_vars/r/sysvars_innodb.result @@ -502,7 +502,7 @@ GLOBAL_VALUE_ORIGIN COMPILE-TIME DEFAULT_VALUE zlib VARIABLE_SCOPE GLOBAL VARIABLE_TYPE ENUM -VARIABLE_COMMENT Compression algorithm used on page compression. One of: none, zlib, lz4, lzo, lzma, or bzip2 +VARIABLE_COMMENT Compression algorithm used on page compression. One of: none, zlib, lz4, lzo, lzma, bzip2, or snappy NUMERIC_MIN_VALUE NULL NUMERIC_MAX_VALUE NULL NUMERIC_BLOCK_SIZE NULL diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 10098a2fa4d..8960f42b4a3 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -19862,7 +19862,7 @@ static TYPELIB page_compression_algorithms_typelib= }; static MYSQL_SYSVAR_ENUM(compression_algorithm, innodb_compression_algorithm, PLUGIN_VAR_OPCMDARG, - "Compression algorithm used on page compression. One of: none, zlib, lz4, lzo, lzma, or bzip2", + "Compression algorithm used on page compression. One of: none, zlib, lz4, lzo, lzma, bzip2, or snappy", innodb_compression_algorithm_validate, NULL, /* We use here the largest number of supported compression method to enable all those methods that are available. Availability of compression diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc index bb324faf2b6..44c0c8d5bc5 100644 --- a/storage/xtradb/handler/ha_innodb.cc +++ b/storage/xtradb/handler/ha_innodb.cc @@ -21141,7 +21141,7 @@ static TYPELIB page_compression_algorithms_typelib= }; static MYSQL_SYSVAR_ENUM(compression_algorithm, innodb_compression_algorithm, PLUGIN_VAR_OPCMDARG, - "Compression algorithm used on page compression. One of: none, zlib, lz4, lzo, lzma, or bzip2", + "Compression algorithm used on page compression. One of: none, zlib, lz4, lzo, lzma, bzip2, or snappy", innodb_compression_algorithm_validate, NULL, /* We use here the largest number of supported compression method to enable all those methods that are available. Availability of compression From 754108021415ee718087b004a49bd54bd31cf6ad Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Wed, 12 Aug 2020 21:18:21 +0200 Subject: [PATCH 16/70] MDEV-23461 mysql_upgrade_wizard.exe differs from mariadb-upgrade-wizard.exe The post-build custom command to embed Vista elevation manifest into mariadb-upgrade-wizard.exe seems to do something nasty to the executable, perhaps it removes and recreates it. Thus the previously created hardlink mysql_upgrade_wizard is not marked to require elevation. Solved by using MANIFESTUAC linker flag, rather than invoke mt.exe. This avoids an extra post-build step that modifies mariadb-upgrade-wizard.exe --- win/upgrade_wizard/CMakeLists.txt | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/win/upgrade_wizard/CMakeLists.txt b/win/upgrade_wizard/CMakeLists.txt index 5a98ab15d0f..20a06a41215 100644 --- a/win/upgrade_wizard/CMakeLists.txt +++ b/win/upgrade_wizard/CMakeLists.txt @@ -35,17 +35,12 @@ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/sql) MYSQL_ADD_EXECUTABLE(mariadb-upgrade-wizard upgrade.cpp upgradeDlg.cpp upgrade.rc ${UPGRADE_WIZARD_SOURCES} COMPONENT Server) + + TARGET_LINK_LIBRARIES(mariadb-upgrade-wizard ${UPGRADE_WIZARD_LINK_LIBRARIES}) # upgrade_wizard is Windows executable, set WIN32_EXECUTABLE so it does not # create a console. -SET_TARGET_PROPERTIES(mariadb-upgrade-wizard PROPERTIES WIN32_EXECUTABLE 1) - -# Embed Vista "admin" manifest, since upgrade_wizard needs admin privileges -# to change service configuration. Due to a CMake bug http://www.vtk.org/Bug/view.php?id=11171 -# it is not possible currenly to do it with linker flags. Work around is to use -# manifest tool mt.exe and embed the manifest post-build. -ADD_CUSTOM_COMMAND( - TARGET mariadb-upgrade-wizard POST_BUILD - COMMAND mt.exe -manifest ${CMAKE_CURRENT_SOURCE_DIR}/upgrade_wizard.exe.manifest - "-outputresource:$;#1" +SET_TARGET_PROPERTIES(mariadb-upgrade-wizard PROPERTIES + WIN32_EXECUTABLE 1 + LINK_FLAGS "/MANIFESTUAC:level='requireAdministrator'" ) From 5eff7c022608af69c5f3591326e2be5132033977 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Wed, 12 Aug 2020 21:38:03 +0200 Subject: [PATCH 17/70] MDEV-23462 Upgrade wizard not offered during 10.5 MSI installation on Windows There is no mysql_upgrade_wizard target, only mariadb-upgrade-wizard --- win/packaging/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/win/packaging/CMakeLists.txt b/win/packaging/CMakeLists.txt index 2138c9233ad..d11053fa1dd 100644 --- a/win/packaging/CMakeLists.txt +++ b/win/packaging/CMakeLists.txt @@ -123,7 +123,7 @@ ELSE() ENDIF() SET(CPACK_WIX_CONFIG ${CMAKE_CURRENT_SOURCE_DIR}/CPackWixConfig.cmake) -IF(NOT TARGET mysql_upgrade_wizard) +IF(NOT TARGET mariadb-upgrade-wizard) SET(EXTRA_WIX_PREPROCESSOR_FLAGS "-dHaveUpgradeWizard=0") ENDIF() IF(WITH_INNOBASE_STORAGE_ENGINE) From 7c2aad6be2bc94e022b39cdffe218604d91d410a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Thu, 13 Aug 2020 17:43:37 +0300 Subject: [PATCH 18/70] MDEV-23463 fil_page_decompress() debug check wastes 128KiB of stack fil_page_decompress(): Remove a rather useless debug check. We should have test coverage for reading page_compressed pages from files, either due to buffer pool page eviction or due to server restarts. A similar check was removed from fil_space_encrypt() in commit 0b36c27e0c06b798b7322ab07d8464b69a7b716c (MDEV-20307). --- storage/innobase/fil/fil0pagecompress.cc | 14 +------------- storage/xtradb/fil/fil0pagecompress.cc | 14 +------------- 2 files changed, 2 insertions(+), 26 deletions(-) diff --git a/storage/innobase/fil/fil0pagecompress.cc b/storage/innobase/fil/fil0pagecompress.cc index edc1fa913e7..656d1d46a6a 100644 --- a/storage/innobase/fil/fil0pagecompress.cc +++ b/storage/innobase/fil/fil0pagecompress.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (C) 2013, 2018, MariaDB Corporation. +Copyright (C) 2013, 2020, MariaDB Corporation. 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 @@ -243,24 +243,12 @@ success: /* Set up the actual payload lenght */ mach_write_to_2(out_buf+FIL_PAGE_DATA, write_size); -#ifdef UNIV_DEBUG - /* Verify */ ut_ad(fil_page_is_compressed(out_buf) || fil_page_is_compressed_encrypted(out_buf)); ut_ad(mach_read_from_4(out_buf+FIL_PAGE_SPACE_OR_CHKSUM) == BUF_NO_CHECKSUM_MAGIC); ut_ad(mach_read_from_2(out_buf+FIL_PAGE_DATA) == write_size); ut_ad(mach_read_from_8(out_buf+FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION) == (ulint)comp_method || mach_read_from_2(out_buf+FIL_PAGE_DATA+FIL_PAGE_COMPRESSED_SIZE) == (ulint)comp_method); - /* Verify that page can be decompressed */ - { - page_t tmp_buf[UNIV_PAGE_SIZE_MAX]; - page_t page[UNIV_PAGE_SIZE_MAX]; - memcpy(page, out_buf, srv_page_size); - ut_ad(fil_page_decompress(tmp_buf, page)); - ut_ad(!buf_page_is_corrupted(false, page, 0, NULL)); - } -#endif /* UNIV_DEBUG */ - write_size+=header_len; if (block_size <= 0) { diff --git a/storage/xtradb/fil/fil0pagecompress.cc b/storage/xtradb/fil/fil0pagecompress.cc index edc1fa913e7..656d1d46a6a 100644 --- a/storage/xtradb/fil/fil0pagecompress.cc +++ b/storage/xtradb/fil/fil0pagecompress.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (C) 2013, 2018, MariaDB Corporation. +Copyright (C) 2013, 2020, MariaDB Corporation. 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 @@ -243,24 +243,12 @@ success: /* Set up the actual payload lenght */ mach_write_to_2(out_buf+FIL_PAGE_DATA, write_size); -#ifdef UNIV_DEBUG - /* Verify */ ut_ad(fil_page_is_compressed(out_buf) || fil_page_is_compressed_encrypted(out_buf)); ut_ad(mach_read_from_4(out_buf+FIL_PAGE_SPACE_OR_CHKSUM) == BUF_NO_CHECKSUM_MAGIC); ut_ad(mach_read_from_2(out_buf+FIL_PAGE_DATA) == write_size); ut_ad(mach_read_from_8(out_buf+FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION) == (ulint)comp_method || mach_read_from_2(out_buf+FIL_PAGE_DATA+FIL_PAGE_COMPRESSED_SIZE) == (ulint)comp_method); - /* Verify that page can be decompressed */ - { - page_t tmp_buf[UNIV_PAGE_SIZE_MAX]; - page_t page[UNIV_PAGE_SIZE_MAX]; - memcpy(page, out_buf, srv_page_size); - ut_ad(fil_page_decompress(tmp_buf, page)); - ut_ad(!buf_page_is_corrupted(false, page, 0, NULL)); - } -#endif /* UNIV_DEBUG */ - write_size+=header_len; if (block_size <= 0) { From b811c6ecc74cc1421eedc92573447768d1eb7980 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Thu, 13 Aug 2020 18:21:30 +0300 Subject: [PATCH 19/70] Fix GCC 10.2.0 -Og -Wmaybe-uninitialized Fix some more cases after merging commit 31aef3ae99dff6b7154cf288b3dc508d367f19f8. Some warnings look possibly genuine, others are clearly bogus. --- sql/ha_partition.cc | 12 ++++++------ sql/item_strfunc.cc | 6 +++--- sql/sql_repl.cc | 6 +++++- sql/sql_yacc.yy | 12 ++++++++---- sql/sql_yacc_ora.yy | 14 ++++++++------ 5 files changed, 30 insertions(+), 20 deletions(-) diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index d694fedb831..d4cab001a9a 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -1,6 +1,6 @@ /* Copyright (c) 2005, 2019, Oracle and/or its affiliates. - Copyright (c) 2009, 2019, MariaDB + Copyright (c) 2009, 2020, MariaDB 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 @@ -6380,7 +6380,7 @@ ha_rows ha_partition::multi_range_read_info(uint keyno, uint n_ranges, { uint i; handler **file; - ha_rows rows; + ha_rows rows= 0; DBUG_ENTER("ha_partition::multi_range_read_info"); DBUG_PRINT("enter", ("partition this: %p", this)); @@ -9516,7 +9516,6 @@ double ha_partition::read_time(uint index, uint ranges, ha_rows rows) ha_rows ha_partition::records() { - int error; ha_rows tot_rows= 0; uint i; DBUG_ENTER("ha_partition::records"); @@ -9525,9 +9524,10 @@ ha_rows ha_partition::records() i < m_tot_parts; i= bitmap_get_next_set(&m_part_info->read_partitions, i)) { - ha_rows rows; - if (unlikely((error= m_file[i]->pre_records()) || - (rows= m_file[i]->records()) == HA_POS_ERROR)) + if (unlikely(m_file[i]->pre_records())) + DBUG_RETURN(HA_POS_ERROR); + const ha_rows rows= m_file[i]->records(); + if (unlikely(rows == HA_POS_ERROR)) DBUG_RETURN(HA_POS_ERROR); tot_rows+= rows; } diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 0d519edc5b3..5bdd3e10069 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -1,6 +1,6 @@ /* Copyright (c) 2000, 2017, Oracle and/or its affiliates. - Copyright (c) 2009, 2019, MariaDB Corporation + Copyright (c) 2009, 2020, MariaDB Corporation. 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 @@ -646,7 +646,7 @@ String *Item_func_concat_operator_oracle::val_str(String *str) { DBUG_ASSERT(fixed == 1); THD *thd= current_thd; - String *res; + String *res= NULL; uint i; null_value=0; @@ -656,7 +656,7 @@ String *Item_func_concat_operator_oracle::val_str(String *str) if ((res= args[i]->val_str(str))) break; } - if (i == arg_count) + if (!res) goto null; if (res != str) diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index cd8a2129410..4b23348b306 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -374,11 +374,15 @@ static int send_file(THD *thd) We need net_flush here because the client will not know it needs to send us the file name until it has processed the load event entry */ - if (unlikely(net_flush(net) || (packet_len = my_net_read(net)) == packet_error)) + if (unlikely(net_flush(net))) { + read_error: errmsg = "while reading file name"; goto err; } + packet_len= my_net_read(net); + if (unlikely(packet_len == packet_error)) + goto read_error; // terminate with \0 for fn_format *((char*)net->read_pos + packet_len) = 0; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 04a19d6922e..b3d89eab472 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -4451,9 +4451,11 @@ sp_fetch_list: LEX *lex= Lex; sp_head *sp= lex->sphead; sp_pcontext *spc= lex->spcont; - sp_variable *spv; + sp_variable *spv= likely(spc != NULL) + ? spc->find_variable(&$1, false) + : NULL; - if (unlikely(!spc || !(spv = spc->find_variable(&$1, false)))) + if (unlikely(!spv)) my_yyabort_error((ER_SP_UNDECLARED_VAR, MYF(0), $1.str)); /* An SP local variable */ @@ -4465,9 +4467,11 @@ sp_fetch_list: LEX *lex= Lex; sp_head *sp= lex->sphead; sp_pcontext *spc= lex->spcont; - sp_variable *spv; + sp_variable *spv= likely(spc != NULL) + ? spc->find_variable(&$3, false) + : NULL; - if (unlikely(!spc || !(spv = spc->find_variable(&$3, false)))) + if (unlikely(!spv)) my_yyabort_error((ER_SP_UNDECLARED_VAR, MYF(0), $3.str)); /* An SP local variable */ diff --git a/sql/sql_yacc_ora.yy b/sql/sql_yacc_ora.yy index a1eb74771ef..a4ee6d725e3 100644 --- a/sql/sql_yacc_ora.yy +++ b/sql/sql_yacc_ora.yy @@ -4205,9 +4205,10 @@ sp_fetch_list: LEX *lex= Lex; sp_head *sp= lex->sphead; sp_pcontext *spc= lex->spcont; - sp_variable *spv; - - if (unlikely(!spc || !(spv = spc->find_variable(&$1, false)))) + sp_variable *spv= likely(spc != NULL) + ? spc->find_variable(&$1, false) + : NULL; + if (unlikely(!spv)) my_yyabort_error((ER_SP_UNDECLARED_VAR, MYF(0), $1.str)); /* An SP local variable */ @@ -4219,9 +4220,10 @@ sp_fetch_list: LEX *lex= Lex; sp_head *sp= lex->sphead; sp_pcontext *spc= lex->spcont; - sp_variable *spv; - - if (unlikely(!spc || !(spv = spc->find_variable(&$3, false)))) + sp_variable *spv= likely(spc != NULL) + ? spc->find_variable(&$3, false) + : NULL; + if (unlikely(!spv)) my_yyabort_error((ER_SP_UNDECLARED_VAR, MYF(0), $3.str)); /* An SP local variable */ From 0ac8e2cfdba216f0f33b688cc0cdc464364f9c78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Otto=20Kek=C3=A4l=C3=A4inen?= Date: Thu, 13 Aug 2020 21:44:46 +0300 Subject: [PATCH 20/70] Add a Github CODEOWNERS file to project MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As the first entry, define user 'ottok' (Otto Kekäläinen) as the person who by default gets assigned all PRs that modify the debian/ contents. --- .github/CODEOWNERS | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .github/CODEOWNERS diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 00000000000..538007ed62d --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,2 @@ +/debian @ottok + From e96f66b93dbb9cb2b56172a25693b056baca7476 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Thu, 23 Jul 2020 14:48:04 +0400 Subject: [PATCH 21/70] MDEV-23270 Remove a String parameter from Protocol::store(double/float) --- sql/field.cc | 4 ++-- sql/protocol.cc | 16 ++++++++-------- sql/protocol.h | 17 +++++++++-------- sql/slave.cc | 2 +- sql/sql_prepare.cc | 8 ++++---- sql/sql_profile.cc | 6 ++---- sql/sql_show.cc | 4 +--- sql/sql_type.cc | 4 ++-- 8 files changed, 29 insertions(+), 32 deletions(-) diff --git a/sql/field.cc b/sql/field.cc index f50ddec1c80..90535344174 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -4689,7 +4689,7 @@ void Field_float::sort_string(uchar *to,uint length __attribute__((unused))) bool Field_float::send_binary(Protocol *protocol) { DBUG_ASSERT(marked_for_read()); - return protocol->store((float) Field_float::val_real(), dec, (String*) 0); + return protocol->store_float((float) Field_float::val_real(), dec); } @@ -4982,7 +4982,7 @@ String *Field_double::val_str(String *val_buffer, bool Field_double::send_binary(Protocol *protocol) { - return protocol->store((double) Field_double::val_real(), dec, (String*) 0); + return protocol->store_double(Field_double::val_real(), dec); } diff --git a/sql/protocol.cc b/sql/protocol.cc index 369ef27877d..051f70f01b0 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -1301,25 +1301,25 @@ bool Protocol_text::store_decimal(const my_decimal *d) } -bool Protocol_text::store(float from, uint32 decimals, String *buffer) +bool Protocol_text::store_float(float from, uint32 decimals) { #ifndef DBUG_OFF DBUG_ASSERT(valid_handler(field_pos, PROTOCOL_SEND_FLOAT)); field_pos++; #endif - Float(from).to_string(buffer, decimals); - return store_numeric_string_aux(buffer->ptr(), buffer->length()); + Float(from).to_string(&buffer, decimals); + return store_numeric_string_aux(buffer.ptr(), buffer.length()); } -bool Protocol_text::store(double from, uint32 decimals, String *buffer) +bool Protocol_text::store_double(double from, uint32 decimals) { #ifndef DBUG_OFF DBUG_ASSERT(valid_handler(field_pos, PROTOCOL_SEND_DOUBLE)); field_pos++; #endif - buffer->set_real(from, decimals, thd->charset()); - return store_numeric_string_aux(buffer->ptr(), buffer->length()); + buffer.set_real(from, decimals, thd->charset()); + return store_numeric_string_aux(buffer.ptr(), buffer.length()); } @@ -1538,7 +1538,7 @@ bool Protocol_binary::store_decimal(const my_decimal *d) thd->variables.character_set_results); } -bool Protocol_binary::store(float from, uint32 decimals, String *buffer) +bool Protocol_binary::store_float(float from, uint32 decimals) { field_pos++; char *to= packet->prep_append(4, PACKET_BUFFER_EXTRA_ALLOC); @@ -1549,7 +1549,7 @@ bool Protocol_binary::store(float from, uint32 decimals, String *buffer) } -bool Protocol_binary::store(double from, uint32 decimals, String *buffer) +bool Protocol_binary::store_double(double from, uint32 decimals) { field_pos++; char *to= packet->prep_append(8, PACKET_BUFFER_EXTRA_ALLOC); diff --git a/sql/protocol.h b/sql/protocol.h index 45f6d66dc26..474206c47cd 100644 --- a/sql/protocol.h +++ b/sql/protocol.h @@ -141,8 +141,8 @@ public: CHARSET_INFO *fromcs, my_repertoire_t from_repertoire, CHARSET_INFO *tocs)=0; - virtual bool store(float from, uint32 decimals, String *buffer)=0; - virtual bool store(double from, uint32 decimals, String *buffer)=0; + virtual bool store_float(float from, uint32 decimals)=0; + virtual bool store_double(double from, uint32 decimals)=0; virtual bool store(MYSQL_TIME *time, int decimals)=0; virtual bool store_date(MYSQL_TIME *time)=0; virtual bool store_time(MYSQL_TIME *time, int decimals)=0; @@ -208,6 +208,7 @@ public: class Protocol_text final :public Protocol { + StringBuffer buffer; bool store_numeric_string_aux(const char *from, size_t length); public: Protocol_text(THD *thd_arg, ulong prealloc= 0) @@ -230,8 +231,8 @@ public: bool store(MYSQL_TIME *time, int decimals) override; bool store_date(MYSQL_TIME *time) override; bool store_time(MYSQL_TIME *time, int decimals) override; - bool store(float nr, uint32 decimals, String *buffer) override; - bool store(double from, uint32 decimals, String *buffer) override; + bool store_float(float nr, uint32 decimals) override; + bool store_double(double from, uint32 decimals) override; bool store(Field *field) override; bool send_out_parameters(List *sp_params) override; @@ -276,8 +277,8 @@ public: bool store(MYSQL_TIME *time, int decimals) override; bool store_date(MYSQL_TIME *time) override; bool store_time(MYSQL_TIME *time, int decimals) override; - bool store(float nr, uint32 decimals, String *buffer) override; - bool store(double from, uint32 decimals, String *buffer) override; + bool store_float(float nr, uint32 decimals) override; + bool store_double(double from, uint32 decimals) override; bool store(Field *field) override; bool send_out_parameters(List *sp_params) override; @@ -328,8 +329,8 @@ public: bool store(MYSQL_TIME *, int) override { return false; } bool store_date(MYSQL_TIME *) override { return false; } bool store_time(MYSQL_TIME *, int) override { return false; } - bool store(float, uint32, String *) override { return false; } - bool store(double, uint32, String *) override { return false; } + bool store_float(float, uint32) override { return false; } + bool store_double(double, uint32) override { return false; } bool store(Field *) override { return false; } enum enum_protocol_type type() override { return PROTOCOL_DISCARD; }; }; diff --git a/sql/slave.cc b/sql/slave.cc index cf94f1dc0b5..c302ba1de64 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -3478,7 +3478,7 @@ static bool send_show_master_info_data(THD *thd, Master_info *mi, bool full, protocol->store((ulonglong) mi->rli.max_relay_log_size); protocol->store(mi->rli.executed_entries); protocol->store((uint32) mi->received_heartbeats); - protocol->store((double) mi->heartbeat_period, 3, &tmp); + protocol->store_double(mi->heartbeat_period, 3); protocol->store(gtid_pos->ptr(), gtid_pos->length(), &my_charset_bin); } diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index bf531fe4d7d..7e783ade42c 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -269,8 +269,8 @@ protected: virtual bool store(MYSQL_TIME *time, int decimals); virtual bool store_date(MYSQL_TIME *time); virtual bool store_time(MYSQL_TIME *time, int decimals); - virtual bool store(float value, uint32 decimals, String *buffer); - virtual bool store(double value, uint32 decimals, String *buffer); + virtual bool store_float(float value, uint32 decimals); + virtual bool store_double(double value, uint32 decimals); virtual bool store(Field *field); virtual bool send_result_set_metadata(List *list, uint flags); @@ -5378,7 +5378,7 @@ bool Protocol_local::store_time(MYSQL_TIME *time, int decimals) /* Store a floating point number, as is. */ -bool Protocol_local::store(float value, uint32 decimals, String *buffer) +bool Protocol_local::store_float(float value, uint32 decimals) { return store_column(&value, sizeof(float)); } @@ -5386,7 +5386,7 @@ bool Protocol_local::store(float value, uint32 decimals, String *buffer) /* Store a double precision number, as is. */ -bool Protocol_local::store(double value, uint32 decimals, String *buffer) +bool Protocol_local::store_double(double value, uint32 decimals) { return store_column(&value, sizeof (double)); } diff --git a/sql/sql_profile.cc b/sql/sql_profile.cc index 2a47aa846eb..d8ecd2abee7 100644 --- a/sql/sql_profile.cc +++ b/sql/sql_profile.cc @@ -433,8 +433,6 @@ bool PROFILING::show_profiles() { prof= history.iterator_value(iterator); - String elapsed; - double query_time_usecs= prof->m_end_time_usecs - prof->m_start_time_usecs; if (unit->lim.check_offset(idx)) @@ -444,8 +442,8 @@ bool PROFILING::show_profiles() protocol->prepare_for_resend(); protocol->store((uint32)(prof->profiling_query_id)); - protocol->store((double)(query_time_usecs/(1000.0*1000)), - (uint32) TIME_FLOAT_DIGITS-1, &elapsed); + protocol->store_double(query_time_usecs/(1000.0*1000), + (uint32) TIME_FLOAT_DIGITS-1); if (prof->query_source != NULL) protocol->store(prof->query_source, strlen(prof->query_source), system_charset_info); diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 0d41857aaf5..452690f3237 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -2891,8 +2891,6 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose) server_threads.iterate(list_callback, &arg); ulonglong now= microsecond_interval_timer(); - char buff[20]; // For progress - String store_buffer(buff, sizeof(buff), system_charset_info); while (auto thd_info= arg.thread_infos.get()) { @@ -2918,7 +2916,7 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose) protocol->store_null(); if (!thd->variables.old_mode && !(thd->variables.old_behavior & OLD_MODE_NO_PROGRESS_INFO)) - protocol->store(thd_info->progress, 3, &store_buffer); + protocol->store_double(thd_info->progress, 3); if (protocol->write()) break; /* purecov: inspected */ } diff --git a/sql/sql_type.cc b/sql/sql_type.cc index 9e0f9b013c0..adceb5013c8 100644 --- a/sql/sql_type.cc +++ b/sql/sql_type.cc @@ -7348,7 +7348,7 @@ bool Type_handler:: { float nr= (float) item->val_real(); if (!item->null_value) - return protocol->store(nr, item->decimals, &buf->m_string); + return protocol->store_float(nr, item->decimals); return protocol->store_null(); } @@ -7358,7 +7358,7 @@ bool Type_handler:: { double nr= item->val_real(); if (!item->null_value) - return protocol->store(nr, item->decimals, &buf->m_string); + return protocol->store_double(nr, item->decimals); return protocol->store_null(); } From f1a9700fec8312bdce3e7a7145389adede1722b2 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Fri, 24 Jul 2020 06:46:40 +0400 Subject: [PATCH 22/70] Revert "MDEV-23162 Improve Protocol performance for numeric data" This reverts commit eb2eaba7fdbd13c9814ab4619cc23d9f140e5485. A different implementation of MDEV-23162 is coming. --- sql/protocol.cc | 28 ++++++++----------------- sql/protocol.h | 52 ++++++++++++++-------------------------------- sql/sql_prepare.cc | 20 ++++++------------ 3 files changed, 31 insertions(+), 69 deletions(-) diff --git a/sql/protocol.cc b/sql/protocol.cc index 051f70f01b0..189cdfca9af 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -848,13 +848,12 @@ bool Protocol_text::store_field_metadata(const THD * thd, { CHARSET_INFO *thd_charset= thd->variables.character_set_results; char *pos; - CHARSET_INFO *cs= system_charset_info; DBUG_ASSERT(field.is_sane()); if (thd->client_capabilities & CLIENT_PROTOCOL_41) { const LEX_CSTRING def= {STRING_WITH_LEN("def")}; - if (store_ident(def, MY_REPERTOIRE_ASCII) || + if (store_ident(def) || store_ident(field.db_name) || store_ident(field.table_name) || store_ident(field.org_table_name) || @@ -870,8 +869,7 @@ bool Protocol_text::store_field_metadata(const THD * thd, Don't apply character set conversion: extended metadata is a binary encoded data. */ - if (store_binary_string(&metadata, cs, - MY_REPERTOIRE_UNICODE30)) + if (store_binary_string(metadata.ptr(), metadata.length())) return true; } if (packet->realloc(packet->length() + 12)) @@ -1185,12 +1183,10 @@ bool Protocol_text::store_null() */ bool Protocol::store_string_aux(const char *from, size_t length, - CHARSET_INFO *fromcs, - my_repertoire_t from_repertoire, - CHARSET_INFO *tocs) + CHARSET_INFO *fromcs, CHARSET_INFO *tocs) { /* 'tocs' is set 0 when client issues SET character_set_results=NULL */ - if (needs_conversion(fromcs, from_repertoire, tocs)) + if (needs_conversion(fromcs, tocs)) { /* Store with conversion */ return net_store_data_cs((uchar*) from, length, fromcs, tocs); @@ -1223,9 +1219,7 @@ bool Protocol::store_warning(const char *from, size_t length) bool Protocol_text::store_str(const char *from, size_t length, - CHARSET_INFO *fromcs, - my_repertoire_t from_repertoire, - CHARSET_INFO *tocs) + CHARSET_INFO *fromcs, CHARSET_INFO *tocs) { #ifndef DBUG_OFF DBUG_PRINT("info", ("Protocol_text::store field %u : %.*b", field_pos, @@ -1234,7 +1228,7 @@ bool Protocol_text::store_str(const char *from, size_t length, DBUG_ASSERT(valid_handler(field_pos, PROTOCOL_SEND_STRING)); field_pos++; #endif - return store_string_aux(from, length, fromcs, from_repertoire, tocs); + return store_string_aux(from, length, fromcs, tocs); } @@ -1346,8 +1340,7 @@ bool Protocol_text::store(Field *field) dbug_tmp_restore_column_map(table->read_set, old_map); #endif - return store_string_aux(str.ptr(), str.length(), str.charset(), - field->dtcollation().repertoire, tocs); + return store_string_aux(str.ptr(), str.length(), str.charset(), tocs); } @@ -1466,12 +1459,10 @@ void Protocol_binary::prepare_for_resend() bool Protocol_binary::store_str(const char *from, size_t length, - CHARSET_INFO *fromcs, - my_repertoire_t from_repertoire, - CHARSET_INFO *tocs) + CHARSET_INFO *fromcs, CHARSET_INFO *tocs) { field_pos++; - return store_string_aux(from, length, fromcs, from_repertoire, tocs); + return store_string_aux(from, length, fromcs, tocs); } bool Protocol_binary::store_null() @@ -1534,7 +1525,6 @@ bool Protocol_binary::store_decimal(const my_decimal *d) StringBuffer str; (void) d->to_string(&str); return store_str(str.ptr(), str.length(), str.charset(), - MY_REPERTOIRE_ASCII, thd->variables.character_set_results); } diff --git a/sql/protocol.h b/sql/protocol.h index 474206c47cd..da01b6244e1 100644 --- a/sql/protocol.h +++ b/sql/protocol.h @@ -63,25 +63,19 @@ protected: MEM_ROOT *alloc; #endif bool needs_conversion(CHARSET_INFO *fromcs, - my_repertoire_t from_repertoire, CHARSET_INFO *tocs) const { // 'tocs' is set 0 when client issues SET character_set_results=NULL return tocs && !my_charset_same(fromcs, tocs) && fromcs != &my_charset_bin && - tocs != &my_charset_bin && - (from_repertoire != MY_REPERTOIRE_ASCII || - (fromcs->state & MY_CS_NONASCII) || - (tocs->state & MY_CS_NONASCII)); + tocs != &my_charset_bin; } /* The following two are low-level functions that are invoked from higher-level store_xxx() funcs. The data is stored into this->packet. */ bool store_string_aux(const char *from, size_t length, - CHARSET_INFO *fromcs, - my_repertoire_t from_repertoire, - CHARSET_INFO *tocs); + CHARSET_INFO *fromcs, CHARSET_INFO *tocs); virtual bool send_ok(uint server_status, uint statement_warn_count, ulonglong affected_rows, ulonglong last_insert_id, @@ -138,9 +132,7 @@ public: virtual bool store_longlong(longlong from, bool unsigned_flag)=0; virtual bool store_decimal(const my_decimal *)=0; virtual bool store_str(const char *from, size_t length, - CHARSET_INFO *fromcs, - my_repertoire_t from_repertoire, - CHARSET_INFO *tocs)=0; + CHARSET_INFO *fromcs, CHARSET_INFO *tocs)=0; virtual bool store_float(float from, uint32 decimals)=0; virtual bool store_double(double from, uint32 decimals)=0; virtual bool store(MYSQL_TIME *time, int decimals)=0; @@ -150,30 +142,23 @@ public: // Various useful wrappers for the virtual store*() methods. // Backward wrapper for store_str() - inline bool store(const char *from, size_t length, CHARSET_INFO *cs, - my_repertoire_t repertoire= MY_REPERTOIRE_UNICODE30) + bool store(const char *from, size_t length, CHARSET_INFO *cs) { - return store_str(from, length, cs, repertoire, character_set_results()); + return store_str(from, length, cs, character_set_results()); } - inline bool store_lex_cstring(const LEX_CSTRING &s, - CHARSET_INFO *fromcs, - my_repertoire_t from_repertoire, - CHARSET_INFO *tocs) + bool store_lex_cstring(const LEX_CSTRING &s, + CHARSET_INFO *fromcs, + CHARSET_INFO *tocs) { - return store_str(s.str, (uint) s.length, fromcs, from_repertoire, tocs); + return store_str(s.str, (uint) s.length, fromcs, tocs); } - inline bool store_binary_string(Binary_string *str, - CHARSET_INFO *fromcs, - my_repertoire_t from_repertoire) + bool store_binary_string(const char *str, size_t length) { - return store_str(str->ptr(), (uint) str->length(), fromcs, from_repertoire, - &my_charset_bin); + return store_str(str, (uint) length, &my_charset_bin, &my_charset_bin); } - bool store_ident(const LEX_CSTRING &s, - my_repertoire_t repertoire= MY_REPERTOIRE_UNICODE30) + bool store_ident(const LEX_CSTRING &s) { - return store_lex_cstring(s, system_charset_info, repertoire, - character_set_results()); + return store_lex_cstring(s, system_charset_info, character_set_results()); } // End of wrappers @@ -225,9 +210,7 @@ public: bool store_longlong(longlong from, bool unsigned_flag) override; bool store_decimal(const my_decimal *) override; bool store_str(const char *from, size_t length, - CHARSET_INFO *fromcs, - my_repertoire_t from_repertoire, - CHARSET_INFO *tocs) override; + CHARSET_INFO *fromcs, CHARSET_INFO *tocs) override; bool store(MYSQL_TIME *time, int decimals) override; bool store_date(MYSQL_TIME *time) override; bool store_time(MYSQL_TIME *time, int decimals) override; @@ -271,9 +254,7 @@ public: bool store_longlong(longlong from, bool unsigned_flag) override; bool store_decimal(const my_decimal *) override; bool store_str(const char *from, size_t length, - CHARSET_INFO *fromcs, - my_repertoire_t from_repertoire, - CHARSET_INFO *tocs) override; + CHARSET_INFO *fromcs, CHARSET_INFO *tocs); bool store(MYSQL_TIME *time, int decimals) override; bool store_date(MYSQL_TIME *time) override; bool store_time(MYSQL_TIME *time, int decimals) override; @@ -321,8 +302,7 @@ public: bool store_long(longlong) override { return false; } bool store_longlong(longlong, bool) override { return false; } bool store_decimal(const my_decimal *) override { return false; } - bool store_str(const char *, size_t, CHARSET_INFO *, my_repertoire_t, - CHARSET_INFO *) override + bool store_str(const char *, size_t, CHARSET_INFO *, CHARSET_INFO *) { return false; } diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 7e783ade42c..5d034b80b6d 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -263,9 +263,7 @@ protected: virtual bool store_longlong(longlong from, bool unsigned_flag); virtual bool store_decimal(const my_decimal *); virtual bool store_str(const char *from, size_t length, - CHARSET_INFO *fromcs, - my_repertoire_t from_repertoire, - CHARSET_INFO *tocs); + CHARSET_INFO *fromcs, CHARSET_INFO *tocs); virtual bool store(MYSQL_TIME *time, int decimals); virtual bool store_date(MYSQL_TIME *time); virtual bool store_time(MYSQL_TIME *time, int decimals); @@ -288,9 +286,7 @@ protected: virtual bool send_error(uint sql_errno, const char *err_msg, const char* sqlstate); private: bool store_string(const char *str, size_t length, - CHARSET_INFO *src_cs, - my_repertoire_t src_repertoire, - CHARSET_INFO *dst_cs); + CHARSET_INFO *src_cs, CHARSET_INFO *dst_cs); bool store_column(const void *data, size_t length); void opt_add_row_to_rset(); @@ -5273,14 +5269,12 @@ bool Protocol_local::store_column(const void *data, size_t length) bool Protocol_local::store_string(const char *str, size_t length, - CHARSET_INFO *src_cs, - my_repertoire_t src_repertoire, - CHARSET_INFO *dst_cs) + CHARSET_INFO *src_cs, CHARSET_INFO *dst_cs) { /* Store with conversion */ uint error_unused; - if (needs_conversion(src_cs, src_repertoire, dst_cs)) + if (needs_conversion(src_cs, dst_cs)) { if (unlikely(convert->copy(str, length, src_cs, dst_cs, &error_unused))) return TRUE; @@ -5340,11 +5334,9 @@ bool Protocol_local::store_decimal(const my_decimal *value) /** Store a string. */ bool Protocol_local::store_str(const char *str, size_t length, - CHARSET_INFO *src_cs, - my_repertoire_t from_repertoire, - CHARSET_INFO *dst_cs) + CHARSET_INFO *src_cs, CHARSET_INFO *dst_cs) { - return store_string(str, length, src_cs, from_repertoire, dst_cs); + return store_string(str, length, src_cs, dst_cs); } From c55f24cd99f3c6f001c210bc83f1f6b5b106bf83 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Fri, 24 Jul 2020 08:07:04 +0400 Subject: [PATCH 23/70] MDEV-23162 Improve Protocol performance for numeric data An alternative implementation (replacing the one based on repertoire). This implementation makes Field send itself to Protocol_text using data type specific Protocol methods rather than field->val_str() followed by protocol_text->store_str(). As now Field sends itself in the same way to all protocol types (e.g. Protocol_binary, Protocol_text, Protocol_local), the method Field::send_binary() was renamed just to Field::send(). Note, this change introduces symmetry between Field and Item, because Items also send themself using a single method Item::send(), which is used for *all* protocol types. Performance improvement is achieved by the fact that Protocol_text implements these data type specific methods using store_numeric_string_aux() rather than store_string_aux(). The conversion now happens only when character_set_results is not ASCII compatible character sets (e.g. UCS2, UTF16, UTF32). In the old code (before any MDEV-23162 work, e.g. as of 10.5.4), Protocol_text::store(Field*) used val_str() for all data types. So the execution went through the character set conversion routines even for numeric and temporal data types. Benchmarking summary (see details in MDEV-23478): The new approach stably demonstrates additional improvement comparing to the previous implementation (the smaller time - the better): Original - the commit before MDEV-23162 be98036f25ac8cfb34fa5bb5066975d79f595aec 1m9.336s 1m9.290s 1m9.300s MDEV-23162 - the repertoire optimization 1m6.101s 1m5.988s 1m6.264s MDEV-23478 - this commit 1m2.150s 1m2.079s 1m2.099s --- sql/field.cc | 103 +++++++++++++++++++++++++++++++++++++-------- sql/field.h | 56 +++++++++++++++++------- sql/protocol.cc | 31 +++++++++----- sql/protocol.h | 4 ++ sql/sql_prepare.cc | 2 +- 5 files changed, 152 insertions(+), 44 deletions(-) diff --git a/sql/field.cc b/sql/field.cc index 90535344174..d20c2c3af5c 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -1888,7 +1888,7 @@ void Field::copy_from_tmp(int row_offset) } -bool Field::send_binary(Protocol *protocol) +bool Field::send(Protocol *protocol) { char buff[MAX_FIELD_WIDTH]; String tmp(buff,sizeof(buff),charset()); @@ -1897,6 +1897,18 @@ bool Field::send_binary(Protocol *protocol) } +bool Field_num::send_numeric_zerofill_str(Protocol_text *protocol, + protocol_send_type_t send_type) +{ + DBUG_ASSERT(marked_for_read()); + StringBuffer tmp(&my_charset_latin1); + val_str(&tmp); + return protocol->store_numeric_zerofill_str(tmp.ptr(), + tmp.length(), + send_type); +} + + /** Check to see if field size is compatible with destination. @@ -3855,11 +3867,16 @@ String *Field_tiny::val_str(String *val_buffer, return val_str_from_long(val_buffer, 5, -10, nr); } -bool Field_tiny::send_binary(Protocol *protocol) +bool Field_tiny::send(Protocol *protocol) { - return protocol->store_tiny((longlong) (int8) ptr[0]); + DBUG_ASSERT(marked_for_read()); + Protocol_text *txt; + if (unlikely(zerofill) && (txt= dynamic_cast(protocol))) + return send_numeric_zerofill_str(txt, PROTOCOL_SEND_TINY); + return protocol->store_tiny(Field_tiny::val_int()); } + int Field_tiny::cmp(const uchar *a_ptr, const uchar *b_ptr) const { signed char a,b; @@ -4015,8 +4032,12 @@ String *Field_short::val_str(String *val_buffer, } -bool Field_short::send_binary(Protocol *protocol) +bool Field_short::send(Protocol *protocol) { + DBUG_ASSERT(marked_for_read()); + Protocol_text *txt; + if (unlikely(zerofill) && (txt= dynamic_cast(protocol))) + return send_numeric_zerofill_str(txt, PROTOCOL_SEND_SHORT); return protocol->store_short(Field_short::val_int()); } @@ -4198,9 +4219,12 @@ String *Field_int::val_str_from_long(String *val_buffer, } -bool Field_medium::send_binary(Protocol *protocol) +bool Field_medium::send(Protocol *protocol) { DBUG_ASSERT(marked_for_read()); + Protocol_text *txt; + if (unlikely(zerofill) && (txt= dynamic_cast(protocol))) + return send_numeric_zerofill_str(txt, PROTOCOL_SEND_LONG); return protocol->store_long(Field_medium::val_int()); } @@ -4369,12 +4393,16 @@ String *Field_long::val_str(String *val_buffer, } -bool Field_long::send_binary(Protocol *protocol) +bool Field_long::send(Protocol *protocol) { DBUG_ASSERT(marked_for_read()); + Protocol_text *txt; + if (unlikely(zerofill) && (txt= dynamic_cast(protocol))) + return send_numeric_zerofill_str(txt, PROTOCOL_SEND_LONG); return protocol->store_long(Field_long::val_int()); } + int Field_long::cmp(const uchar *a_ptr, const uchar *b_ptr) const { int32 a,b; @@ -4506,9 +4534,12 @@ String *Field_longlong::val_str(String *val_buffer, } -bool Field_longlong::send_binary(Protocol *protocol) +bool Field_longlong::send(Protocol *protocol) { DBUG_ASSERT(marked_for_read()); + Protocol_text *txt; + if (unlikely(zerofill) && (txt= dynamic_cast(protocol))) + return send_numeric_zerofill_str(txt, PROTOCOL_SEND_LONGLONG); return protocol->store_longlong(Field_longlong::val_int(), unsigned_flag); } @@ -4686,9 +4717,12 @@ void Field_float::sort_string(uchar *to,uint length __attribute__((unused))) } -bool Field_float::send_binary(Protocol *protocol) +bool Field_float::send(Protocol *protocol) { DBUG_ASSERT(marked_for_read()); + Protocol_text *txt; + if (unlikely(zerofill) && (txt= dynamic_cast(protocol))) + return send_numeric_zerofill_str(txt, PROTOCOL_SEND_FLOAT); return protocol->store_float((float) Field_float::val_real(), dec); } @@ -4980,8 +5014,12 @@ String *Field_double::val_str(String *val_buffer, return val_buffer; } -bool Field_double::send_binary(Protocol *protocol) +bool Field_double::send(Protocol *protocol) { + DBUG_ASSERT(marked_for_read()); + Protocol_text *txt; + if (unlikely(zerofill) && (txt= dynamic_cast(protocol))) + return send_numeric_zerofill_str(txt, PROTOCOL_SEND_DOUBLE); return protocol->store_double(Field_double::val_real(), dec); } @@ -5378,7 +5416,7 @@ bool Field_timestamp::get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate) } -bool Field_timestamp0::send_binary(Protocol *protocol) +bool Field_timestamp0::send(Protocol *protocol) { MYSQL_TIME ltime; Field_timestamp0::get_date(<ime, date_mode_t(0)); @@ -5538,7 +5576,7 @@ int Field_timestamp_with_dec::set_time() return 0; } -bool Field_timestamp_with_dec::send_binary(Protocol *protocol) +bool Field_timestamp_with_dec::send(Protocol *protocol) { MYSQL_TIME ltime; Field_timestamp::get_date(<ime, date_mode_t(0)); @@ -6047,7 +6085,7 @@ bool Field_time0::get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate) } -bool Field_time::send_binary(Protocol *protocol) +bool Field_time::send(Protocol *protocol) { MYSQL_TIME ltime; get_date(<ime, Time::Options(TIME_TIME_ONLY, get_thd())); @@ -6369,9 +6407,12 @@ int Field_year::store_time_dec(const MYSQL_TIME *ltime, uint dec_arg) return 0; } -bool Field_year::send_binary(Protocol *protocol) +bool Field_year::send(Protocol *protocol) { DBUG_ASSERT(marked_for_read()); + Protocol_text *txt; + if ((txt= dynamic_cast(protocol))) + return send_numeric_zerofill_str(txt, PROTOCOL_SEND_SHORT); ulonglong tmp= Field_year::val_int(); return protocol->store_short(tmp); } @@ -6506,7 +6547,7 @@ void Field_date::store_TIME(const MYSQL_TIME *ltime) int4store(ptr,tmp); } -bool Field_date::send_binary(Protocol *protocol) +bool Field_date::send(Protocol *protocol) { longlong tmp= Field_date::val_int(); MYSQL_TIME tm; @@ -6600,7 +6641,7 @@ void Field_newdate::store_TIME(const MYSQL_TIME *ltime) } -bool Field_newdate::send_binary(Protocol *protocol) +bool Field_newdate::send(Protocol *protocol) { MYSQL_TIME tm; Field_newdate::get_date(&tm, date_mode_t(0)); @@ -6772,7 +6813,7 @@ Field_datetime::conversion_depends_on_sql_mode(THD *thd, Item *expr) const } -bool Field_datetime0::send_binary(Protocol *protocol) +bool Field_datetime0::send(Protocol *protocol) { MYSQL_TIME tm; Field_datetime0::get_date(&tm, date_mode_t(0)); @@ -6900,7 +6941,7 @@ void Field_datetime_hires::store_TIME(const MYSQL_TIME *ltime) store_bigendian(packed, ptr, Field_datetime_hires::pack_length()); } -bool Field_datetime_with_dec::send_binary(Protocol *protocol) +bool Field_datetime_with_dec::send(Protocol *protocol) { MYSQL_TIME ltime; get_date(<ime, date_mode_t(0)); @@ -7109,6 +7150,23 @@ void Field_longstr::make_send_field(Send_field *field) } } + +/* + An optimized version that uses less stack than Field::send(). +*/ +bool Field_longstr::send(Protocol *protocol) +{ + String tmp; + val_str(&tmp, &tmp); + /* + Ensure this function is only used with classes that do not allocate + memory in val_str() + */ + DBUG_ASSERT(tmp.alloced_length() == 0); + return protocol->store(tmp.ptr(), tmp.length(), tmp.charset()); +} + + /* Copy a string and fill with space */ int Field_string::store(const char *from, size_t length,CHARSET_INFO *cs) @@ -7698,6 +7756,17 @@ my_decimal *Field_varstring::val_decimal(my_decimal *decimal_value) } +/* + An optimized version that uses less stack and less temporary + variable initialization than Field_longstr::send() +*/ +bool Field_varstring::send(Protocol *protocol) +{ + return protocol->store((const char *) get_data(), get_length(), + field_charset()); +} + + #ifdef HAVE_valgrind void Field_varstring::mark_unused_memory_as_defined() { diff --git a/sql/field.h b/sql/field.h index 0f531564116..2c73fed708b 100644 --- a/sql/field.h +++ b/sql/field.h @@ -37,6 +37,7 @@ class Send_field; class Copy_field; class Protocol; +class Protocol_text; class Create_field; class Relay_log_info; class Field; @@ -1576,7 +1577,7 @@ public: ptr= old_ptr; return str; } - virtual bool send_binary(Protocol *protocol); + virtual bool send(Protocol *protocol); virtual uchar *pack(uchar *to, const uchar *from, uint max_length); /** @@ -2005,6 +2006,9 @@ protected: return (flags & UNSIGNED_FLAG) ? Binlog_type_info::SIGN_UNSIGNED : Binlog_type_info::SIGN_SIGNED; } + bool send_numeric_zerofill_str(Protocol_text *protocol, + protocol_send_type_t send_type); + public: const uint8 dec; bool zerofill,unsigned_flag; // Purify cannot handle bit fields @@ -2194,6 +2198,7 @@ public: int store_decimal(const my_decimal *d) override; uint32 max_data_length() const override; void make_send_field(Send_field *) override; + bool send(Protocol *protocol) override; bool is_varchar_and_in_write_set() const override { @@ -2520,7 +2525,7 @@ public: double val_real() override; longlong val_int() override; String *val_str(String *, String *) override; - bool send_binary(Protocol *protocol) override; + bool send(Protocol *protocol) override; int cmp(const uchar *,const uchar *) const override; void sort_string(uchar *buff,uint length) override; uint32 pack_length() const override { return 1; } @@ -2583,7 +2588,7 @@ public: double val_real() override; longlong val_int() override; String *val_str(String *, String *) override; - bool send_binary(Protocol *protocol) override; + bool send(Protocol *protocol) override; int cmp(const uchar *,const uchar *) const override; void sort_string(uchar *buff,uint length) override; uint32 pack_length() const override { return 2; } @@ -2630,7 +2635,7 @@ public: double val_real() override; longlong val_int() override; String *val_str(String *, String *) override; - bool send_binary(Protocol *protocol) override; + bool send(Protocol *protocol) override; int cmp(const uchar *,const uchar *) const override; void sort_string(uchar *buff,uint length) override; uint32 pack_length() const override { return 3; } @@ -2681,7 +2686,7 @@ public: int reset() override { ptr[0]=ptr[1]=ptr[2]=ptr[3]=0; return 0; } double val_real() override; longlong val_int() override; - bool send_binary(Protocol *protocol) override; + bool send(Protocol *protocol) override; String *val_str(String *, String *) override; int cmp(const uchar *,const uchar *) const override; void sort_string(uchar *buff,uint length) override; @@ -2743,7 +2748,7 @@ public: double val_real() override; longlong val_int() override; String *val_str(String *, String *) override; - bool send_binary(Protocol *protocol) override; + bool send(Protocol *protocol) override; int cmp(const uchar *,const uchar *) const override; void sort_string(uchar *buff,uint length) override; uint32 pack_length() const override { return 8; } @@ -2843,7 +2848,7 @@ public: double val_real() override; longlong val_int() override; String *val_str(String *, String *) override; - bool send_binary(Protocol *protocol) override; + bool send(Protocol *protocol) override; int cmp(const uchar *,const uchar *) const override; void sort_string(uchar *buff, uint length) override; uint32 pack_length() const override { return sizeof(float); } @@ -2907,7 +2912,7 @@ public: longlong val_int() override final { return val_int_from_real(false); } ulonglong val_uint() override final { return (ulonglong) val_int_from_real(true); } String *val_str(String *, String *) override final; - bool send_binary(Protocol *protocol) override final; + bool send(Protocol *protocol) override; int cmp(const uchar *,const uchar *) const override final; void sort_string(uchar *buff, uint length) override final; uint32 pack_length() const override final { return sizeof(double); } @@ -3210,7 +3215,7 @@ public: { return (double) Field_timestamp0::val_int(); } - bool send_binary(Protocol *protocol) override; + bool send(Protocol *protocol) override; int cmp(const uchar *,const uchar *) const override; void sort_string(uchar *buff,uint length) override; uint32 pack_length() const override { return 4; } @@ -3265,7 +3270,7 @@ public: DBUG_ASSERT(length == pack_length()); memcpy(to, ptr, length); } - bool send_binary(Protocol *protocol) override; + bool send(Protocol *protocol) override; double val_real() override; my_decimal* val_decimal(my_decimal*) override; int set_time() override; @@ -3403,7 +3408,7 @@ public: longlong val_int() override; String *val_str(String *, String *) override; bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate) override; - bool send_binary(Protocol *protocol) override; + bool send(Protocol *protocol) override; Information_schema_numeric_attributes information_schema_numeric_attributes() const override { @@ -3462,7 +3467,7 @@ public: double val_real() override; longlong val_int() override; String *val_str(String *, String *) override; - bool send_binary(Protocol *protocol) override; + bool send(Protocol *protocol) override; int cmp(const uchar *,const uchar *) const override; void sort_string(uchar *buff,uint length) override; uint32 pack_length() const override { return 4; } @@ -3501,7 +3506,7 @@ public: double val_real() override; longlong val_int() override; String *val_str(String *, String *) override; - bool send_binary(Protocol *protocol) override; + bool send(Protocol *protocol) override; int cmp(const uchar *,const uchar *) const override; void sort_string(uchar *buff,uint length) override; uint32 pack_length() const override { return 3; } @@ -3561,7 +3566,7 @@ public: int store(longlong nr, bool unsigned_val) override; int store_decimal(const my_decimal *) override; String *val_str(String *, String *) override; - bool send_binary(Protocol *protocol) override; + bool send(Protocol *protocol) override; void set_curdays(THD *thd); Field *new_key_field(MEM_ROOT *root, TABLE *new_table, uchar *new_ptr, uint32 length, @@ -3775,7 +3780,7 @@ public: } longlong val_int() override; String *val_str(String *, String *) override; - bool send_binary(Protocol *protocol) override; + bool send(Protocol *protocol) override; int cmp(const uchar *,const uchar *) const override; void sort_string(uchar *buff,uint length) override; uint32 pack_length() const override { return 8; } @@ -3815,7 +3820,7 @@ public: uint decimals() const override final { return dec; } enum ha_base_keytype key_type() const override final { return HA_KEYTYPE_BINARY; } void make_send_field(Send_field *field) override final; - bool send_binary(Protocol *protocol) override final; + bool send(Protocol *protocol) override final; uchar *pack(uchar *to, const uchar *from, uint max_length) override final { return Field::pack(to, from, max_length); } const uchar *unpack(uchar* to, const uchar *from, const uchar *from_end, @@ -4153,6 +4158,7 @@ public: longlong val_int() override; String *val_str(String *, String *) override; my_decimal *val_decimal(my_decimal *) override; + bool send(Protocol *protocol) override; int cmp(const uchar *a,const uchar *b) const override; int cmp_prefix(const uchar *a, const uchar *b, size_t prefix_len) const override; @@ -4217,6 +4223,15 @@ private: double val_real() override; longlong val_int() override; uint size_of() const override { return sizeof *this; } + /* + We use the default Field::send() implementation, + because the derived optimized version (from Field_longstr) + is not suitable for compressed fields. + */ + bool send(Protocol *protocol) override + { + return Field::send(protocol); + } enum_field_types binlog_type() const override { return MYSQL_TYPE_VARCHAR_COMPRESSED; } void sql_type(String &str) const override @@ -4614,6 +4629,15 @@ private: String *val_str(String *, String *) override; double val_real() override; longlong val_int() override; + /* + We use the default Field::send() implementation, + because the derived optimized version (from Field_longstr) + is not suitable for compressed fields. + */ + bool send(Protocol *protocol) override + { + return Field::send(protocol); + } uint size_of() const override { return sizeof *this; } enum_field_types binlog_type() const override { return MYSQL_TYPE_BLOB_COMPRESSED; } diff --git a/sql/protocol.cc b/sql/protocol.cc index 189cdfca9af..a446e3b656f 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -1232,6 +1232,22 @@ bool Protocol_text::store_str(const char *from, size_t length, } +bool Protocol_text::store_numeric_zerofill_str(const char *from, + size_t length, + protocol_send_type_t send_type) +{ +#ifndef DBUG_OFF + DBUG_PRINT("info", + ("Protocol_text::store_numeric_zerofill_str field %u : %.*b", + field_pos, (int) length, (length == 0 ? "" : from))); + DBUG_ASSERT(field_handlers == 0 || field_pos < field_count); + DBUG_ASSERT(valid_handler(field_pos, send_type)); + field_pos++; +#endif + return store_numeric_string_aux(from, length); +} + + bool Protocol_text::store_tiny(longlong from) { #ifndef DBUG_OFF @@ -1321,12 +1337,6 @@ bool Protocol_text::store(Field *field) { if (field->is_null()) return store_null(); -#ifndef DBUG_OFF - field_pos++; -#endif - char buff[MAX_FIELD_WIDTH]; - String str(buff,sizeof(buff), &my_charset_bin); - CHARSET_INFO *tocs= this->thd->variables.character_set_results; #ifdef DBUG_ASSERT_EXISTS TABLE *table= field->table; my_bitmap_map *old_map= 0; @@ -1334,13 +1344,14 @@ bool Protocol_text::store(Field *field) old_map= dbug_tmp_use_all_columns(table, table->read_set); #endif - field->val_str(&str); + bool rc= field->send(this); + #ifdef DBUG_ASSERT_EXISTS if (old_map) dbug_tmp_restore_column_map(table->read_set, old_map); #endif - return store_string_aux(str.ptr(), str.length(), str.charset(), tocs); + return rc; } @@ -1553,12 +1564,12 @@ bool Protocol_binary::store_double(double from, uint32 decimals) bool Protocol_binary::store(Field *field) { /* - We should not increment field_pos here as send_binary() will call another + We should not increment field_pos here as send() will call another protocol function to do this for us */ if (field->is_null()) return store_null(); - return field->send_binary(this); + return field->send(this); } diff --git a/sql/protocol.h b/sql/protocol.h index da01b6244e1..72cbc672cde 100644 --- a/sql/protocol.h +++ b/sql/protocol.h @@ -219,6 +219,10 @@ public: bool store(Field *field) override; bool send_out_parameters(List *sp_params) override; + + bool store_numeric_zerofill_str(const char *from, size_t length, + protocol_send_type_t send_type); + #ifdef EMBEDDED_LIBRARY void remove_last_row() override; #endif diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 5d034b80b6d..ade531339bb 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -5390,7 +5390,7 @@ bool Protocol_local::store(Field *field) { if (field->is_null()) return store_null(); - return field->send_binary(this); + return field->send(this); } From 48cbb2c021a6bee4992ce6df8764a55e7d876b58 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Fri, 14 Aug 2020 11:04:39 +0400 Subject: [PATCH 24/70] MDEV-23478 Improve Protocol performance for numeric data - version 2 The previous commit was erroneously marked as MDEV-23162. The correct issue is MDEV-23478. From 1bf77cde5c62166c0f1652c2a1764e05ce76edb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Fri, 14 Aug 2020 11:32:46 +0300 Subject: [PATCH 25/70] MDEV-23162: Fix clang -Winconsistent-missing-override --- sql/protocol.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sql/protocol.h b/sql/protocol.h index 72cbc672cde..4b80b34b96b 100644 --- a/sql/protocol.h +++ b/sql/protocol.h @@ -258,7 +258,7 @@ public: bool store_longlong(longlong from, bool unsigned_flag) override; bool store_decimal(const my_decimal *) override; bool store_str(const char *from, size_t length, - CHARSET_INFO *fromcs, CHARSET_INFO *tocs); + CHARSET_INFO *fromcs, CHARSET_INFO *tocs) override; bool store(MYSQL_TIME *time, int decimals) override; bool store_date(MYSQL_TIME *time) override; bool store_time(MYSQL_TIME *time, int decimals) override; @@ -306,7 +306,7 @@ public: bool store_long(longlong) override { return false; } bool store_longlong(longlong, bool) override { return false; } bool store_decimal(const my_decimal *) override { return false; } - bool store_str(const char *, size_t, CHARSET_INFO *, CHARSET_INFO *) + bool store_str(const char *, size_t, CHARSET_INFO *, CHARSET_INFO *) override { return false; } From eab219d594fba26c3f8d9793e377c5ab7de61678 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Mon, 10 Aug 2020 11:44:42 +0300 Subject: [PATCH 26/70] MDEV-22543 : Galera SST donation fails, FLUSH TABLES WITH READ LOCK times out During SST we need to let FTWRL to use normal timeout method even when client is disconnected. --- mysql-test/suite/galera/r/mdev-22543.result | 19 +++++++ mysql-test/suite/galera/t/mdev-22543.test | 58 +++++++++++++++++++++ sql/mdl.cc | 27 +++++++--- sql/wsrep_sst.cc | 14 ++++- sql/wsrep_sst.h | 2 + 5 files changed, 111 insertions(+), 9 deletions(-) create mode 100644 mysql-test/suite/galera/r/mdev-22543.result create mode 100644 mysql-test/suite/galera/t/mdev-22543.test diff --git a/mysql-test/suite/galera/r/mdev-22543.result b/mysql-test/suite/galera/r/mdev-22543.result new file mode 100644 index 00000000000..9386b7405d4 --- /dev/null +++ b/mysql-test/suite/galera/r/mdev-22543.result @@ -0,0 +1,19 @@ +connection node_2; +connection node_1; +connection node_1; +connection node_2; +connection node_1; +CREATE TABLE t1 (f1 INT PRIMARY KEY, f2 INT); +INSERT INTO t1 VALUES (1, 1); +SET DEBUG_SYNC = "before_lock_tables_takes_lock SIGNAL sync_point_reached WAIT_FOR sync_point_continue"; +UPDATE t1 SET f2 = 2 WHERE f1 = 1; +connection node_1_ctrl; +SET DEBUG_SYNC = "now WAIT_FOR sync_point_reached"; +connection node_2; +connection node_1_ctrl; +SET DEBUG_SYNC = "now SIGNAL sync_point_continue"; +connection node_1; +SET DEBUG_SYNC = "RESET"; +connection node_2; +connection node_1; +DROP TABLE t1; diff --git a/mysql-test/suite/galera/t/mdev-22543.test b/mysql-test/suite/galera/t/mdev-22543.test new file mode 100644 index 00000000000..53662e36942 --- /dev/null +++ b/mysql-test/suite/galera/t/mdev-22543.test @@ -0,0 +1,58 @@ +# The test verifies that the FLUSH TABLES WITH READ LOCK does not +# time out if it needs to wait for another MDL lock for short duration +# during SST donation. + +--source include/galera_cluster.inc +--source include/have_debug.inc +--source include/have_debug_sync.inc + +--let $node_1 = node_1 +--let $node_2 = node_2 +--source include/auto_increment_offset_save.inc + +--let $galera_connection_name = node_1_ctrl +--let $galera_server_number = 1 +--source include/galera_connect.inc + +# +# Run UPDATE on node_1 and make it block before table locks are taken. +# This should block FTWRL. +# +--connection node_1 +CREATE TABLE t1 (f1 INT PRIMARY KEY, f2 INT); +INSERT INTO t1 VALUES (1, 1); +SET DEBUG_SYNC = "before_lock_tables_takes_lock SIGNAL sync_point_reached WAIT_FOR sync_point_continue"; +--send UPDATE t1 SET f2 = 2 WHERE f1 = 1 + +--connection node_1_ctrl +SET DEBUG_SYNC = "now WAIT_FOR sync_point_reached"; + +# +# Restart node_2, force SST. +# +--connection node_2 +--source include/shutdown_mysqld.inc +--remove_file $MYSQLTEST_VARDIR/mysqld.2/data/grastate.dat +# Restart without waiting. The UPDATE should block FTWRL on node_1, +# so the SST cannot be completed and node_2 cannot join before +# UPDATE connection is signalled to continue. +--exec echo "restart:$start_mysqld_params" > $_expect_file_name +# If the bug is present, FTWRL times out on node_1 in couple of +# seconds and node_2 fails to join. +--sleep 10 + +--connection node_1_ctrl +SET DEBUG_SYNC = "now SIGNAL sync_point_continue"; + +--connection node_1 +--reap +SET DEBUG_SYNC = "RESET"; + +--connection node_2 +--enable_reconnect +--source include/wait_until_connected_again.inc + +--connection node_1 +DROP TABLE t1; + +--source include/auto_increment_offset_restore.inc diff --git a/sql/mdl.cc b/sql/mdl.cc index 4772dc017f9..240ef97b1c4 100644 --- a/sql/mdl.cc +++ b/sql/mdl.cc @@ -25,6 +25,9 @@ #include #include #include +#ifdef WITH_WSREP +#include "wsrep_sst.h" +#endif #include #include #include @@ -2332,18 +2335,26 @@ MDL_context::acquire_lock(MDL_request *mdl_request, double lock_wait_timeout) wait_status= m_wait.timed_wait(m_owner, &abs_shortwait, FALSE, mdl_request->key.get_wait_state_name()); + THD* thd= m_owner->get_thd(); + if (wait_status != MDL_wait::EMPTY) break; /* Check if the client is gone while we were waiting. */ - if (! thd_is_connected(m_owner->get_thd())) + if (! thd_is_connected(thd)) { - /* - * The client is disconnected. Don't wait forever: - * assume it's the same as a wait timeout, this - * ensures all error handling is correct. - */ - wait_status= MDL_wait::TIMEOUT; - break; +#if defined(WITH_WSREP) && !defined(EMBEDDED_LIBRARY) + // During SST client might not be connected + if (!wsrep_is_sst_progress()) +#endif + { + /* + * The client is disconnected. Don't wait forever: + * assume it's the same as a wait timeout, this + * ensures all error handling is correct. + */ + wait_status= MDL_wait::TIMEOUT; + break; + } } mysql_prlock_wrlock(&lock->m_rwlock); diff --git a/sql/wsrep_sst.cc b/sql/wsrep_sst.cc index 93b7bc74489..444fb98c4b9 100644 --- a/sql/wsrep_sst.cc +++ b/sql/wsrep_sst.cc @@ -54,6 +54,7 @@ my_bool wsrep_sst_donor_rejects_queries= FALSE; bool sst_joiner_completed = false; bool sst_donor_completed = false; +bool sst_needed = false; struct sst_thread_arg { @@ -307,6 +308,7 @@ bool wsrep_before_SE() && strcmp (wsrep_sst_method, WSREP_SST_MYSQLDUMP)); } +static bool sst_in_progress = false; // Signal end of SST static void wsrep_sst_complete (THD* thd, int const rcode) @@ -1625,7 +1627,10 @@ static void* sst_donor_thread (void* a) char out_buf[out_len]; wsrep_uuid_t ret_uuid= WSREP_UUID_UNDEFINED; - wsrep_seqno_t ret_seqno= WSREP_SEQNO_UNDEFINED; // seqno of complete SST + // seqno of complete SST + wsrep_seqno_t ret_seqno= WSREP_SEQNO_UNDEFINED; + // SST is now in progress + sst_in_progress= true; wsp::thd thd(FALSE); // we turn off wsrep_on for this THD so that it can // operate with wsrep_ready == OFF @@ -1731,6 +1736,8 @@ wait_signal: proc.wait(); wsrep_donor_monitor_end(); + sst_in_progress= false; + return NULL; } @@ -1884,3 +1891,8 @@ int wsrep_sst_donate(const std::string& msg, return (ret >= 0 ? 0 : 1); } + +bool wsrep_is_sst_progress() +{ + return (sst_in_progress); +} diff --git a/sql/wsrep_sst.h b/sql/wsrep_sst.h index 2389db4abe7..50f2d362c5a 100644 --- a/sql/wsrep_sst.h +++ b/sql/wsrep_sst.h @@ -77,6 +77,7 @@ extern void wsrep_SE_init_grab(); /*! grab init critical section */ extern void wsrep_SE_init_wait(); /*! wait for SE init to complete */ extern void wsrep_SE_init_done(); /*! signal that SE init is complte */ extern void wsrep_SE_initialized(); /*! mark SE initialization complete */ +extern bool wsrep_is_sst_progress(); /** Return a string containing the state transfer request string. @@ -102,5 +103,6 @@ int wsrep_sst_donate(const std::string& request, #define wsrep_SE_init_grab() do { } while(0) #define wsrep_SE_init_done() do { } while(0) #define wsrep_sst_continue() (0) +#define wsrep_is_sst_progress() (0) #endif /* WSREP_SST_H */ From 16d8d18907f3e9775ac6e89c03d1f6259b77ec14 Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Fri, 14 Aug 2020 14:43:26 +0300 Subject: [PATCH 27/70] Basic Optimizer Trace support for table condition pushdown Print the condition being pushed. --- sql/sql_select.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 5dbe01c5044..a4ef786776b 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -11587,11 +11587,16 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) HA_CAN_TABLE_CONDITION_PUSHDOWN) && !first_inner_tab) { + Json_writer_object wrap(thd); + Json_writer_object trace_cp(thd, "table_condition_pushdown"); + trace_cp.add_table_name(tab->table); + COND *push_cond= make_cond_for_table(thd, tmp_cond, current_map, current_map, -1, FALSE, FALSE); if (push_cond) { + trace_cp.add("push_cond", push_cond); /* Push condition to handler */ if (!tab->table->file->cond_push(push_cond)) tab->table->file->pushed_cond= push_cond; From 68cba09173a49185c02d5b57a5a241f102257fea Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Fri, 14 Aug 2020 14:45:36 +0300 Subject: [PATCH 28/70] Add QT_ITEM_IDENT_DISABLE_DB_TABLE_NAMES flag for Item::print It allows to skip db and table name when printing table column references. --- sql/item.cc | 6 ++++++ sql/mysqld.h | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/sql/item.cc b/sql/item.cc index 6cd8407e4dd..b164b945abf 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -3193,6 +3193,12 @@ void Item_ident::print(String *str, enum_query_type query_type) use_db_name= use_table_name= false; } + if ((query_type & QT_ITEM_IDENT_DISABLE_DB_TABLE_NAMES)) + { + // Don't print db or table name irrespective of any other settings. + use_db_name= use_table_name= false; + } + if (!field_name.str || !field_name.str[0]) { append_identifier(thd, str, STRING_WITH_LEN("tmp_field")); diff --git a/sql/mysqld.h b/sql/mysqld.h index db8d9b4b1aa..e8dd5706e80 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -871,6 +871,12 @@ enum enum_query_type QT_ITEM_SUBSELECT_ID_ONLY, QT_SHOW_SELECT_NUMBER= (1<<10), + + /// Do not print database name or table name in the identifiers (even if + /// this means the printout will be ambigous). It is assumed that the caller + /// passing this flag knows what they are doing. + QT_ITEM_IDENT_DISABLE_DB_TABLE_NAMES= (1 <<11), + /// This is used for EXPLAIN EXTENDED extra warnings / Be more detailed /// Be more detailed than QT_EXPLAIN. /// Perhaps we should eventually include QT_ITEM_IDENT_SKIP_CURRENT_DATABASE From b01c426146710f1c24ab75e2ffcd953feac08882 Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Fri, 14 Aug 2020 21:04:25 +0400 Subject: [PATCH 29/70] MDEV-19275 Provide SQL service to plugins. Protocol_local fixed so it can be used now. Some Protocol:: methods made virtual so they can adapt. as well as net_ok and net_send_error functions. execute_sql_string function is exported to the plugins. To be changed with the mysql_use_result. --- libmysqld/emb_qcache.cc | 4 +- libmysqld/emb_qcache.h | 1 - libmysqld/lib_sql.cc | 11 +- libmysqld/libmysql.c | 5 - sql-common/client.c | 6 + sql/mysqld.cc | 2 +- sql/protocol.cc | 39 +- sql/protocol.h | 24 +- sql/sql_audit.h | 29 +- sql/sql_class.cc | 55 +++ sql/sql_class.h | 7 + sql/sql_connect.cc | 2 +- sql/sql_parse.cc | 2 +- sql/sql_prepare.cc | 1040 ++++++++++++++++++++++++++------------- sql/sql_prepare.h | 5 +- 15 files changed, 816 insertions(+), 416 deletions(-) diff --git a/libmysqld/emb_qcache.cc b/libmysqld/emb_qcache.cc index 33de60e92ac..31f4cf111ee 100644 --- a/libmysqld/emb_qcache.cc +++ b/libmysqld/emb_qcache.cc @@ -491,8 +491,8 @@ int emb_load_querycache_result(THD *thd, Querycache_stream *src) *prev_row= NULL; data->embedded_info->prev_ptr= prev_row; return_ok: - net_send_eof(thd, thd->server_status, - thd->get_stmt_da()->current_statement_warn_count()); + thd->protocol->net_send_eof(thd, thd->server_status, + thd->get_stmt_da()->current_statement_warn_count()); DBUG_RETURN(0); err: DBUG_RETURN(1); diff --git a/libmysqld/emb_qcache.h b/libmysqld/emb_qcache.h index c4268752f9a..e3b6339ba3a 100644 --- a/libmysqld/emb_qcache.h +++ b/libmysqld/emb_qcache.h @@ -81,4 +81,3 @@ public: uint emb_count_querycache_size(THD *thd); int emb_load_querycache_result(THD *thd, Querycache_stream *src); void emb_store_querycache_result(Querycache_stream *dst, THD* thd); -bool net_send_eof(THD *thd, uint server_status, uint total_warn_count); diff --git a/libmysqld/lib_sql.cc b/libmysqld/lib_sql.cc index b93cd85bfe8..3930e14829d 100644 --- a/libmysqld/lib_sql.cc +++ b/libmysqld/lib_sql.cc @@ -1139,7 +1139,7 @@ bool Protocol::send_result_set_metadata(List *list, uint flags) for (uint pos= 0 ; (item= it++); pos++) { - if (prot.store_field_metadata(thd, item, pos)) + if (prot.store_item_metadata(thd, item, pos)) goto err; } @@ -1254,8 +1254,7 @@ bool Protocol_binary::write() @retval FALSE Success */ -bool -net_send_ok(THD *thd, +bool Protocol::net_send_ok(THD *thd, uint server_status, uint statement_warn_count, ulonglong affected_rows, ulonglong id, const char *message, bool, bool) @@ -1290,7 +1289,7 @@ net_send_ok(THD *thd, */ bool -net_send_eof(THD *thd, uint server_status, uint statement_warn_count) +Protocol::net_send_eof(THD *thd, uint server_status, uint statement_warn_count) { bool error= write_eof_packet(thd, server_status, statement_warn_count); thd->cur_data= 0; @@ -1298,8 +1297,8 @@ net_send_eof(THD *thd, uint server_status, uint statement_warn_count) } -bool net_send_error_packet(THD *thd, uint sql_errno, const char *err, - const char *sqlstate) +bool Protocol::net_send_error_packet(THD *thd, uint sql_errno, const char *err, + const char *sqlstate) { uint error; char converted_err[MYSQL_ERRMSG_SIZE]; diff --git a/libmysqld/libmysql.c b/libmysqld/libmysql.c index e269840d674..9a17b9b4f09 100644 --- a/libmysqld/libmysql.c +++ b/libmysqld/libmysql.c @@ -1087,11 +1087,6 @@ unsigned int STDCALL mysql_field_count(MYSQL *mysql) return mysql->field_count; } -my_ulonglong STDCALL mysql_affected_rows(MYSQL *mysql) -{ - return mysql->affected_rows; -} - my_ulonglong STDCALL mysql_insert_id(MYSQL *mysql) { return mysql->insert_id; diff --git a/sql-common/client.c b/sql-common/client.c index c12b3ef5c0a..ecc3b821395 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -3735,6 +3735,12 @@ static MYSQL_RES * cli_use_result(MYSQL *mysql) } +my_ulonglong STDCALL mysql_affected_rows(MYSQL *mysql) +{ + return mysql->affected_rows; +} + + /************************************************************************** Return next row of the query results **************************************************************************/ diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 1fadc7ebaac..5a4ef3d3ad2 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -2553,7 +2553,7 @@ void close_connection(THD *thd, uint sql_errno) if (sql_errno) { - net_send_error(thd, sql_errno, ER_DEFAULT(sql_errno), NULL); + thd->protocol->net_send_error(thd, sql_errno, ER_DEFAULT(sql_errno), NULL); thd->print_aborted_warning(lvl, ER_DEFAULT(sql_errno)); } else diff --git a/sql/protocol.cc b/sql/protocol.cc index a446e3b656f..65066111238 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -32,13 +32,6 @@ #include static const unsigned int PACKET_BUFFER_EXTRA_ALLOC= 1024; -/* Declared non-static only because of the embedded library. */ -bool net_send_error_packet(THD *, uint, const char *, const char *); -/* Declared non-static only because of the embedded library. */ -bool net_send_ok(THD *, uint, uint, ulonglong, ulonglong, const char *, - bool, bool); -/* Declared non-static only because of the embedded library. */ -bool net_send_eof(THD *thd, uint server_status, uint statement_warn_count); #ifndef EMBEDDED_LIBRARY static bool write_eof_packet(THD *, NET *, uint, uint); #endif @@ -152,11 +145,11 @@ bool Protocol_binary::net_store_data_cs(const uchar *from, size_t length, @retval TRUE An error occurred and the message wasn't sent properly */ -bool net_send_error(THD *thd, uint sql_errno, const char *err, - const char* sqlstate) +bool Protocol::net_send_error(THD *thd, uint sql_errno, const char *err, + const char* sqlstate) { bool error; - DBUG_ENTER("net_send_error"); + DBUG_ENTER("Protocol::net_send_error"); DBUG_ASSERT(!thd->spcont); DBUG_ASSERT(sql_errno); @@ -214,11 +207,11 @@ bool net_send_error(THD *thd, uint sql_errno, const char *err, #ifndef EMBEDDED_LIBRARY bool -net_send_ok(THD *thd, - uint server_status, uint statement_warn_count, - ulonglong affected_rows, ulonglong id, const char *message, - bool is_eof, - bool skip_flush) +Protocol::net_send_ok(THD *thd, + uint server_status, uint statement_warn_count, + ulonglong affected_rows, ulonglong id, + const char *message, bool is_eof, + bool skip_flush) { NET *net= &thd->net; StringBuffer store; @@ -226,7 +219,7 @@ net_send_ok(THD *thd, bool state_changed= false; bool error= FALSE; - DBUG_ENTER("net_send_ok"); + DBUG_ENTER("Protocol::net_send_ok"); if (! net->vio) // hack for re-parsing queries { @@ -329,11 +322,11 @@ static uchar eof_buff[1]= { (uchar) 254 }; /* Marker for end of fields */ */ bool -net_send_eof(THD *thd, uint server_status, uint statement_warn_count) +Protocol::net_send_eof(THD *thd, uint server_status, uint statement_warn_count) { NET *net= &thd->net; bool error= FALSE; - DBUG_ENTER("net_send_eof"); + DBUG_ENTER("Protocol::net_send_eof"); /* Check if client understand new format packets (OK instead of EOF) @@ -420,8 +413,8 @@ static bool write_eof_packet(THD *thd, NET *net, @retval TRUE An error occurred and the messages wasn't sent properly */ -bool net_send_error_packet(THD *thd, uint sql_errno, const char *err, - const char* sqlstate) +bool Protocol::net_send_error_packet(THD *thd, uint sql_errno, const char *err, + const char* sqlstate) { NET *net= &thd->net; @@ -434,7 +427,7 @@ bool net_send_error_packet(THD *thd, uint sql_errno, const char *err, char buff[2+1+SQLSTATE_LENGTH+MYSQL_ERRMSG_SIZE], *pos; my_bool ret; uint8 save_compress; - DBUG_ENTER("send_error_packet"); + DBUG_ENTER("Protocol::send_error_packet"); if (net->vio == 0) { @@ -963,7 +956,7 @@ bool Protocol::send_result_set_metadata(List *list, uint flags) for (uint pos= 0; (item=it++); pos++) { prot.prepare_for_resend(); - if (prot.store_field_metadata(thd, item, pos)) + if (prot.store_item_metadata(thd, item, pos)) goto err; if (prot.write()) DBUG_RETURN(1); @@ -1043,7 +1036,7 @@ bool Protocol::write() #endif /* EMBEDDED_LIBRARY */ -bool Protocol_text::store_field_metadata(THD *thd, Item *item, uint pos) +bool Protocol_text::store_item_metadata(THD *thd, Item *item, uint pos) { Send_field field(thd, item); return store_field_metadata(thd, field, item->charset_for_protocol(), pos); diff --git a/sql/protocol.h b/sql/protocol.h index 4b80b34b96b..eb11304a4d5 100644 --- a/sql/protocol.h +++ b/sql/protocol.h @@ -50,14 +50,13 @@ protected: } #endif uint field_count; -#ifndef EMBEDDED_LIBRARY - bool net_store_data(const uchar *from, size_t length); - bool net_store_data_cs(const uchar *from, size_t length, - CHARSET_INFO *fromcs, CHARSET_INFO *tocs); -#else virtual bool net_store_data(const uchar *from, size_t length); virtual bool net_store_data_cs(const uchar *from, size_t length, CHARSET_INFO *fromcs, CHARSET_INFO *tocs); + virtual bool net_send_ok(THD *, uint, uint, ulonglong, ulonglong, const char *, + bool, bool); + virtual bool net_send_error_packet(THD *, uint, const char *, const char *); +#ifdef EMBEDDED_LIBRARY char **next_field; MYSQL_FIELD *next_mysql_field; MEM_ROOT *alloc; @@ -181,6 +180,9 @@ public: }; virtual enum enum_protocol_type type()= 0; + virtual bool net_send_eof(THD *thd, uint server_status, uint statement_warn_count); + bool net_send_error(THD *thd, uint sql_errno, const char *err, + const char* sqlstate); void end_statement(); friend int send_answer_1(Protocol *protocol, String *s1, String *s2, @@ -191,7 +193,7 @@ public: /** Class used for the old (MySQL 4.0 protocol). */ -class Protocol_text final :public Protocol +class Protocol_text :public Protocol { StringBuffer buffer; bool store_numeric_string_aux(const char *from, size_t length); @@ -226,10 +228,10 @@ public: #ifdef EMBEDDED_LIBRARY void remove_last_row() override; #endif - bool store_field_metadata(const THD *thd, const Send_field &field, - CHARSET_INFO *charset_for_protocol, - uint pos); - bool store_field_metadata(THD *thd, Item *item, uint pos); + virtual bool store_field_metadata(const THD *thd, const Send_field &field, + CHARSET_INFO *charset_for_protocol, + uint pos); + bool store_item_metadata(THD *thd, Item *item, uint pos); bool store_field_metadata_for_list_fields(const THD *thd, Field *field, const TABLE_LIST *table_list, uint pos); @@ -321,8 +323,6 @@ public: void send_warning(THD *thd, uint sql_errno, const char *err=0); -bool net_send_error(THD *thd, uint sql_errno, const char *err, - const char* sqlstate); void net_send_progress_packet(THD *thd); uchar *net_store_data(uchar *to,const uchar *from, size_t length); uchar *net_store_data(uchar *to,int32 from); diff --git a/sql/sql_audit.h b/sql/sql_audit.h index 97317203e34..40276c86a78 100644 --- a/sql/sql_audit.h +++ b/sql/sql_audit.h @@ -254,35 +254,36 @@ void mysql_audit_notify_connection_disconnect(THD *thd, int errcode) } static inline -void mysql_audit_notify_connection_change_user(THD *thd) +void mysql_audit_notify_connection_change_user(THD *thd, + const Security_context *old_ctx) { if (mysql_audit_connection_enabled()) { - const Security_context *sctx= thd->security_ctx; mysql_event_connection event; event.event_subclass= MYSQL_AUDIT_CONNECTION_CHANGE_USER; event.status= thd->get_stmt_da()->is_error() ? thd->get_stmt_da()->sql_errno() : 0; event.thread_id= (unsigned long)thd->thread_id; - event.user= sctx->user; - event.user_length= safe_strlen_uint(sctx->user); - event.priv_user= sctx->priv_user; - event.priv_user_length= strlen_uint(sctx->priv_user); - event.external_user= sctx->external_user; - event.external_user_length= safe_strlen_uint(sctx->external_user); - event.proxy_user= sctx->proxy_user; - event.proxy_user_length= strlen_uint(sctx->proxy_user); - event.host= sctx->host; - event.host_length= safe_strlen_uint(sctx->host); - event.ip= sctx->ip; - event.ip_length= safe_strlen_uint(sctx->ip); + event.user= old_ctx->user; + event.user_length= safe_strlen_uint(old_ctx->user); + event.priv_user= old_ctx->priv_user; + event.priv_user_length= strlen_uint(old_ctx->priv_user); + event.external_user= old_ctx->external_user; + event.external_user_length= safe_strlen_uint(old_ctx->external_user); + event.proxy_user= old_ctx->proxy_user; + event.proxy_user_length= strlen_uint(old_ctx->proxy_user); + event.host= old_ctx->host; + event.host_length= safe_strlen_uint(old_ctx->host); + event.ip= old_ctx->ip; + event.ip_length= safe_strlen_uint(old_ctx->ip); event.database= thd->db; mysql_audit_notify(thd, MYSQL_AUDIT_CONNECTION_CLASS, &event); } } + static inline void mysql_audit_external_lock_ex(THD *thd, my_thread_id thread_id, const char *user, const char *host, const char *ip, query_id_t query_id, diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 702acb623ae..f4cbda5490c 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -348,6 +348,12 @@ void thd_clear_errors(THD *thd) } +extern "C" unsigned long long thd_query_id(const MYSQL_THD thd) +{ + return((unsigned long long)thd->query_id); +} + + /** Get thread attributes for connection threads @@ -4983,6 +4989,55 @@ extern "C" size_t thd_query_safe(MYSQL_THD thd, char *buf, size_t buflen) } +extern "C" const char *thd_user_name(MYSQL_THD thd) +{ + if (!thd->security_ctx) + return 0; + + return thd->security_ctx->user; +} + + +extern "C" const char *thd_client_host(MYSQL_THD thd) +{ + if (!thd->security_ctx) + return 0; + + return thd->security_ctx->host; +} + + +extern "C" const char *thd_client_ip(MYSQL_THD thd) +{ + if (!thd->security_ctx) + return 0; + + return thd->security_ctx->ip; +} + + +extern "C" LEX_CSTRING *thd_current_db(MYSQL_THD thd) +{ + return &thd->db; +} + + +extern "C" int thd_current_status(MYSQL_THD thd) +{ + Diagnostics_area *da= thd->get_stmt_da(); + if (!da) + return 0; + + return da->is_error() ? da->sql_errno() : 0; +} + + +extern "C" enum enum_server_command thd_current_command(MYSQL_THD thd) +{ + return thd->get_command(); +} + + extern "C" int thd_slave_thread(const MYSQL_THD thd) { return(thd->slave_thread); diff --git a/sql/sql_class.h b/sql/sql_class.h index 7e512048bce..6bc01119508 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -195,7 +195,14 @@ extern char empty_c_string[1]; extern MYSQL_PLUGIN_IMPORT const char **errmesg; extern "C" LEX_STRING * thd_query_string (MYSQL_THD thd); +extern "C" unsigned long long thd_query_id(const MYSQL_THD thd); extern "C" size_t thd_query_safe(MYSQL_THD thd, char *buf, size_t buflen); +extern "C" const char *thd_user_name(MYSQL_THD thd); +extern "C" const char *thd_client_host(MYSQL_THD thd); +extern "C" const char *thd_client_ip(MYSQL_THD thd); +extern "C" LEX_CSTRING *thd_current_db(MYSQL_THD thd); +extern "C" int thd_current_status(MYSQL_THD thd); +extern "C" enum enum_server_command thd_current_command(MYSQL_THD thd); /** @class CSET_STRING diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc index 83f4de1b5df..479a310542b 100644 --- a/sql/sql_connect.cc +++ b/sql/sql_connect.cc @@ -1494,7 +1494,7 @@ void CONNECT::close_with_error(uint sql_errno, if (thd) { if (sql_errno) - net_send_error(thd, sql_errno, message, NULL); + thd->protocol->net_send_error(thd, sql_errno, message, NULL); close_connection(thd, close_error); delete thd; set_current_thd(0); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 51109f128d0..c2b6fb02325 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1748,7 +1748,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, else auth_rc= acl_authenticate(thd, packet_length); - mysql_audit_notify_connection_change_user(thd); + mysql_audit_notify_connection_change_user(thd, &save_security_ctx); if (auth_rc) { /* Free user if allocated by acl_authenticate */ diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index ade531339bb..fee65ed4e22 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -243,61 +243,6 @@ private: class Ed_connection; -/** - Protocol_local: a helper class to intercept the result - of the data written to the network. -*/ - -class Protocol_local :public Protocol -{ -public: - Protocol_local(THD *thd, Ed_connection *ed_connection); - ~Protocol_local() { free_root(&m_rset_root, MYF(0)); } -protected: - virtual void prepare_for_resend(); - virtual bool write(); - virtual bool store_null(); - virtual bool store_tiny(longlong from); - virtual bool store_short(longlong from); - virtual bool store_long(longlong from); - virtual bool store_longlong(longlong from, bool unsigned_flag); - virtual bool store_decimal(const my_decimal *); - virtual bool store_str(const char *from, size_t length, - CHARSET_INFO *fromcs, CHARSET_INFO *tocs); - virtual bool store(MYSQL_TIME *time, int decimals); - virtual bool store_date(MYSQL_TIME *time); - virtual bool store_time(MYSQL_TIME *time, int decimals); - virtual bool store_float(float value, uint32 decimals); - virtual bool store_double(double value, uint32 decimals); - virtual bool store(Field *field); - - virtual bool send_result_set_metadata(List *list, uint flags); - virtual bool send_out_parameters(List *sp_params); -#ifdef EMBEDDED_LIBRARY - void remove_last_row(); -#endif - virtual enum enum_protocol_type type() { return PROTOCOL_LOCAL; }; - - virtual bool send_ok(uint server_status, uint statement_warn_count, - ulonglong affected_rows, ulonglong last_insert_id, - const char *message, bool skip_flush); - - virtual bool send_eof(uint server_status, uint statement_warn_count); - virtual bool send_error(uint sql_errno, const char *err_msg, const char* sqlstate); -private: - bool store_string(const char *str, size_t length, - CHARSET_INFO *src_cs, CHARSET_INFO *dst_cs); - - bool store_column(const void *data, size_t length); - void opt_add_row_to_rset(); -private: - Ed_connection *m_connection; - MEM_ROOT m_rset_root; - List *m_rset; - size_t m_column_count; - Ed_column *m_current_row; - Ed_column *m_current_column; -}; /****************************************************************************** Implementation @@ -3792,6 +3737,7 @@ Execute_sql_statement::execute_server_code(THD *thd) end: thd->lex->restore_set_statement_var(); + delete_explain_query(thd->lex); lex_end(thd->lex); return error; @@ -5035,12 +4981,12 @@ Ed_connection::free_old_result() */ bool -Ed_connection::execute_direct(LEX_STRING sql_text) +Ed_connection::execute_direct(Protocol *p, LEX_STRING sql_text) { Execute_sql_statement execute_sql_statement(sql_text); DBUG_PRINT("ed_query", ("%s", sql_text.str)); - return execute_direct(&execute_sql_statement); + return execute_direct(p, &execute_sql_statement); } @@ -5057,10 +5003,9 @@ Ed_connection::execute_direct(LEX_STRING sql_text) @param server_runnable A code fragment to execute. */ -bool Ed_connection::execute_direct(Server_runnable *server_runnable) +bool Ed_connection::execute_direct(Protocol *p, Server_runnable *server_runnable) { bool rc= FALSE; - Protocol_local protocol_local(m_thd, this); Prepared_statement stmt(m_thd); Protocol *save_protocol= m_thd->protocol; Diagnostics_area *save_diagnostics_area= m_thd->get_stmt_da(); @@ -5069,7 +5014,7 @@ bool Ed_connection::execute_direct(Server_runnable *server_runnable) free_old_result(); /* Delete all data from previous execution, if any */ - m_thd->protocol= &protocol_local; + m_thd->protocol= p; m_thd->set_stmt_da(&m_diagnostics_area); rc= stmt.execute_server_runnable(server_runnable); @@ -5156,340 +5101,741 @@ Ed_connection::store_result_set() return ed_result_set; } -/************************************************************************* -* Protocol_local -**************************************************************************/ - -Protocol_local::Protocol_local(THD *thd, Ed_connection *ed_connection) - :Protocol(thd), - m_connection(ed_connection), - m_rset(NULL), - m_column_count(0), - m_current_row(NULL), - m_current_column(NULL) -{ - clear_alloc_root(&m_rset_root); -} - -/** - Called between two result set rows. - - Prepare structures to fill result set rows. - Unfortunately, we can't return an error here. If memory allocation - fails, we'll have to return an error later. And so is done - in methods such as @sa store_column(). +/* + MENT-56 + Protocol_local and service_sql for plugins to enable 'local' SQL query execution. */ -void Protocol_local::prepare_for_resend() -{ - DBUG_ASSERT(alloc_root_inited(&m_rset_root)); +#ifndef EMBEDDED_LIBRARY +// This part is mostly copied from libmysqld/lib_sql.cc +// TODO: get rid of code duplications - opt_add_row_to_rset(); - /* Start a new row. */ - m_current_row= (Ed_column *) alloc_root(&m_rset_root, - sizeof(Ed_column) * m_column_count); - m_current_column= m_current_row; +#include +#include "../libmysqld/embedded_priv.h" + +class Protocol_local : public Protocol_text +{ +public: + struct st_mysql_data *cur_data; + struct st_mysql_data *first_data; + struct st_mysql_data **data_tail; + void clear_data_list(); + struct st_mysql_data *alloc_new_dataset(); + char **next_field; + MYSQL_FIELD *next_mysql_field; + MEM_ROOT *alloc; + + Protocol_local(THD *thd_arg, ulong prealloc= 0) : + Protocol_text(thd_arg, prealloc), + cur_data(0), first_data(0), data_tail(&first_data) + {} + +protected: + bool net_store_data(const uchar *from, size_t length); + bool net_store_data_cs(const uchar *from, size_t length, + CHARSET_INFO *fromcs, CHARSET_INFO *tocs); + bool net_send_eof(THD *thd, uint server_status, uint statement_warn_count); + bool net_send_ok(THD *, uint, uint, ulonglong, ulonglong, const char *, + bool, bool); + bool net_send_error_packet(THD *, uint, const char *, const char *); + bool begin_dataset(); + bool begin_dataset(THD *thd, uint numfields); + + bool write(); + bool flush(); + + bool store_field_metadata(const THD *thd, const Send_field &field, + CHARSET_INFO *charset_for_protocol, + uint pos); + bool send_result_set_metadata(List *list, uint flags); + void remove_last_row(); + bool store_null(); + void prepare_for_resend(); + bool send_list_fields(List *list, const TABLE_LIST *table_list); + + enum enum_protocol_type type() { return PROTOCOL_LOCAL; }; +}; + +static +bool +write_eof_packet_local(THD *thd, + Protocol_local *p, uint server_status, uint statement_warn_count) +{ +// if (!thd->mysql) // bootstrap file handling +// return FALSE; + /* + The following test should never be true, but it's better to do it + because if 'is_fatal_error' is set the server is not going to execute + other queries (see the if test in dispatch_command / COM_QUERY) + */ + if (thd->is_fatal_error) + thd->server_status&= ~SERVER_MORE_RESULTS_EXISTS; + p->cur_data->embedded_info->server_status= server_status; + /* + Don't send warn count during SP execution, as the warn_list + is cleared between substatements, and mysqltest gets confused + */ + p->cur_data->embedded_info->warning_count= + (thd->spcont ? 0 : MY_MIN(statement_warn_count, 65535)); + return FALSE; +} + + +MYSQL_DATA *Protocol_local::alloc_new_dataset() +{ + MYSQL_DATA *data; + struct embedded_query_result *emb_data; + if (!my_multi_malloc(PSI_INSTRUMENT_ME, MYF(MY_WME | MY_ZEROFILL), + &data, sizeof(*data), + &emb_data, sizeof(*emb_data), + NULL)) + return NULL; + + emb_data->prev_ptr= &data->data; + cur_data= data; + *data_tail= data; + data_tail= &emb_data->next; + data->embedded_info= emb_data; + return data; +} + + +static char *dup_str_aux(MEM_ROOT *root, const char *from, uint length, + CHARSET_INFO *fromcs, CHARSET_INFO *tocs) +{ + uint32 dummy32; + uint dummy_err; + char *result; + + /* 'tocs' is set 0 when client issues SET character_set_results=NULL */ + if (tocs && String::needs_conversion(0, fromcs, tocs, &dummy32)) + { + uint new_len= (tocs->mbmaxlen * length) / fromcs->mbminlen + 1; + result= (char *)alloc_root(root, new_len); + length= copy_and_convert(result, new_len, + tocs, from, length, fromcs, &dummy_err); + } + else + { + result= (char *)alloc_root(root, length + 1); + memcpy(result, from, length); + } + + result[length]= 0; + return result; +} + + +static char *dup_str_aux(MEM_ROOT *root, const LEX_CSTRING &from, + CHARSET_INFO *fromcs, CHARSET_INFO *tocs) +{ + return dup_str_aux(root, from.str, (uint) from.length, fromcs, tocs); +} + + +bool Protocol_local::net_store_data(const uchar *from, size_t length) +{ + char *field_buf; +// if (!thd->mysql) // bootstrap file handling +// return FALSE; + + if (!(field_buf= (char*) alloc_root(alloc, length + sizeof(uint) + 1))) + return TRUE; + *(uint *)field_buf= (uint) length; + *next_field= field_buf + sizeof(uint); + memcpy((uchar*) *next_field, from, length); + (*next_field)[length]= 0; + if (next_mysql_field->max_length < length) + next_mysql_field->max_length= (unsigned long) length; + ++next_field; + ++next_mysql_field; + return FALSE; +} + + +bool Protocol_local::net_store_data_cs(const uchar *from, size_t length, + CHARSET_INFO *from_cs, CHARSET_INFO *to_cs) +{ + uint conv_length= (uint) (to_cs->mbmaxlen * length / from_cs->mbminlen); + uint dummy_error; + char *field_buf; +// if (!thd->mysql) // bootstrap file handling +// return false; + + if (!(field_buf= (char*) alloc_root(alloc, conv_length + sizeof(uint) + 1))) + return true; + *next_field= field_buf + sizeof(uint); + length= copy_and_convert(*next_field, conv_length, to_cs, + (const char*) from, length, from_cs, &dummy_error); + *(uint *) field_buf= (uint) length; + (*next_field)[length]= 0; + if (next_mysql_field->max_length < length) + next_mysql_field->max_length= (unsigned long) length; + ++next_field; + ++next_mysql_field; + return false; } /** - In "real" protocols this is called to finish a result set row. - Unused in the local implementation. + Embedded library implementation of OK response. + + This function is used by the server to write 'OK' packet to + the "network" when the server is compiled as an embedded library. + Since there is no network in the embedded configuration, + a different implementation is necessary. + Instead of marshalling response parameters to a network representation + and then writing it to the socket, here we simply copy the data to the + corresponding client-side connection structures. + + @sa Server implementation of net_send_ok in protocol.cc for + description of the arguments. + + @return + @retval TRUE An error occurred + @retval FALSE Success */ +bool +Protocol_local::net_send_ok(THD *thd, + uint server_status, uint statement_warn_count, + ulonglong affected_rows, ulonglong id, const char *message, bool, bool) +{ + DBUG_ENTER("emb_net_send_ok"); + MYSQL_DATA *data; +// MYSQL *mysql= thd->mysql; + +// if (!mysql) // bootstrap file handling +// DBUG_RETURN(FALSE); + if (!(data= alloc_new_dataset())) + DBUG_RETURN(TRUE); + data->embedded_info->affected_rows= affected_rows; + data->embedded_info->insert_id= id; + if (message) + strmake_buf(data->embedded_info->info, message); + + bool error= write_eof_packet_local(thd, this, + server_status, statement_warn_count); + cur_data= 0; + DBUG_RETURN(error); +} + + +/** + Embedded library implementation of EOF response. + + @sa net_send_ok + + @return + @retval TRUE An error occurred + @retval FALSE Success +*/ + +bool +Protocol_local::net_send_eof(THD *thd, uint server_status, + uint statement_warn_count) +{ + bool error= write_eof_packet_local(thd, this, server_status, + statement_warn_count); + cur_data= 0; + return error; +} + + +bool Protocol_local::net_send_error_packet(THD *thd, uint sql_errno, + const char *err, const char *sqlstate) +{ + uint error; + char converted_err[MYSQL_ERRMSG_SIZE]; + MYSQL_DATA *data= cur_data; + struct embedded_query_result *ei; + +// if (!thd->mysql) // bootstrap file handling +// { +// fprintf(stderr, "ERROR: %d %s\n", sql_errno, err); +// return TRUE; +// } + if (!data) + data= alloc_new_dataset(); + + ei= data->embedded_info; + ei->last_errno= sql_errno; + convert_error_message(converted_err, sizeof(converted_err), + thd->variables.character_set_results, + err, strlen(err), + system_charset_info, &error); + /* Converted error message is always null-terminated. */ + strmake_buf(ei->info, converted_err); + strmov(ei->sqlstate, sqlstate); + ei->server_status= thd->server_status; + cur_data= 0; + return FALSE; +} + + +bool Protocol_local::begin_dataset() +{ + MYSQL_DATA *data= alloc_new_dataset(); + if (!data) + return 1; + alloc= &data->alloc; + /* Assume rowlength < 8192 */ + init_alloc_root(PSI_INSTRUMENT_ME, alloc, 8192, 0, MYF(0)); + alloc->min_malloc= sizeof(MYSQL_ROWS); + return 0; +} + + +bool Protocol_local::begin_dataset(THD *thd, uint numfields) +{ + if (begin_dataset()) + return true; + MYSQL_DATA *data= cur_data; + data->fields= field_count= numfields; + if (!(data->embedded_info->fields_list= + (MYSQL_FIELD*)alloc_root(&data->alloc, sizeof(MYSQL_FIELD)*field_count))) + return true; + return false; +} + + bool Protocol_local::write() { - return FALSE; +// if (!thd->mysql) // bootstrap file handling +// return false; + + *next_field= 0; + return false; } -/** - A helper function to add the current row to the current result - set. Called in @sa prepare_for_resend(), when a new row is started, - and in send_eof(), when the result set is finished. -*/ -void Protocol_local::opt_add_row_to_rset() +bool Protocol_local::flush() { - if (m_current_row) + return 0; +} + + +bool Protocol_local::store_field_metadata(const THD * thd, + const Send_field &server_field, + CHARSET_INFO *charset_for_protocol, + uint pos) +{ + CHARSET_INFO *cs= system_charset_info; + CHARSET_INFO *thd_cs= thd->variables.character_set_results; + MYSQL_DATA *data= cur_data; + MEM_ROOT *field_alloc= &data->alloc; + MYSQL_FIELD *client_field= &cur_data->embedded_info->fields_list[pos]; + DBUG_ASSERT(server_field.is_sane()); + + client_field->db= dup_str_aux(field_alloc, server_field.db_name, + cs, thd_cs); + client_field->table= dup_str_aux(field_alloc, server_field.table_name, + cs, thd_cs); + client_field->name= dup_str_aux(field_alloc, server_field.col_name, + cs, thd_cs); + client_field->org_table= dup_str_aux(field_alloc, server_field.org_table_name, + cs, thd_cs); + client_field->org_name= dup_str_aux(field_alloc, server_field.org_col_name, + cs, thd_cs); + if (charset_for_protocol == &my_charset_bin || thd_cs == NULL) { - /* Add the old row to the result set */ - Ed_row *ed_row= new (&m_rset_root) Ed_row(m_current_row, m_column_count); - if (ed_row) - m_rset->push_back(ed_row, &m_rset_root); + /* No conversion */ + client_field->charsetnr= charset_for_protocol->number; + client_field->length= server_field.length; + } + else + { + /* With conversion */ + client_field->charsetnr= thd_cs->number; + client_field->length= server_field.max_octet_length(charset_for_protocol, + thd_cs); + } + client_field->type= server_field.type_handler()->type_code_for_protocol(); + client_field->flags= (uint16) server_field.flags; + client_field->decimals= server_field.decimals; + + client_field->db_length= (unsigned int) strlen(client_field->db); + client_field->table_length= (unsigned int) strlen(client_field->table); + client_field->name_length= (unsigned int) strlen(client_field->name); + client_field->org_name_length= (unsigned int) strlen(client_field->org_name); + client_field->org_table_length= (unsigned int) strlen(client_field->org_table); + + client_field->catalog= dup_str_aux(field_alloc, "def", 3, cs, thd_cs); + client_field->catalog_length= 3; + + if (IS_NUM(client_field->type)) + client_field->flags|= NUM_FLAG; + + client_field->max_length= 0; + client_field->def= 0; + return false; +} + + +void Protocol_local::remove_last_row() +{ + MYSQL_DATA *data= cur_data; + MYSQL_ROWS **last_row_hook= &data->data; + my_ulonglong count= data->rows; + DBUG_ENTER("Protocol_text::remove_last_row"); + while (--count) + last_row_hook= &(*last_row_hook)->next; + + *last_row_hook= 0; + data->embedded_info->prev_ptr= last_row_hook; + data->rows--; + + DBUG_VOID_RETURN; +} + + +bool Protocol_local::send_result_set_metadata(List *list, uint flags) +{ + List_iterator_fast it(*list); + Item *item; +// Protocol_local prot(thd); + DBUG_ENTER("send_result_set_metadata"); + +// if (!thd->mysql) // bootstrap file handling +// DBUG_RETURN(0); + + if (begin_dataset(thd, list->elements)) + goto err; + + for (uint pos= 0 ; (item= it++); pos++) + { + if (/*prot.*/store_item_metadata(thd, item, pos)) + goto err; + } + + if (flags & SEND_EOF) + write_eof_packet_local(thd, this, thd->server_status, + thd->get_stmt_da()->current_statement_warn_count()); + + DBUG_RETURN(prepare_for_send(list->elements)); + err: + my_error(ER_OUT_OF_RESOURCES, MYF(0)); /* purecov: inspected */ + DBUG_RETURN(1); /* purecov: inspected */ +} + +static void +list_fields_send_default(THD *thd, Protocol_local *p, Field *fld, uint pos) +{ + char buff[80]; + String tmp(buff, sizeof(buff), default_charset_info), *res; + MYSQL_FIELD *client_field= &p->cur_data->embedded_info->fields_list[pos]; + + if (fld->is_null() || !(res= fld->val_str(&tmp))) + { + client_field->def_length= 0; + client_field->def= strmake_root(&p->cur_data->alloc, "", 0); + } + else + { + client_field->def_length= res->length(); + client_field->def= strmake_root(&p->cur_data->alloc, res->ptr(), + client_field->def_length); } } -/** - Add a NULL column to the current row. -*/ +bool Protocol_local::send_list_fields(List *list, const TABLE_LIST *table_list) +{ + DBUG_ENTER("send_result_set_metadata"); + Protocol_text prot(thd); + List_iterator_fast it(*list); + Field *fld; + +// if (!thd->mysql) // bootstrap file handling +// DBUG_RETURN(0); + + if (begin_dataset(thd, list->elements)) + goto err; + + for (uint pos= 0 ; (fld= it++); pos++) + { + if (prot.store_field_metadata_for_list_fields(thd, fld, table_list, pos)) + goto err; + list_fields_send_default(thd, this, fld, pos); + } + + DBUG_RETURN(prepare_for_send(list->elements)); +err: + my_error(ER_OUT_OF_RESOURCES, MYF(0)); + DBUG_RETURN(1); +} + + +void Protocol_local::prepare_for_resend() +{ + MYSQL_ROWS *cur; + MYSQL_DATA *data= cur_data; + DBUG_ENTER("send_data"); + +// if (!thd->mysql) // bootstrap file handling +// DBUG_VOID_RETURN; + + data->rows++; + if (!(cur= (MYSQL_ROWS *)alloc_root(alloc, sizeof(MYSQL_ROWS)+(field_count + 1) * sizeof(char *)))) + { + my_error(ER_OUT_OF_RESOURCES,MYF(0)); + DBUG_VOID_RETURN; + } + cur->data= (MYSQL_ROW)(((char *)cur) + sizeof(MYSQL_ROWS)); + + *data->embedded_info->prev_ptr= cur; + data->embedded_info->prev_ptr= &cur->next; + next_field=cur->data; + next_mysql_field= data->embedded_info->fields_list; +#ifndef DBUG_OFF + field_pos= 0; +#endif + + DBUG_VOID_RETURN; +} bool Protocol_local::store_null() { - if (m_current_column == NULL) - return TRUE; /* prepare_for_resend() failed to allocate memory. */ - - bzero(m_current_column, sizeof(*m_current_column)); - ++m_current_column; - return FALSE; + *(next_field++)= NULL; + ++next_mysql_field; + return false; } -/** - A helper method to add any column to the current row - in its binary form. +#include +#include - Allocates memory for the data in the result set memory root. -*/ - -bool Protocol_local::store_column(const void *data, size_t length) +struct local_results { - if (m_current_column == NULL) - return TRUE; /* prepare_for_resend() failed to allocate memory. */ - /* - alloc_root() automatically aligns memory, so we don't need to - do any extra alignment if we're pointing to, say, an integer. - */ - m_current_column->str= (char*) memdup_root(&m_rset_root, - data, - length + 1 /* Safety */); - if (! m_current_column->str) - return TRUE; - m_current_column->str[length]= '\0'; /* Safety */ - m_current_column->length= length; - ++m_current_column; - return FALSE; + struct st_mysql_data *cur_data; + struct st_mysql_data *first_data; + struct st_mysql_data **data_tail; + void clear_data_list(); + struct st_mysql_data *alloc_new_dataset(); + char **next_field; + MYSQL_FIELD *next_mysql_field; + MEM_ROOT *alloc; +}; + + +static void embedded_get_error(MYSQL *mysql, MYSQL_DATA *data) +{ + NET *net= &mysql->net; + struct embedded_query_result *ei= data->embedded_info; + net->last_errno= ei->last_errno; + strmake_buf(net->last_error, ei->info); + memcpy(net->sqlstate, ei->sqlstate, sizeof(net->sqlstate)); + mysql->server_status= ei->server_status; + my_free(data); } -/** - Store a string value in a result set column, optionally - having converted it to character_set_results. -*/ - -bool -Protocol_local::store_string(const char *str, size_t length, - CHARSET_INFO *src_cs, CHARSET_INFO *dst_cs) +static my_bool loc_read_query_result(MYSQL *mysql) { - /* Store with conversion */ - uint error_unused; + local_results *thd= (local_results *) mysql->thd; - if (needs_conversion(src_cs, dst_cs)) + MYSQL_DATA *res= thd->first_data; + DBUG_ASSERT(!thd->cur_data); + thd->first_data= res->embedded_info->next; + if (res->embedded_info->last_errno && + !res->embedded_info->fields_list) { - if (unlikely(convert->copy(str, length, src_cs, dst_cs, &error_unused))) - return TRUE; - str= convert->ptr(); - length= convert->length(); + embedded_get_error(mysql, res); + return 1; } - return store_column(str, length); + + mysql->warning_count= res->embedded_info->warning_count; + mysql->server_status= res->embedded_info->server_status; + mysql->field_count= res->fields; + if (!(mysql->fields= res->embedded_info->fields_list)) + { + mysql->affected_rows= res->embedded_info->affected_rows; + mysql->insert_id= res->embedded_info->insert_id; + } + net_clear_error(&mysql->net); + mysql->info= 0; + + if (res->embedded_info->info[0]) + { + strmake(mysql->info_buffer, res->embedded_info->info, MYSQL_ERRMSG_SIZE-1); + mysql->info= mysql->info_buffer; + } + + if (res->embedded_info->fields_list) + { + mysql->status=MYSQL_STATUS_GET_RESULT; + thd->cur_data= res; + } + else + my_free(res); + + return 0; } -/** Store a tiny int as is (1 byte) in a result set column. */ - -bool Protocol_local::store_tiny(longlong value) +static MYSQL_METHODS local_methods= { - char v= (char) value; - return store_column(&v, 1); -} + loc_read_query_result, /* read_query_result */ + NULL/*loc_advanced_command*/, /* advanced_command */ + NULL/*loc_read_rows*/, /* read_rows */ + NULL/*loc_use_result*/, /* use_result */ + NULL/*loc_fetch_lengths*/, /* fetch_lengths */ + NULL/*loc_flush_use_result*/, /* flush_use_result */ + NULL/*loc_read_change_user_result*/ /* read_change_user_result */ +}; -/** Store a short as is (2 bytes, host order) in a result set column. */ - -bool Protocol_local::store_short(longlong value) +extern "C" MYSQL *mysql_real_connect_local(MYSQL *mysql, + const char *host, const char *user, const char *passwd, const char *db) { - int16 v= (int16) value; - return store_column(&v, 2); + //char name_buff[USERNAME_LENGTH]; + + DBUG_ENTER("mysql_real_connect_local"); + + /* Test whether we're already connected */ + if (mysql->server_version) + { + set_mysql_error(mysql, CR_ALREADY_CONNECTED, unknown_sqlstate); + DBUG_RETURN(0); + } + + if (!host || !host[0]) + host= mysql->options.host; + + mysql->methods= &local_methods; + + if (!db || !db[0]) + db=mysql->options.db; + + if (!user || !user[0]) + user=mysql->options.user; + + mysql->user= my_strdup(PSI_INSTRUMENT_ME, user, MYF(0)); + + + mysql->info_buffer= (char *) my_malloc(PSI_INSTRUMENT_ME, + MYSQL_ERRMSG_SIZE, MYF(0)); + //mysql->thd= create_embedded_thd(client_flag); + + //init_embedded_mysql(mysql, client_flag); + + //if (mysql_init_character_set(mysql)) + // goto error; + + //if (check_embedded_connection(mysql, db)) + // goto error; + + mysql->server_status= SERVER_STATUS_AUTOCOMMIT; + + //if (mysql->options.init_commands) + //{ + // DYNAMIC_ARRAY *init_commands= mysql->options.init_commands; + // char **ptr= (char**)init_commands->buffer; + // char **end= ptr + init_commands->elements; +// + // for (; ptrfields) + // { + // if (!(res= (*mysql->methods->use_result)(mysql))) + // goto error; + // mysql_free_result(res); + // } + // } + //} + + DBUG_PRINT("exit",("Mysql handler: %p", mysql)); + DBUG_RETURN(mysql); + +//error: + DBUG_PRINT("error",("message: %u (%s)", + mysql->net.last_errno, + mysql->net.last_error)); + { + /* Free alloced memory */ + my_bool free_me=mysql->free_me; + free_old_query(mysql); + mysql->free_me=0; + mysql_close(mysql); + mysql->free_me=free_me; + } + DBUG_RETURN(0); } -/** Store a "long" as is (4 bytes, host order) in a result set column. */ - -bool Protocol_local::store_long(longlong value) +extern "C" int execute_sql_command(const char *command, + char *hosts, char *names, char *filters) { - int32 v= (int32) value; - return store_column(&v, 4); + MYSQL_LEX_STRING sql_text; + THD *thd= current_thd; + THD *new_thd= 0; + int result; + my_bool qc_save= 0; + + if (!thd) + { + new_thd= new THD(0); + new_thd->thread_stack= (char*) &sql_text; + new_thd->store_globals(); + new_thd->security_ctx->skip_grants(); + new_thd->query_cache_is_applicable= 0; + bzero((char*) &new_thd->net, sizeof(new_thd->net)); + thd= new_thd; + } + else + { + if (thd->lock) + /* Doesn't work if the thread opened/locked tables already. */ + return 2; + + qc_save= thd->query_cache_is_applicable; + thd->query_cache_is_applicable= 0; + } + sql_text.str= (char *) command; + sql_text.length= strlen(command); + { + Protocol_local p(thd); + Ed_connection con(thd); + result= con.execute_direct(&p, sql_text); + if (!result && p.first_data) + { + int nr= (int) p.first_data->rows; + MYSQL_ROWS *rows= p.first_data->data; + + while (nr--) + { + strcpy(hosts, rows->data[0]); + hosts+= strlen(hosts) + 1; + strcpy(names, rows->data[1]); + names+= strlen(names) + 1; + if (filters) + { + strcpy(filters, rows->data[2]); + filters+= strlen(filters) + 1; + } + rows= rows->next; + } + } + if (p.first_data) + { + if (p.alloc) + free_root(p.alloc, MYF(0)); + my_free(p.first_data); + } + } + + if (new_thd) + delete new_thd; + else + thd->query_cache_is_applicable= qc_save; + + *hosts= 0; + return result; } - -/** Store a "longlong" as is (8 bytes, host order) in a result set column. */ - -bool Protocol_local::store_longlong(longlong value, bool unsigned_flag) -{ - int64 v= (int64) value; - return store_column(&v, 8); -} +#endif /*!EMBEDDED_LIBRARY*/ -/** Store a decimal in string format in a result set column */ - -bool Protocol_local::store_decimal(const my_decimal *value) -{ - DBUG_ASSERT(0); // This method is not used yet - StringBuffer str; - return value->to_string(&str) ? store_column(str.ptr(), str.length()) : true; -} - - -/** Store a string. */ - -bool Protocol_local::store_str(const char *str, size_t length, - CHARSET_INFO *src_cs, CHARSET_INFO *dst_cs) -{ - return store_string(str, length, src_cs, dst_cs); -} - - -/* Store MYSQL_TIME (in binary format) */ - -bool Protocol_local::store(MYSQL_TIME *time, int decimals) -{ - if (decimals != AUTO_SEC_PART_DIGITS) - my_datetime_trunc(time, decimals); - return store_column(time, sizeof(MYSQL_TIME)); -} - - -/** Store MYSQL_TIME (in binary format) */ - -bool Protocol_local::store_date(MYSQL_TIME *time) -{ - return store_column(time, sizeof(MYSQL_TIME)); -} - - -/** Store MYSQL_TIME (in binary format) */ - -bool Protocol_local::store_time(MYSQL_TIME *time, int decimals) -{ - if (decimals != AUTO_SEC_PART_DIGITS) - my_time_trunc(time, decimals); - return store_column(time, sizeof(MYSQL_TIME)); -} - - -/* Store a floating point number, as is. */ - -bool Protocol_local::store_float(float value, uint32 decimals) -{ - return store_column(&value, sizeof(float)); -} - - -/* Store a double precision number, as is. */ - -bool Protocol_local::store_double(double value, uint32 decimals) -{ - return store_column(&value, sizeof (double)); -} - - -/* Store a Field. */ - -bool Protocol_local::store(Field *field) -{ - if (field->is_null()) - return store_null(); - return field->send(this); -} - - -/** Called to start a new result set. */ - -bool Protocol_local::send_result_set_metadata(List *columns, uint) -{ - DBUG_ASSERT(m_rset == 0 && !alloc_root_inited(&m_rset_root)); - - init_sql_alloc(PSI_INSTRUMENT_ME, &m_rset_root, MEM_ROOT_BLOCK_SIZE, 0, - MYF(MY_THREAD_SPECIFIC)); - - if (! (m_rset= new (&m_rset_root) List)) - return TRUE; - - m_column_count= columns->elements; - - return FALSE; -} - - -/** - Normally this is a separate result set with OUT parameters - of stored procedures. Currently unsupported for the local - version. -*/ - -bool Protocol_local::send_out_parameters(List *sp_params) -{ - return FALSE; -} - - -/** Called for statements that don't have a result set, at statement end. */ - -bool -Protocol_local::send_ok(uint server_status, uint statement_warn_count, - ulonglong affected_rows, ulonglong last_insert_id, - const char *message, bool skip_flush) -{ - /* - Just make sure nothing is sent to the client, we have grabbed - the status information in the connection diagnostics area. - */ - return FALSE; -} - - -/** - Called at the end of a result set. Append a complete - result set to the list in Ed_connection. - - Don't send anything to the client, but instead finish - building of the result set at hand. -*/ - -bool Protocol_local::send_eof(uint server_status, uint statement_warn_count) -{ - Ed_result_set *ed_result_set; - - DBUG_ASSERT(m_rset); - - opt_add_row_to_rset(); - m_current_row= 0; - - ed_result_set= new (&m_rset_root) Ed_result_set(m_rset, m_column_count, - &m_rset_root); - - m_rset= NULL; - - if (! ed_result_set) - return TRUE; - - /* In case of successful allocation memory ownership was transferred. */ - DBUG_ASSERT(!alloc_root_inited(&m_rset_root)); - - /* - Link the created Ed_result_set instance into the list of connection - result sets. Never fails. - */ - m_connection->add_result_set(ed_result_set); - return FALSE; -} - - -/** Called to send an error to the client at the end of a statement. */ - -bool -Protocol_local::send_error(uint sql_errno, const char *err_msg, const char*) -{ - /* - Just make sure that nothing is sent to the client (default - implementation). - */ - return FALSE; -} - - -#ifdef EMBEDDED_LIBRARY -void Protocol_local::remove_last_row() -{ } -#endif diff --git a/sql/sql_prepare.h b/sql/sql_prepare.h index f1c4e5e4be9..166be95eb89 100644 --- a/sql/sql_prepare.h +++ b/sql/sql_prepare.h @@ -200,7 +200,7 @@ public: @retval TRUE error, use get_last_error() to see the error number. */ - bool execute_direct(LEX_STRING sql_text); + bool execute_direct(Protocol *p, LEX_STRING sql_text); /** Same as the previous, but takes an instance of Server_runnable @@ -213,7 +213,7 @@ public: return a result set @retval TRUE failure */ - bool execute_direct(Server_runnable *server_runnable); + bool execute_direct(Protocol *p, Server_runnable *server_runnable); /** Get the number of affected (deleted, updated) @@ -309,7 +309,6 @@ private: THD *m_thd; Ed_result_set *m_rsets; Ed_result_set *m_current_rset; - friend class Protocol_local; private: void free_old_result(); void add_result_set(Ed_result_set *ed_result_set); From ad1a3ce418a14bd34e251cc731dbf3778c63de05 Mon Sep 17 00:00:00 2001 From: Kentoku SHIBA Date: Thu, 13 Aug 2020 05:36:23 +0900 Subject: [PATCH 30/70] MDEV-19794 Spider crash with XA --- .../spider/bugfix/include/xa_cmd_deinit.inc | 11 +++ .../spider/bugfix/include/xa_cmd_init.inc | 24 +++++++ .../mysql-test/spider/bugfix/r/xa_cmd.result | 70 +++++++++++++++++++ .../mysql-test/spider/bugfix/t/xa_cmd.cnf | 3 + .../mysql-test/spider/bugfix/t/xa_cmd.test | 69 ++++++++++++++++++ storage/spider/spd_trx.cc | 20 ++++-- 6 files changed, 193 insertions(+), 4 deletions(-) create mode 100644 storage/spider/mysql-test/spider/bugfix/include/xa_cmd_deinit.inc create mode 100644 storage/spider/mysql-test/spider/bugfix/include/xa_cmd_init.inc create mode 100644 storage/spider/mysql-test/spider/bugfix/r/xa_cmd.result create mode 100644 storage/spider/mysql-test/spider/bugfix/t/xa_cmd.cnf create mode 100644 storage/spider/mysql-test/spider/bugfix/t/xa_cmd.test diff --git a/storage/spider/mysql-test/spider/bugfix/include/xa_cmd_deinit.inc b/storage/spider/mysql-test/spider/bugfix/include/xa_cmd_deinit.inc new file mode 100644 index 00000000000..76b7582abfe --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/include/xa_cmd_deinit.inc @@ -0,0 +1,11 @@ +--let $MASTER_1_COMMENT_2_1= $MASTER_1_COMMENT_2_1_BACKUP +--let $CHILD2_1_DROP_TABLES= $CHILD2_1_DROP_TABLES_BACKUP +--let $CHILD2_1_CREATE_TABLES= $CHILD2_1_CREATE_TABLES_BACKUP +--let $CHILD2_1_SELECT_TABLES= $CHILD2_1_SELECT_TABLES_BACKUP +--disable_warnings +--disable_query_log +--disable_result_log +--source ../t/test_deinit.inc +--enable_result_log +--enable_query_log +--enable_warnings diff --git a/storage/spider/mysql-test/spider/bugfix/include/xa_cmd_init.inc b/storage/spider/mysql-test/spider/bugfix/include/xa_cmd_init.inc new file mode 100644 index 00000000000..5c607bd1ff5 --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/include/xa_cmd_init.inc @@ -0,0 +1,24 @@ +--disable_warnings +--disable_query_log +--disable_result_log +--source ../t/test_init.inc +--enable_result_log +--enable_query_log +--enable_warnings +--let $MASTER_1_COMMENT_2_1_BACKUP= $MASTER_1_COMMENT_2_1 +let $MASTER_1_COMMENT_2_1= + COMMENT='table "tbl_a", srv "s_2_1"'; +--let $CHILD2_1_DROP_TABLES_BACKUP= $CHILD2_1_DROP_TABLES +let $CHILD2_1_DROP_TABLES= + DROP TABLE IF EXISTS tbl_a; +--let $CHILD2_1_CREATE_TABLES_BACKUP= $CHILD2_1_CREATE_TABLES +let $CHILD2_1_CREATE_TABLES= + CREATE TABLE tbl_a ( + pkey int NOT NULL, + PRIMARY KEY (pkey) + ) $CHILD2_1_ENGINE $CHILD2_1_CHARSET; +--let $CHILD2_1_SELECT_TABLES_BACKUP= $CHILD2_1_SELECT_TABLES +let $CHILD2_1_SELECT_TABLES= + SELECT pkey FROM tbl_a ORDER BY pkey; +let $CHILD2_1_SELECT_ARGUMENT1= + SELECT argument FROM mysql.general_log WHERE argument LIKE '%insert %'; diff --git a/storage/spider/mysql-test/spider/bugfix/r/xa_cmd.result b/storage/spider/mysql-test/spider/bugfix/r/xa_cmd.result new file mode 100644 index 00000000000..3ff39317de6 --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/r/xa_cmd.result @@ -0,0 +1,70 @@ +for master_1 +for child2 +child2_1 +child2_2 +child2_3 +for child3 + +this test is for MDEV-19794 + +drop and create databases +connection master_1; +CREATE DATABASE auto_test_local; +USE auto_test_local; +connection child2_1; +SET @old_log_output = @@global.log_output; +SET GLOBAL log_output = 'TABLE,FILE'; +CREATE DATABASE auto_test_remote; +USE auto_test_remote; + +create table and insert +connection child2_1; +CHILD2_1_CREATE_TABLES +TRUNCATE TABLE mysql.general_log; +connection master_1; +CREATE TABLE tbl_a ( +pkey int NOT NULL, +PRIMARY KEY (pkey) +) MASTER_1_ENGINE MASTER_1_CHARSET MASTER_1_COMMENT_2_1 +connection child2_1; +TRUNCATE TABLE mysql.general_log; +connection master_1; +XA START 'test'; +INSERT INTO tbl_a (pkey) VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +XA END 'test'; +XA PREPARE 'test'; +Warnings: +Warning 1030 Got error 131 "Command not supported by the engine" from storage engine Aria +XA COMMIT 'test'; +connection child2_1; +SELECT argument FROM mysql.general_log WHERE argument LIKE '%insert %'; +argument +insert into `auto_test_remote`.`tbl_a`(`pkey`)values(0),(1),(2),(3),(4),(5),(6),(7),(8),(9) +SELECT argument FROM mysql.general_log WHERE argument LIKE '%insert %' +SELECT pkey FROM tbl_a ORDER BY pkey; +pkey +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 + +deinit +connection master_1; +DROP DATABASE IF EXISTS auto_test_local; +connection child2_1; +DROP DATABASE IF EXISTS auto_test_remote; +SET GLOBAL log_output = @old_log_output; +for master_1 +for child2 +child2_1 +child2_2 +child2_3 +for child3 + +end of test diff --git a/storage/spider/mysql-test/spider/bugfix/t/xa_cmd.cnf b/storage/spider/mysql-test/spider/bugfix/t/xa_cmd.cnf new file mode 100644 index 00000000000..05dfd8a0bce --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/t/xa_cmd.cnf @@ -0,0 +1,3 @@ +!include include/default_mysqld.cnf +!include ../my_1_1.cnf +!include ../my_2_1.cnf diff --git a/storage/spider/mysql-test/spider/bugfix/t/xa_cmd.test b/storage/spider/mysql-test/spider/bugfix/t/xa_cmd.test new file mode 100644 index 00000000000..9ae528071e3 --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/t/xa_cmd.test @@ -0,0 +1,69 @@ +--source ../include/xa_cmd_init.inc +--echo +--echo this test is for MDEV-19794 +--echo +--echo drop and create databases + +--connection master_1 +--disable_warnings +CREATE DATABASE auto_test_local; +USE auto_test_local; + +--connection child2_1 +SET @old_log_output = @@global.log_output; +SET GLOBAL log_output = 'TABLE,FILE'; +CREATE DATABASE auto_test_remote; +USE auto_test_remote; +--enable_warnings + +--echo +--echo create table and insert + +--connection child2_1 +--disable_query_log +echo CHILD2_1_CREATE_TABLES; +eval $CHILD2_1_CREATE_TABLES; +--enable_query_log +TRUNCATE TABLE mysql.general_log; + +--connection master_1 +--disable_query_log +echo CREATE TABLE tbl_a ( + pkey int NOT NULL, + PRIMARY KEY (pkey) +) MASTER_1_ENGINE MASTER_1_CHARSET MASTER_1_COMMENT_2_1; +eval CREATE TABLE tbl_a ( + pkey int NOT NULL, + PRIMARY KEY (pkey) +) $MASTER_1_ENGINE $MASTER_1_CHARSET $MASTER_1_COMMENT_2_1; +--enable_query_log + +--connection child2_1 +TRUNCATE TABLE mysql.general_log; + +--connection master_1 +XA START 'test'; +INSERT INTO tbl_a (pkey) VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +XA END 'test'; +XA PREPARE 'test'; +XA COMMIT 'test'; + +--connection child2_1 +eval $CHILD2_1_SELECT_ARGUMENT1; +eval $CHILD2_1_SELECT_TABLES; + +--echo +--echo deinit +--disable_warnings + +--connection master_1 +DROP DATABASE IF EXISTS auto_test_local; + +--connection child2_1 +DROP DATABASE IF EXISTS auto_test_remote; +SET GLOBAL log_output = @old_log_output; + +--enable_warnings +--source ../include/xa_cmd_deinit.inc +--echo +--echo end of test diff --git a/storage/spider/spd_trx.cc b/storage/spider/spd_trx.cc index e2df52814dd..78af5623b94 100644 --- a/storage/spider/spd_trx.cc +++ b/storage/spider/spd_trx.cc @@ -2294,7 +2294,10 @@ int spider_internal_xa_commit( spider_close_sys_table(thd, table_xa, &open_tables_backup, TRUE); table_xa_opened = FALSE; } - spider_xa_unlock(&trx->internal_xid_state); + if (trx->internal_xa) + { + spider_xa_unlock(&trx->internal_xid_state); + } DBUG_RETURN(0); error: @@ -2304,7 +2307,10 @@ error: spider_close_sys_table(thd, table_xa_member, &open_tables_backup, TRUE); error_in_commit: error_open_table: - spider_xa_unlock(&trx->internal_xid_state); + if (trx->internal_xa) + { + spider_xa_unlock(&trx->internal_xid_state); + } DBUG_RETURN(error_num); } @@ -2530,7 +2536,10 @@ int spider_internal_xa_rollback( spider_close_sys_table(thd, table_xa, &open_tables_backup, TRUE); table_xa_opened = FALSE; } - spider_xa_unlock(&trx->internal_xid_state); + if (trx->internal_xa) + { + spider_xa_unlock(&trx->internal_xid_state); + } DBUG_RETURN(0); error: @@ -2540,7 +2549,10 @@ error: spider_close_sys_table(thd, table_xa_member, &open_tables_backup, TRUE); error_in_rollback: error_open_table: - spider_xa_unlock(&trx->internal_xid_state); + if (trx->internal_xa) + { + spider_xa_unlock(&trx->internal_xid_state); + } DBUG_RETURN(error_num); } From a7a9f44f8c2f2d09a0e0af6a560ef84608d4bb7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Mon, 10 Aug 2020 11:44:42 +0300 Subject: [PATCH 31/70] MDEV-22543 : Galera SST donation fails, FLUSH TABLES WITH READ LOCK times out During SST we need to let FTWRL to use normal timeout method even when client is disconnected. --- mysql-test/suite/galera/r/mdev-22543.result | 19 +++++++ mysql-test/suite/galera/t/mdev-22543.test | 58 +++++++++++++++++++++ sql/mdl.cc | 25 ++++++--- sql/wsrep_sst.cc | 14 ++++- sql/wsrep_sst.h | 2 + 5 files changed, 109 insertions(+), 9 deletions(-) create mode 100644 mysql-test/suite/galera/r/mdev-22543.result create mode 100644 mysql-test/suite/galera/t/mdev-22543.test diff --git a/mysql-test/suite/galera/r/mdev-22543.result b/mysql-test/suite/galera/r/mdev-22543.result new file mode 100644 index 00000000000..9386b7405d4 --- /dev/null +++ b/mysql-test/suite/galera/r/mdev-22543.result @@ -0,0 +1,19 @@ +connection node_2; +connection node_1; +connection node_1; +connection node_2; +connection node_1; +CREATE TABLE t1 (f1 INT PRIMARY KEY, f2 INT); +INSERT INTO t1 VALUES (1, 1); +SET DEBUG_SYNC = "before_lock_tables_takes_lock SIGNAL sync_point_reached WAIT_FOR sync_point_continue"; +UPDATE t1 SET f2 = 2 WHERE f1 = 1; +connection node_1_ctrl; +SET DEBUG_SYNC = "now WAIT_FOR sync_point_reached"; +connection node_2; +connection node_1_ctrl; +SET DEBUG_SYNC = "now SIGNAL sync_point_continue"; +connection node_1; +SET DEBUG_SYNC = "RESET"; +connection node_2; +connection node_1; +DROP TABLE t1; diff --git a/mysql-test/suite/galera/t/mdev-22543.test b/mysql-test/suite/galera/t/mdev-22543.test new file mode 100644 index 00000000000..53662e36942 --- /dev/null +++ b/mysql-test/suite/galera/t/mdev-22543.test @@ -0,0 +1,58 @@ +# The test verifies that the FLUSH TABLES WITH READ LOCK does not +# time out if it needs to wait for another MDL lock for short duration +# during SST donation. + +--source include/galera_cluster.inc +--source include/have_debug.inc +--source include/have_debug_sync.inc + +--let $node_1 = node_1 +--let $node_2 = node_2 +--source include/auto_increment_offset_save.inc + +--let $galera_connection_name = node_1_ctrl +--let $galera_server_number = 1 +--source include/galera_connect.inc + +# +# Run UPDATE on node_1 and make it block before table locks are taken. +# This should block FTWRL. +# +--connection node_1 +CREATE TABLE t1 (f1 INT PRIMARY KEY, f2 INT); +INSERT INTO t1 VALUES (1, 1); +SET DEBUG_SYNC = "before_lock_tables_takes_lock SIGNAL sync_point_reached WAIT_FOR sync_point_continue"; +--send UPDATE t1 SET f2 = 2 WHERE f1 = 1 + +--connection node_1_ctrl +SET DEBUG_SYNC = "now WAIT_FOR sync_point_reached"; + +# +# Restart node_2, force SST. +# +--connection node_2 +--source include/shutdown_mysqld.inc +--remove_file $MYSQLTEST_VARDIR/mysqld.2/data/grastate.dat +# Restart without waiting. The UPDATE should block FTWRL on node_1, +# so the SST cannot be completed and node_2 cannot join before +# UPDATE connection is signalled to continue. +--exec echo "restart:$start_mysqld_params" > $_expect_file_name +# If the bug is present, FTWRL times out on node_1 in couple of +# seconds and node_2 fails to join. +--sleep 10 + +--connection node_1_ctrl +SET DEBUG_SYNC = "now SIGNAL sync_point_continue"; + +--connection node_1 +--reap +SET DEBUG_SYNC = "RESET"; + +--connection node_2 +--enable_reconnect +--source include/wait_until_connected_again.inc + +--connection node_1 +DROP TABLE t1; + +--source include/auto_increment_offset_restore.inc diff --git a/sql/mdl.cc b/sql/mdl.cc index 54128c2ee97..a369f9e9a95 100644 --- a/sql/mdl.cc +++ b/sql/mdl.cc @@ -24,6 +24,7 @@ #include #include #include +#include "wsrep_sst.h" #ifdef HAVE_PSI_INTERFACE static PSI_mutex_key key_MDL_wait_LOCK_wait_status; @@ -2325,18 +2326,26 @@ MDL_context::acquire_lock(MDL_request *mdl_request, double lock_wait_timeout) wait_status= m_wait.timed_wait(m_owner, &abs_shortwait, FALSE, mdl_request->key.get_wait_state_name()); + THD* thd= m_owner->get_thd(); + if (wait_status != MDL_wait::EMPTY) break; /* Check if the client is gone while we were waiting. */ - if (! thd_is_connected(m_owner->get_thd())) + if (! thd_is_connected(thd)) { - /* - * The client is disconnected. Don't wait forever: - * assume it's the same as a wait timeout, this - * ensures all error handling is correct. - */ - wait_status= MDL_wait::TIMEOUT; - break; +#if defined(WITH_WSREP) && !defined(EMBEDDED_LIBRARY) + // During SST client might not be connected + if (!wsrep_is_sst_progress()) +#endif + { + /* + * The client is disconnected. Don't wait forever: + * assume it's the same as a wait timeout, this + * ensures all error handling is correct. + */ + wait_status= MDL_wait::TIMEOUT; + break; + } } mysql_prlock_wrlock(&lock->m_rwlock); diff --git a/sql/wsrep_sst.cc b/sql/wsrep_sst.cc index c14cfe814fa..396b262abb4 100644 --- a/sql/wsrep_sst.cc +++ b/sql/wsrep_sst.cc @@ -54,6 +54,7 @@ my_bool wsrep_sst_donor_rejects_queries= FALSE; bool sst_joiner_completed = false; bool sst_donor_completed = false; +bool sst_needed = false; struct sst_thread_arg { @@ -307,6 +308,7 @@ bool wsrep_before_SE() && strcmp (wsrep_sst_method, WSREP_SST_MYSQLDUMP)); } +static bool sst_in_progress = false; // Signal end of SST static void wsrep_sst_complete (THD* thd, int const rcode) @@ -1623,7 +1625,10 @@ static void* sst_donor_thread (void* a) char out_buf[out_len]; wsrep_uuid_t ret_uuid= WSREP_UUID_UNDEFINED; - wsrep_seqno_t ret_seqno= WSREP_SEQNO_UNDEFINED; // seqno of complete SST + // seqno of complete SST + wsrep_seqno_t ret_seqno= WSREP_SEQNO_UNDEFINED; + // SST is now in progress + sst_in_progress= true; wsp::thd thd(FALSE); // we turn off wsrep_on for this THD so that it can // operate with wsrep_ready == OFF @@ -1729,6 +1734,8 @@ wait_signal: proc.wait(); wsrep_donor_monitor_end(); + sst_in_progress= false; + return NULL; } @@ -1882,3 +1889,8 @@ int wsrep_sst_donate(const std::string& msg, return (ret >= 0 ? 0 : 1); } + +bool wsrep_is_sst_progress() +{ + return (sst_in_progress); +} diff --git a/sql/wsrep_sst.h b/sql/wsrep_sst.h index 2389db4abe7..50f2d362c5a 100644 --- a/sql/wsrep_sst.h +++ b/sql/wsrep_sst.h @@ -77,6 +77,7 @@ extern void wsrep_SE_init_grab(); /*! grab init critical section */ extern void wsrep_SE_init_wait(); /*! wait for SE init to complete */ extern void wsrep_SE_init_done(); /*! signal that SE init is complte */ extern void wsrep_SE_initialized(); /*! mark SE initialization complete */ +extern bool wsrep_is_sst_progress(); /** Return a string containing the state transfer request string. @@ -102,5 +103,6 @@ int wsrep_sst_donate(const std::string& request, #define wsrep_SE_init_grab() do { } while(0) #define wsrep_SE_init_done() do { } while(0) #define wsrep_sst_continue() (0) +#define wsrep_is_sst_progress() (0) #endif /* WSREP_SST_H */ From 7df4706619898c025fbc1d3d48420da039e889cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Fri, 14 Aug 2020 13:34:19 +0300 Subject: [PATCH 32/70] Fix Windows compiler error. --- sql/mdl.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sql/mdl.cc b/sql/mdl.cc index a369f9e9a95..97135890f09 100644 --- a/sql/mdl.cc +++ b/sql/mdl.cc @@ -24,7 +24,9 @@ #include #include #include +#ifdef WITH_WSREP #include "wsrep_sst.h" +#endif #ifdef HAVE_PSI_INTERFACE static PSI_mutex_key key_MDL_wait_LOCK_wait_status; From 303212d4b605ee423dc6b278ab22fc743b2eddde Mon Sep 17 00:00:00 2001 From: Kentoku SHIBA Date: Thu, 13 Aug 2020 05:36:23 +0900 Subject: [PATCH 33/70] MDEV-19794 Spider crash with XA --- .../spider/bugfix/include/xa_cmd_deinit.inc | 11 +++ .../spider/bugfix/include/xa_cmd_init.inc | 24 +++++++ .../mysql-test/spider/bugfix/r/xa_cmd.result | 68 ++++++++++++++++++ .../mysql-test/spider/bugfix/t/xa_cmd.cnf | 3 + .../mysql-test/spider/bugfix/t/xa_cmd.test | 69 +++++++++++++++++++ storage/spider/spd_trx.cc | 20 ++++-- 6 files changed, 191 insertions(+), 4 deletions(-) create mode 100644 storage/spider/mysql-test/spider/bugfix/include/xa_cmd_deinit.inc create mode 100644 storage/spider/mysql-test/spider/bugfix/include/xa_cmd_init.inc create mode 100644 storage/spider/mysql-test/spider/bugfix/r/xa_cmd.result create mode 100644 storage/spider/mysql-test/spider/bugfix/t/xa_cmd.cnf create mode 100644 storage/spider/mysql-test/spider/bugfix/t/xa_cmd.test diff --git a/storage/spider/mysql-test/spider/bugfix/include/xa_cmd_deinit.inc b/storage/spider/mysql-test/spider/bugfix/include/xa_cmd_deinit.inc new file mode 100644 index 00000000000..76b7582abfe --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/include/xa_cmd_deinit.inc @@ -0,0 +1,11 @@ +--let $MASTER_1_COMMENT_2_1= $MASTER_1_COMMENT_2_1_BACKUP +--let $CHILD2_1_DROP_TABLES= $CHILD2_1_DROP_TABLES_BACKUP +--let $CHILD2_1_CREATE_TABLES= $CHILD2_1_CREATE_TABLES_BACKUP +--let $CHILD2_1_SELECT_TABLES= $CHILD2_1_SELECT_TABLES_BACKUP +--disable_warnings +--disable_query_log +--disable_result_log +--source ../t/test_deinit.inc +--enable_result_log +--enable_query_log +--enable_warnings diff --git a/storage/spider/mysql-test/spider/bugfix/include/xa_cmd_init.inc b/storage/spider/mysql-test/spider/bugfix/include/xa_cmd_init.inc new file mode 100644 index 00000000000..5c607bd1ff5 --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/include/xa_cmd_init.inc @@ -0,0 +1,24 @@ +--disable_warnings +--disable_query_log +--disable_result_log +--source ../t/test_init.inc +--enable_result_log +--enable_query_log +--enable_warnings +--let $MASTER_1_COMMENT_2_1_BACKUP= $MASTER_1_COMMENT_2_1 +let $MASTER_1_COMMENT_2_1= + COMMENT='table "tbl_a", srv "s_2_1"'; +--let $CHILD2_1_DROP_TABLES_BACKUP= $CHILD2_1_DROP_TABLES +let $CHILD2_1_DROP_TABLES= + DROP TABLE IF EXISTS tbl_a; +--let $CHILD2_1_CREATE_TABLES_BACKUP= $CHILD2_1_CREATE_TABLES +let $CHILD2_1_CREATE_TABLES= + CREATE TABLE tbl_a ( + pkey int NOT NULL, + PRIMARY KEY (pkey) + ) $CHILD2_1_ENGINE $CHILD2_1_CHARSET; +--let $CHILD2_1_SELECT_TABLES_BACKUP= $CHILD2_1_SELECT_TABLES +let $CHILD2_1_SELECT_TABLES= + SELECT pkey FROM tbl_a ORDER BY pkey; +let $CHILD2_1_SELECT_ARGUMENT1= + SELECT argument FROM mysql.general_log WHERE argument LIKE '%insert %'; diff --git a/storage/spider/mysql-test/spider/bugfix/r/xa_cmd.result b/storage/spider/mysql-test/spider/bugfix/r/xa_cmd.result new file mode 100644 index 00000000000..846dc6c737b --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/r/xa_cmd.result @@ -0,0 +1,68 @@ +for master_1 +for child2 +child2_1 +child2_2 +child2_3 +for child3 + +this test is for MDEV-19794 + +drop and create databases +connection master_1; +CREATE DATABASE auto_test_local; +USE auto_test_local; +connection child2_1; +SET @old_log_output = @@global.log_output; +SET GLOBAL log_output = 'TABLE,FILE'; +CREATE DATABASE auto_test_remote; +USE auto_test_remote; + +create table and insert +connection child2_1; +CHILD2_1_CREATE_TABLES +TRUNCATE TABLE mysql.general_log; +connection master_1; +CREATE TABLE tbl_a ( +pkey int NOT NULL, +PRIMARY KEY (pkey) +) MASTER_1_ENGINE MASTER_1_CHARSET MASTER_1_COMMENT_2_1 +connection child2_1; +TRUNCATE TABLE mysql.general_log; +connection master_1; +XA START 'test'; +INSERT INTO tbl_a (pkey) VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +XA END 'test'; +XA PREPARE 'test'; +XA COMMIT 'test'; +connection child2_1; +SELECT argument FROM mysql.general_log WHERE argument LIKE '%insert %'; +argument +insert into `auto_test_remote`.`tbl_a`(`pkey`)values(0),(1),(2),(3),(4),(5),(6),(7),(8),(9) +SELECT argument FROM mysql.general_log WHERE argument LIKE '%insert %' +SELECT pkey FROM tbl_a ORDER BY pkey; +pkey +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 + +deinit +connection master_1; +DROP DATABASE IF EXISTS auto_test_local; +connection child2_1; +DROP DATABASE IF EXISTS auto_test_remote; +SET GLOBAL log_output = @old_log_output; +for master_1 +for child2 +child2_1 +child2_2 +child2_3 +for child3 + +end of test diff --git a/storage/spider/mysql-test/spider/bugfix/t/xa_cmd.cnf b/storage/spider/mysql-test/spider/bugfix/t/xa_cmd.cnf new file mode 100644 index 00000000000..05dfd8a0bce --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/t/xa_cmd.cnf @@ -0,0 +1,3 @@ +!include include/default_mysqld.cnf +!include ../my_1_1.cnf +!include ../my_2_1.cnf diff --git a/storage/spider/mysql-test/spider/bugfix/t/xa_cmd.test b/storage/spider/mysql-test/spider/bugfix/t/xa_cmd.test new file mode 100644 index 00000000000..9ae528071e3 --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/t/xa_cmd.test @@ -0,0 +1,69 @@ +--source ../include/xa_cmd_init.inc +--echo +--echo this test is for MDEV-19794 +--echo +--echo drop and create databases + +--connection master_1 +--disable_warnings +CREATE DATABASE auto_test_local; +USE auto_test_local; + +--connection child2_1 +SET @old_log_output = @@global.log_output; +SET GLOBAL log_output = 'TABLE,FILE'; +CREATE DATABASE auto_test_remote; +USE auto_test_remote; +--enable_warnings + +--echo +--echo create table and insert + +--connection child2_1 +--disable_query_log +echo CHILD2_1_CREATE_TABLES; +eval $CHILD2_1_CREATE_TABLES; +--enable_query_log +TRUNCATE TABLE mysql.general_log; + +--connection master_1 +--disable_query_log +echo CREATE TABLE tbl_a ( + pkey int NOT NULL, + PRIMARY KEY (pkey) +) MASTER_1_ENGINE MASTER_1_CHARSET MASTER_1_COMMENT_2_1; +eval CREATE TABLE tbl_a ( + pkey int NOT NULL, + PRIMARY KEY (pkey) +) $MASTER_1_ENGINE $MASTER_1_CHARSET $MASTER_1_COMMENT_2_1; +--enable_query_log + +--connection child2_1 +TRUNCATE TABLE mysql.general_log; + +--connection master_1 +XA START 'test'; +INSERT INTO tbl_a (pkey) VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +XA END 'test'; +XA PREPARE 'test'; +XA COMMIT 'test'; + +--connection child2_1 +eval $CHILD2_1_SELECT_ARGUMENT1; +eval $CHILD2_1_SELECT_TABLES; + +--echo +--echo deinit +--disable_warnings + +--connection master_1 +DROP DATABASE IF EXISTS auto_test_local; + +--connection child2_1 +DROP DATABASE IF EXISTS auto_test_remote; +SET GLOBAL log_output = @old_log_output; + +--enable_warnings +--source ../include/xa_cmd_deinit.inc +--echo +--echo end of test diff --git a/storage/spider/spd_trx.cc b/storage/spider/spd_trx.cc index b47b75a93cf..4f8296f1d01 100644 --- a/storage/spider/spd_trx.cc +++ b/storage/spider/spd_trx.cc @@ -2228,7 +2228,10 @@ int spider_internal_xa_commit( spider_close_sys_table(thd, table_xa, &open_tables_backup, TRUE); table_xa_opened = FALSE; } - spider_xa_unlock(&trx->internal_xid_state); + if (trx->internal_xa) + { + spider_xa_unlock(&trx->internal_xid_state); + } DBUG_RETURN(0); error: @@ -2238,7 +2241,10 @@ error: spider_close_sys_table(thd, table_xa_member, &open_tables_backup, TRUE); error_in_commit: error_open_table: - spider_xa_unlock(&trx->internal_xid_state); + if (trx->internal_xa) + { + spider_xa_unlock(&trx->internal_xid_state); + } DBUG_RETURN(error_num); } @@ -2464,7 +2470,10 @@ int spider_internal_xa_rollback( spider_close_sys_table(thd, table_xa, &open_tables_backup, TRUE); table_xa_opened = FALSE; } - spider_xa_unlock(&trx->internal_xid_state); + if (trx->internal_xa) + { + spider_xa_unlock(&trx->internal_xid_state); + } DBUG_RETURN(0); error: @@ -2474,7 +2483,10 @@ error: spider_close_sys_table(thd, table_xa_member, &open_tables_backup, TRUE); error_in_rollback: error_open_table: - spider_xa_unlock(&trx->internal_xid_state); + if (trx->internal_xa) + { + spider_xa_unlock(&trx->internal_xid_state); + } DBUG_RETURN(error_num); } From b970363acfae02be4667825501316b412ef6486a Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Mon, 10 Aug 2020 18:23:25 +1000 Subject: [PATCH 34/70] MDEV-23440: mysql_tzinfo_to_sql to use transactions Since MDEV-18778, timezone tables get changed to innodb to allow them to be replicated to other galera nodes. Even without galera, timezone tables could be declared innodb. With the standalone innodb tables, the mysql_tzinfo_to_sql takes approximately 27 seconds. With the transactions enabled in this patch, 1.2 seconds is the approximate load time. While explicit checks for the engine of the time zone tables could be done, or checks against !opt_skip_write_binlog, non-transactional storage engines will just ignore the transactional state without even a warning so its safe to enact globally. Leap seconds are pretty much ignored as they are a single insert statement and have gone out of favour as they have caused MariaDB stalls in the past. --- mysql-test/r/mysql_tzinfo_to_sql_symlink.result | 6 ++++++ mysql-test/suite/wsrep/r/mysql_tzinfo_to_sql_symlink.result | 4 ++++ .../suite/wsrep/r/mysql_tzinfo_to_sql_symlink_skip.result | 4 ++++ sql/tztime.cc | 3 +++ 4 files changed, 17 insertions(+) diff --git a/mysql-test/r/mysql_tzinfo_to_sql_symlink.result b/mysql-test/r/mysql_tzinfo_to_sql_symlink.result index fc9ddce08b1..0de4a5ada95 100644 --- a/mysql-test/r/mysql_tzinfo_to_sql_symlink.result +++ b/mysql-test/r/mysql_tzinfo_to_sql_symlink.result @@ -15,6 +15,7 @@ TRUNCATE TABLE time_zone; TRUNCATE TABLE time_zone_name; TRUNCATE TABLE time_zone_transition; TRUNCATE TABLE time_zone_transition_type; +START TRANSACTION; INSERT INTO time_zone (Use_leap_seconds) VALUES ('N'); SET @time_zone_id= LAST_INSERT_ID(); INSERT INTO time_zone_name (Name, Time_zone_id) VALUES ('GMT', @time_zone_id); @@ -32,6 +33,7 @@ INSERT INTO time_zone_transition_type (Time_zone_id, Transition_type_id, Offset, Warning: Unable to load 'MYSQLTEST_VARDIR/zoneinfo/posix/garbage' as time zone. Skipping it. Warning: Unable to load 'MYSQLTEST_VARDIR/zoneinfo/posix/ignored.tab' as time zone. Skipping it. Warning: Skipping directory 'MYSQLTEST_VARDIR/zoneinfo/posix/posix': to avoid infinite symlink recursion. +COMMIT; ALTER TABLE time_zone_transition ORDER BY Time_zone_id, Transition_time; ALTER TABLE time_zone_transition_type ORDER BY Time_zone_id, Transition_type_id; \d | @@ -57,6 +59,7 @@ TRUNCATE TABLE time_zone; TRUNCATE TABLE time_zone_name; TRUNCATE TABLE time_zone_transition; TRUNCATE TABLE time_zone_transition_type; +START TRANSACTION; INSERT INTO time_zone (Use_leap_seconds) VALUES ('N'); SET @time_zone_id= LAST_INSERT_ID(); INSERT INTO time_zone_name (Name, Time_zone_id) VALUES ('GMT', @time_zone_id); @@ -71,6 +74,7 @@ INSERT INTO time_zone_transition_type (Time_zone_id, Transition_type_id, Offset, (@time_zone_id, 0, 0, 0, 'GMT') ; Warning: Unable to load 'MYSQLTEST_VARDIR/zoneinfo/posix/garbage' as time zone. Skipping it. +COMMIT; ALTER TABLE time_zone_transition ORDER BY Time_zone_id, Transition_time; ALTER TABLE time_zone_transition_type ORDER BY Time_zone_id, Transition_type_id; \d | @@ -142,6 +146,8 @@ TRUNCATE TABLE time_zone; TRUNCATE TABLE time_zone_name; TRUNCATE TABLE time_zone_transition; TRUNCATE TABLE time_zone_transition_type; +START TRANSACTION; +COMMIT; ALTER TABLE time_zone_transition ORDER BY Time_zone_id, Transition_time; ALTER TABLE time_zone_transition_type ORDER BY Time_zone_id, Transition_type_id; \d | diff --git a/mysql-test/suite/wsrep/r/mysql_tzinfo_to_sql_symlink.result b/mysql-test/suite/wsrep/r/mysql_tzinfo_to_sql_symlink.result index 1e6ebbbd34d..d146b7187e4 100644 --- a/mysql-test/suite/wsrep/r/mysql_tzinfo_to_sql_symlink.result +++ b/mysql-test/suite/wsrep/r/mysql_tzinfo_to_sql_symlink.result @@ -15,6 +15,7 @@ TRUNCATE TABLE time_zone; TRUNCATE TABLE time_zone_name; TRUNCATE TABLE time_zone_transition; TRUNCATE TABLE time_zone_transition_type; +START TRANSACTION; INSERT INTO time_zone (Use_leap_seconds) VALUES ('N'); SET @time_zone_id= LAST_INSERT_ID(); INSERT INTO time_zone_name (Name, Time_zone_id) VALUES ('GMT', @time_zone_id); @@ -32,6 +33,7 @@ INSERT INTO time_zone_transition_type (Time_zone_id, Transition_type_id, Offset, Warning: Unable to load 'MYSQLTEST_VARDIR/zoneinfo/posix/garbage' as time zone. Skipping it. Warning: Unable to load 'MYSQLTEST_VARDIR/zoneinfo/posix/ignored.tab' as time zone. Skipping it. Warning: Skipping directory 'MYSQLTEST_VARDIR/zoneinfo/posix/posix': to avoid infinite symlink recursion. +COMMIT; ALTER TABLE time_zone_transition ORDER BY Time_zone_id, Transition_time; ALTER TABLE time_zone_transition_type ORDER BY Time_zone_id, Transition_type_id; \d | @@ -57,6 +59,7 @@ TRUNCATE TABLE time_zone; TRUNCATE TABLE time_zone_name; TRUNCATE TABLE time_zone_transition; TRUNCATE TABLE time_zone_transition_type; +START TRANSACTION; INSERT INTO time_zone (Use_leap_seconds) VALUES ('N'); SET @time_zone_id= LAST_INSERT_ID(); INSERT INTO time_zone_name (Name, Time_zone_id) VALUES ('GMT', @time_zone_id); @@ -71,6 +74,7 @@ INSERT INTO time_zone_transition_type (Time_zone_id, Transition_type_id, Offset, (@time_zone_id, 0, 0, 0, 'GMT') ; Warning: Unable to load 'MYSQLTEST_VARDIR/zoneinfo/posix/garbage' as time zone. Skipping it. +COMMIT; ALTER TABLE time_zone_transition ORDER BY Time_zone_id, Transition_time; ALTER TABLE time_zone_transition_type ORDER BY Time_zone_id, Transition_type_id; \d | diff --git a/mysql-test/suite/wsrep/r/mysql_tzinfo_to_sql_symlink_skip.result b/mysql-test/suite/wsrep/r/mysql_tzinfo_to_sql_symlink_skip.result index 85c4d858be2..aff02cb413e 100644 --- a/mysql-test/suite/wsrep/r/mysql_tzinfo_to_sql_symlink_skip.result +++ b/mysql-test/suite/wsrep/r/mysql_tzinfo_to_sql_symlink_skip.result @@ -9,6 +9,7 @@ TRUNCATE TABLE time_zone; TRUNCATE TABLE time_zone_name; TRUNCATE TABLE time_zone_transition; TRUNCATE TABLE time_zone_transition_type; +START TRANSACTION; INSERT INTO time_zone (Use_leap_seconds) VALUES ('N'); SET @time_zone_id= LAST_INSERT_ID(); INSERT INTO time_zone_name (Name, Time_zone_id) VALUES ('GMT', @time_zone_id); @@ -26,6 +27,7 @@ INSERT INTO time_zone_transition_type (Time_zone_id, Transition_type_id, Offset, Warning: Unable to load 'MYSQLTEST_VARDIR/zoneinfo/posix/garbage' as time zone. Skipping it. Warning: Unable to load 'MYSQLTEST_VARDIR/zoneinfo/posix/ignored.tab' as time zone. Skipping it. Warning: Skipping directory 'MYSQLTEST_VARDIR/zoneinfo/posix/posix': to avoid infinite symlink recursion. +COMMIT; ALTER TABLE time_zone_transition ORDER BY Time_zone_id, Transition_time; ALTER TABLE time_zone_transition_type ORDER BY Time_zone_id, Transition_type_id; # Silent run @@ -36,6 +38,7 @@ TRUNCATE TABLE time_zone; TRUNCATE TABLE time_zone_name; TRUNCATE TABLE time_zone_transition; TRUNCATE TABLE time_zone_transition_type; +START TRANSACTION; INSERT INTO time_zone (Use_leap_seconds) VALUES ('N'); SET @time_zone_id= LAST_INSERT_ID(); INSERT INTO time_zone_name (Name, Time_zone_id) VALUES ('GMT', @time_zone_id); @@ -50,6 +53,7 @@ INSERT INTO time_zone_transition_type (Time_zone_id, Transition_type_id, Offset, (@time_zone_id, 0, 0, 0, 'GMT') ; Warning: Unable to load 'MYSQLTEST_VARDIR/zoneinfo/posix/garbage' as time zone. Skipping it. +COMMIT; ALTER TABLE time_zone_transition ORDER BY Time_zone_id, Transition_time; ALTER TABLE time_zone_transition_type ORDER BY Time_zone_id, Transition_type_id; # diff --git a/sql/tztime.cc b/sql/tztime.cc index 960dde38237..fa5a24d3c8a 100644 --- a/sql/tztime.cc +++ b/sql/tztime.cc @@ -2748,9 +2748,11 @@ main(int argc, char **argv) printf("TRUNCATE TABLE time_zone_name;\n"); printf("TRUNCATE TABLE time_zone_transition;\n"); printf("TRUNCATE TABLE time_zone_transition_type;\n"); + printf("START TRANSACTION;\n"); if (scan_tz_dir(root_name_end, 0, opt_verbose)) { + printf("ROLLBACK;\n"); fflush(stdout); fprintf(stderr, "There were fatal errors during processing " @@ -2758,6 +2760,7 @@ main(int argc, char **argv) return 1; } + printf("COMMIT;\n"); printf("ALTER TABLE time_zone_transition " "ORDER BY Time_zone_id, Transition_time;\n"); printf("ALTER TABLE time_zone_transition_type " From 010fd61a5fd82d8dac44e934e0c6cbfeeef1abe1 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Sat, 15 Aug 2020 17:55:01 +0200 Subject: [PATCH 35/70] MDEV-23489 Windows zip files 10.4.14 have an embryonic data folder Fix : Do not INSTALL anything with cmake from data folder. --- sql/CMakeLists.txt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt index 1d3bf837237..5e66da6f5ab 100644 --- a/sql/CMakeLists.txt +++ b/sql/CMakeLists.txt @@ -407,10 +407,6 @@ ADD_CUSTOM_TARGET(distclean IF(INSTALL_LAYOUT STREQUAL "STANDALONE") -# Copy db.opt into data/test/ -SET(DBOPT_FILE ${CMAKE_SOURCE_DIR}/support-files/db.opt ) -INSTALL(FILES ${DBOPT_FILE} DESTINATION data/test COMPONENT DataFiles) - # Install initial database on windows IF(WIN32 AND TARGET mysqld AND NOT CMAKE_CROSSCOMPILING) From 90c8d773ed0ea7de5e735e836e1e33a190711f17 Mon Sep 17 00:00:00 2001 From: Eugene Kosov Date: Tue, 4 Aug 2020 10:13:35 +0300 Subject: [PATCH 36/70] MDEV-21251 CHECK TABLE fails to check info_bits of records btr_validate_index(): do not stop checking after some level failed. That way it'll become possible to see errors in leaf pages even when uppers layers are corrupted too. page_validate(): check info_bits and status_bits more --- storage/innobase/btr/btr0btr.cc | 1 - storage/innobase/page/page0page.cc | 57 ++++++++++++++++++++++++++---- 2 files changed, 51 insertions(+), 7 deletions(-) diff --git a/storage/innobase/btr/btr0btr.cc b/storage/innobase/btr/btr0btr.cc index 786755cb1ab..b29c26b4842 100644 --- a/storage/innobase/btr/btr0btr.cc +++ b/storage/innobase/btr/btr0btr.cc @@ -5260,7 +5260,6 @@ btr_validate_index( if (!btr_validate_level(index, trx, n - i, lockout)) { err = DB_CORRUPTION; - break; } } diff --git a/storage/innobase/page/page0page.cc b/storage/innobase/page/page0page.cc index aab4fbe5d8b..38796d8cb8d 100644 --- a/storage/innobase/page/page0page.cc +++ b/storage/innobase/page/page0page.cc @@ -2476,6 +2476,7 @@ wrong_page_type: /* Validate the record list in a loop checking also that it is consistent with the directory. */ ulint count = 0, data_size = 0, own_count = 1, slot_no = 0; + ulint info_bits; slot_no = 0; slot = page_dir_get_nth_slot(page, slot_no); @@ -2499,9 +2500,16 @@ wrong_page_type: goto next_rec; } + info_bits = rec_get_info_bits(rec, page_is_comp(page)); + if (info_bits + & ~(REC_INFO_MIN_REC_FLAG | REC_INFO_DELETED_FLAG)) { + ib::error() << "info_bits has an incorrect value " + << info_bits; + ret = false; + } + if (rec == first_rec) { - if ((rec_get_info_bits(rec, page_is_comp(page)) - & REC_INFO_MIN_REC_FLAG)) { + if (info_bits & REC_INFO_MIN_REC_FLAG) { if (page_has_prev(page)) { ib::error() << "REC_INFO_MIN_REC_FLAG " "is set on non-left page"; @@ -2512,8 +2520,7 @@ wrong_page_type: ib::error() << "REC_INFO_MIN_REC_FLAG " "is set in a leaf-page record"; ret = false; - } else if (rec_get_deleted_flag( - rec, page_is_comp(page))) { + } else if (info_bits & REC_INFO_DELETED_FLAG) { /* If this were a 10.4 metadata record for index->table->instant we should not get here in 10.3, because @@ -2529,13 +2536,51 @@ wrong_page_type: ib::error() << "Metadata record is missing"; ret = false; } - } else if (rec_get_info_bits(rec, page_is_comp(page)) - & REC_INFO_MIN_REC_FLAG) { + } else if (info_bits & REC_INFO_MIN_REC_FLAG) { ib::error() << "REC_INFO_MIN_REC_FLAG record is not " "first in page"; ret = false; } + if (page_is_comp(page)) { + const rec_comp_status_t status = rec_get_status(rec); + if (status != REC_STATUS_ORDINARY + && status != REC_STATUS_NODE_PTR + && status != REC_STATUS_INFIMUM + && status != REC_STATUS_SUPREMUM + && status != REC_STATUS_COLUMNS_ADDED) { + ib::error() << "impossible record status " + << status; + ret = false; + } else if (page_rec_is_infimum(rec)) { + if (status != REC_STATUS_INFIMUM) { + ib::error() + << "infimum record has status " + << status; + ret = false; + } + } else if (page_rec_is_supremum(rec)) { + if (status != REC_STATUS_SUPREMUM) { + ib::error() << "supremum record has " + "status " + << status; + ret = false; + } + } else if (!page_is_leaf(page)) { + if (status != REC_STATUS_NODE_PTR) { + ib::error() << "node ptr record has " + "status " + << status; + ret = false; + } + } else if (!index->is_instant() + && status == REC_STATUS_COLUMNS_ADDED) { + ib::error() << "instantly added record in a " + "non-instant index"; + ret = false; + } + } + /* Check that the records are in the ascending order */ if (count >= PAGE_HEAP_NO_USER_LOW && !page_rec_is_supremum(rec)) { From 314a90e12b72a4c889278847b8d2a8c3f21f41e3 Mon Sep 17 00:00:00 2001 From: Kentoku SHIBA Date: Mon, 17 Aug 2020 09:45:03 +0900 Subject: [PATCH 37/70] MDEV-20827 Wrong param parsing in spider_direct_sql() when param contain comma --- .../direct_sql_with_comma_pwd_deinit.inc | 9 ++ .../direct_sql_with_comma_pwd_init.inc | 11 +++ .../bugfix/r/direct_sql_with_comma_pwd.result | 37 ++++++++ .../bugfix/t/direct_sql_with_comma_pwd.cnf | 3 + .../bugfix/t/direct_sql_with_comma_pwd.test | 35 ++++++++ storage/spider/spd_copy_tables.cc | 21 +++-- storage/spider/spd_direct_sql.cc | 21 +++-- storage/spider/spd_table.cc | 21 +++-- storage/spider/spd_table.h | 88 +++++++++++++++++++ 9 files changed, 213 insertions(+), 33 deletions(-) create mode 100644 storage/spider/mysql-test/spider/bugfix/include/direct_sql_with_comma_pwd_deinit.inc create mode 100644 storage/spider/mysql-test/spider/bugfix/include/direct_sql_with_comma_pwd_init.inc create mode 100644 storage/spider/mysql-test/spider/bugfix/r/direct_sql_with_comma_pwd.result create mode 100644 storage/spider/mysql-test/spider/bugfix/t/direct_sql_with_comma_pwd.cnf create mode 100644 storage/spider/mysql-test/spider/bugfix/t/direct_sql_with_comma_pwd.test diff --git a/storage/spider/mysql-test/spider/bugfix/include/direct_sql_with_comma_pwd_deinit.inc b/storage/spider/mysql-test/spider/bugfix/include/direct_sql_with_comma_pwd_deinit.inc new file mode 100644 index 00000000000..27682e43441 --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/include/direct_sql_with_comma_pwd_deinit.inc @@ -0,0 +1,9 @@ +--connection child2_1 +DROP USER tu@'%'; +--disable_warnings +--disable_query_log +--disable_result_log +--source ../t/test_deinit.inc +--enable_result_log +--enable_query_log +--enable_warnings diff --git a/storage/spider/mysql-test/spider/bugfix/include/direct_sql_with_comma_pwd_init.inc b/storage/spider/mysql-test/spider/bugfix/include/direct_sql_with_comma_pwd_init.inc new file mode 100644 index 00000000000..c87af2d02e4 --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/include/direct_sql_with_comma_pwd_init.inc @@ -0,0 +1,11 @@ +--disable_warnings +--disable_query_log +--disable_result_log +--source ../t/test_init.inc +--enable_result_log +--enable_query_log +--enable_warnings +let $DIRECT_SQL_COMMAND= + SELECT spider_direct_sql('SELECT 22', 'tmp_a', 'srv "s_2_1", database "test", password "pass,1234", user "tu"'); +--connection child2_1 +GRANT ALL ON *.* TO tu@'%' IDENTIFIED BY 'pass,1234'; diff --git a/storage/spider/mysql-test/spider/bugfix/r/direct_sql_with_comma_pwd.result b/storage/spider/mysql-test/spider/bugfix/r/direct_sql_with_comma_pwd.result new file mode 100644 index 00000000000..b485d645619 --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/r/direct_sql_with_comma_pwd.result @@ -0,0 +1,37 @@ +for master_1 +for child2 +child2_1 +child2_2 +child2_3 +for child3 +connection child2_1; +GRANT ALL ON *.* TO tu@'%' IDENTIFIED BY 'pass,1234'; + +drop and create databases +connection master_1; +CREATE DATABASE auto_test_local; +USE auto_test_local; +CREATE TEMPORARY TABLE tmp_a ( +pkey int NOT NULL, +PRIMARY KEY (pkey) +) MASTER_1_ENGINE2 +SELECT spider_direct_sql('SELECT 22', 'tmp_a', 'srv "s_2_1", database "test", password "pass,1234", user "tu"'); +spider_direct_sql('SELECT 22', 'tmp_a', 'srv "s_2_1", database "test", password "pass,1234", user "tu"') +1 +SELECT pkey FROM tmp_a; +pkey +22 + +deinit +connection master_1; +DROP DATABASE IF EXISTS auto_test_local; +connection child2_1; +DROP USER tu@'%'; +for master_1 +for child2 +child2_1 +child2_2 +child2_3 +for child3 + +end of test diff --git a/storage/spider/mysql-test/spider/bugfix/t/direct_sql_with_comma_pwd.cnf b/storage/spider/mysql-test/spider/bugfix/t/direct_sql_with_comma_pwd.cnf new file mode 100644 index 00000000000..05dfd8a0bce --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/t/direct_sql_with_comma_pwd.cnf @@ -0,0 +1,3 @@ +!include include/default_mysqld.cnf +!include ../my_1_1.cnf +!include ../my_2_1.cnf diff --git a/storage/spider/mysql-test/spider/bugfix/t/direct_sql_with_comma_pwd.test b/storage/spider/mysql-test/spider/bugfix/t/direct_sql_with_comma_pwd.test new file mode 100644 index 00000000000..0b7d51190a7 --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/t/direct_sql_with_comma_pwd.test @@ -0,0 +1,35 @@ +--source ../include/direct_sql_with_comma_pwd_init.inc +--echo +--echo drop and create databases + +--connection master_1 +--disable_warnings +CREATE DATABASE auto_test_local; +USE auto_test_local; +--enable_warnings + +--disable_query_log +echo CREATE TEMPORARY TABLE tmp_a ( + pkey int NOT NULL, + PRIMARY KEY (pkey) +) MASTER_1_ENGINE2; +eval CREATE TEMPORARY TABLE tmp_a ( + pkey int NOT NULL, + PRIMARY KEY (pkey) +) $MASTER_1_ENGINE2; +--enable_query_log + +eval $DIRECT_SQL_COMMAND; +SELECT pkey FROM tmp_a; + +--echo +--echo deinit +--disable_warnings + +--connection master_1 +DROP DATABASE IF EXISTS auto_test_local; + +--enable_warnings +--source ../include/direct_sql_with_comma_pwd_deinit.inc +--echo +--echo end of test diff --git a/storage/spider/spd_copy_tables.cc b/storage/spider/spd_copy_tables.cc index ed08cb8a6af..28bc5464e13 100644 --- a/storage/spider/spd_copy_tables.cc +++ b/storage/spider/spd_copy_tables.cc @@ -217,7 +217,7 @@ int spider_udf_parse_copy_tables_param( ) { int error_num = 0; char *param_string = NULL; - char *sprit_ptr[2]; + char *sprit_ptr; char *tmp_ptr, *tmp_ptr2, *start_ptr; int title_length; SPIDER_PARAM_STRING_PARSE param_string_parse; @@ -244,23 +244,17 @@ int spider_udf_parse_copy_tables_param( } DBUG_PRINT("info",("spider param_string=%s", param_string)); - sprit_ptr[0] = param_string; + sprit_ptr = param_string; param_string_parse.init(param_string, ER_SPIDER_INVALID_UDF_PARAM_NUM); - while (sprit_ptr[0]) + while (sprit_ptr) { - if ((sprit_ptr[1] = strchr(sprit_ptr[0], ','))) - { - *sprit_ptr[1] = '\0'; - sprit_ptr[1]++; - } - tmp_ptr = sprit_ptr[0]; - sprit_ptr[0] = sprit_ptr[1]; + tmp_ptr = sprit_ptr; while (*tmp_ptr == ' ' || *tmp_ptr == '\r' || *tmp_ptr == '\n' || *tmp_ptr == '\t') tmp_ptr++; if (*tmp_ptr == '\0') - continue; + break; title_length = 0; start_ptr = tmp_ptr; @@ -273,6 +267,11 @@ int spider_udf_parse_copy_tables_param( start_ptr++; } param_string_parse.set_param_title(tmp_ptr, tmp_ptr + title_length); + if ((error_num = param_string_parse.get_next_parameter_head( + start_ptr, &sprit_ptr))) + { + goto error; + } switch (title_length) { diff --git a/storage/spider/spd_direct_sql.cc b/storage/spider/spd_direct_sql.cc index e14e8d95363..1486cbece9e 100644 --- a/storage/spider/spd_direct_sql.cc +++ b/storage/spider/spd_direct_sql.cc @@ -1172,7 +1172,7 @@ int spider_udf_parse_direct_sql_param( ) { int error_num = 0, roop_count; char *param_string = NULL; - char *sprit_ptr[2]; + char *sprit_ptr; char *tmp_ptr, *tmp_ptr2, *start_ptr; int title_length; SPIDER_PARAM_STRING_PARSE param_string_parse; @@ -1211,23 +1211,17 @@ int spider_udf_parse_direct_sql_param( } DBUG_PRINT("info",("spider param_string=%s", param_string)); - sprit_ptr[0] = param_string; + sprit_ptr = param_string; param_string_parse.init(param_string, ER_SPIDER_INVALID_UDF_PARAM_NUM); - while (sprit_ptr[0]) + while (sprit_ptr) { - if ((sprit_ptr[1] = strchr(sprit_ptr[0], ','))) - { - *sprit_ptr[1] = '\0'; - sprit_ptr[1]++; - } - tmp_ptr = sprit_ptr[0]; - sprit_ptr[0] = sprit_ptr[1]; + tmp_ptr = sprit_ptr; while (*tmp_ptr == ' ' || *tmp_ptr == '\r' || *tmp_ptr == '\n' || *tmp_ptr == '\t') tmp_ptr++; if (*tmp_ptr == '\0') - continue; + break; title_length = 0; start_ptr = tmp_ptr; @@ -1240,6 +1234,11 @@ int spider_udf_parse_direct_sql_param( start_ptr++; } param_string_parse.set_param_title(tmp_ptr, tmp_ptr + title_length); + if ((error_num = param_string_parse.get_next_parameter_head( + start_ptr, &sprit_ptr))) + { + goto error; + } switch (title_length) { diff --git a/storage/spider/spd_table.cc b/storage/spider/spd_table.cc index e77e1a9261b..1f0dcb82e8f 100644 --- a/storage/spider/spd_table.cc +++ b/storage/spider/spd_table.cc @@ -2053,7 +2053,7 @@ int spider_parse_connect_info( ) { int error_num = 0; char *connect_string = NULL; - char *sprit_ptr[2]; + char *sprit_ptr; char *tmp_ptr, *tmp_ptr2, *start_ptr; int roop_count; int title_length; @@ -2247,23 +2247,17 @@ int spider_parse_connect_info( break; } - sprit_ptr[0] = connect_string; + sprit_ptr = connect_string; connect_string_parse.init(connect_string, ER_SPIDER_INVALID_CONNECT_INFO_NUM); - while (sprit_ptr[0]) + while (sprit_ptr) { - if ((sprit_ptr[1] = strchr(sprit_ptr[0], ','))) - { - *sprit_ptr[1] = '\0'; - sprit_ptr[1]++; - } - tmp_ptr = sprit_ptr[0]; - sprit_ptr[0] = sprit_ptr[1]; + tmp_ptr = sprit_ptr; while (*tmp_ptr == ' ' || *tmp_ptr == '\r' || *tmp_ptr == '\n' || *tmp_ptr == '\t') tmp_ptr++; if (*tmp_ptr == '\0') - continue; + break; title_length = 0; start_ptr = tmp_ptr; @@ -2276,6 +2270,11 @@ int spider_parse_connect_info( start_ptr++; } connect_string_parse.set_param_title(tmp_ptr, tmp_ptr + title_length); + if ((error_num = connect_string_parse.get_next_parameter_head( + start_ptr, &sprit_ptr))) + { + goto error; + } switch (title_length) { diff --git a/storage/spider/spd_table.h b/storage/spider/spd_table.h index c03f15a5a88..c57f4e4d4c0 100644 --- a/storage/spider/spd_table.h +++ b/storage/spider/spd_table.h @@ -180,6 +180,94 @@ typedef struct st_spider_param_string_parse DBUG_RETURN(error_num); } + inline int get_next_parameter_head(char *st, char **nx) + { + DBUG_ENTER("get_next_parameter_head"); + char *sq = strchr(st, '\''); + char *dq = strchr(st, '"'); + if (!sq && !dq) + { + DBUG_RETURN(print_param_error()); + } + else if (!sq || sq > dq) + { + while (1) + { + ++dq; + if (*dq == '\\') + { + ++dq; + } + else if (*dq == '"') + { + break; + } + else if (*dq == '\0') + { + DBUG_RETURN(print_param_error()); + } + } + while (1) + { + ++dq; + if (*dq == '\0') + { + *nx = dq; + break; + } + else if (*dq == ',') + { + *dq = '\0'; + *nx = dq + 1; + break; + } + else if (*dq != ' ' && *dq != '\r' && *dq != '\n' && *dq != '\t') + { + DBUG_RETURN(print_param_error()); + } + } + } + else + { + while (1) + { + ++sq; + if (*sq == '\\') + { + ++sq; + } + else if (*sq == '\'') + { + break; + } + else if (*sq == '\0') + { + DBUG_RETURN(print_param_error()); + } + } + while (1) + { + ++sq; + if (*sq == '\0') + { + *nx = sq; + break; + } + else if (*sq == ',') + { + *sq = '\0'; + *nx = sq + 1; + break; + } + else if (*sq != ' ' && *sq != '\r' && *sq != '\n' && *sq != '\t') + { + DBUG_RETURN(print_param_error()); + } + } + } + DBUG_RETURN(0); + } + /** Restore the current parameter's input delimiter characters in the parameter string. They were NULLed during parameter parsing. From 5c8a1249ddeff70a3ffb6ce963a6eed3d55d4510 Mon Sep 17 00:00:00 2001 From: Kentoku SHIBA Date: Mon, 17 Aug 2020 09:45:03 +0900 Subject: [PATCH 38/70] MDEV-20827 Wrong param parsing in spider_direct_sql() when param contain comma --- .../direct_sql_with_comma_pwd_deinit.inc | 9 ++ .../direct_sql_with_comma_pwd_init.inc | 11 +++ .../bugfix/r/direct_sql_with_comma_pwd.result | 37 ++++++++ .../bugfix/t/direct_sql_with_comma_pwd.cnf | 3 + .../bugfix/t/direct_sql_with_comma_pwd.test | 35 ++++++++ storage/spider/spd_copy_tables.cc | 21 +++-- storage/spider/spd_direct_sql.cc | 21 +++-- storage/spider/spd_table.cc | 21 +++-- storage/spider/spd_table.h | 88 +++++++++++++++++++ 9 files changed, 213 insertions(+), 33 deletions(-) create mode 100644 storage/spider/mysql-test/spider/bugfix/include/direct_sql_with_comma_pwd_deinit.inc create mode 100644 storage/spider/mysql-test/spider/bugfix/include/direct_sql_with_comma_pwd_init.inc create mode 100644 storage/spider/mysql-test/spider/bugfix/r/direct_sql_with_comma_pwd.result create mode 100644 storage/spider/mysql-test/spider/bugfix/t/direct_sql_with_comma_pwd.cnf create mode 100644 storage/spider/mysql-test/spider/bugfix/t/direct_sql_with_comma_pwd.test diff --git a/storage/spider/mysql-test/spider/bugfix/include/direct_sql_with_comma_pwd_deinit.inc b/storage/spider/mysql-test/spider/bugfix/include/direct_sql_with_comma_pwd_deinit.inc new file mode 100644 index 00000000000..27682e43441 --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/include/direct_sql_with_comma_pwd_deinit.inc @@ -0,0 +1,9 @@ +--connection child2_1 +DROP USER tu@'%'; +--disable_warnings +--disable_query_log +--disable_result_log +--source ../t/test_deinit.inc +--enable_result_log +--enable_query_log +--enable_warnings diff --git a/storage/spider/mysql-test/spider/bugfix/include/direct_sql_with_comma_pwd_init.inc b/storage/spider/mysql-test/spider/bugfix/include/direct_sql_with_comma_pwd_init.inc new file mode 100644 index 00000000000..c87af2d02e4 --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/include/direct_sql_with_comma_pwd_init.inc @@ -0,0 +1,11 @@ +--disable_warnings +--disable_query_log +--disable_result_log +--source ../t/test_init.inc +--enable_result_log +--enable_query_log +--enable_warnings +let $DIRECT_SQL_COMMAND= + SELECT spider_direct_sql('SELECT 22', 'tmp_a', 'srv "s_2_1", database "test", password "pass,1234", user "tu"'); +--connection child2_1 +GRANT ALL ON *.* TO tu@'%' IDENTIFIED BY 'pass,1234'; diff --git a/storage/spider/mysql-test/spider/bugfix/r/direct_sql_with_comma_pwd.result b/storage/spider/mysql-test/spider/bugfix/r/direct_sql_with_comma_pwd.result new file mode 100644 index 00000000000..b485d645619 --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/r/direct_sql_with_comma_pwd.result @@ -0,0 +1,37 @@ +for master_1 +for child2 +child2_1 +child2_2 +child2_3 +for child3 +connection child2_1; +GRANT ALL ON *.* TO tu@'%' IDENTIFIED BY 'pass,1234'; + +drop and create databases +connection master_1; +CREATE DATABASE auto_test_local; +USE auto_test_local; +CREATE TEMPORARY TABLE tmp_a ( +pkey int NOT NULL, +PRIMARY KEY (pkey) +) MASTER_1_ENGINE2 +SELECT spider_direct_sql('SELECT 22', 'tmp_a', 'srv "s_2_1", database "test", password "pass,1234", user "tu"'); +spider_direct_sql('SELECT 22', 'tmp_a', 'srv "s_2_1", database "test", password "pass,1234", user "tu"') +1 +SELECT pkey FROM tmp_a; +pkey +22 + +deinit +connection master_1; +DROP DATABASE IF EXISTS auto_test_local; +connection child2_1; +DROP USER tu@'%'; +for master_1 +for child2 +child2_1 +child2_2 +child2_3 +for child3 + +end of test diff --git a/storage/spider/mysql-test/spider/bugfix/t/direct_sql_with_comma_pwd.cnf b/storage/spider/mysql-test/spider/bugfix/t/direct_sql_with_comma_pwd.cnf new file mode 100644 index 00000000000..05dfd8a0bce --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/t/direct_sql_with_comma_pwd.cnf @@ -0,0 +1,3 @@ +!include include/default_mysqld.cnf +!include ../my_1_1.cnf +!include ../my_2_1.cnf diff --git a/storage/spider/mysql-test/spider/bugfix/t/direct_sql_with_comma_pwd.test b/storage/spider/mysql-test/spider/bugfix/t/direct_sql_with_comma_pwd.test new file mode 100644 index 00000000000..0b7d51190a7 --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/t/direct_sql_with_comma_pwd.test @@ -0,0 +1,35 @@ +--source ../include/direct_sql_with_comma_pwd_init.inc +--echo +--echo drop and create databases + +--connection master_1 +--disable_warnings +CREATE DATABASE auto_test_local; +USE auto_test_local; +--enable_warnings + +--disable_query_log +echo CREATE TEMPORARY TABLE tmp_a ( + pkey int NOT NULL, + PRIMARY KEY (pkey) +) MASTER_1_ENGINE2; +eval CREATE TEMPORARY TABLE tmp_a ( + pkey int NOT NULL, + PRIMARY KEY (pkey) +) $MASTER_1_ENGINE2; +--enable_query_log + +eval $DIRECT_SQL_COMMAND; +SELECT pkey FROM tmp_a; + +--echo +--echo deinit +--disable_warnings + +--connection master_1 +DROP DATABASE IF EXISTS auto_test_local; + +--enable_warnings +--source ../include/direct_sql_with_comma_pwd_deinit.inc +--echo +--echo end of test diff --git a/storage/spider/spd_copy_tables.cc b/storage/spider/spd_copy_tables.cc index 13c53220b16..319b02462b1 100644 --- a/storage/spider/spd_copy_tables.cc +++ b/storage/spider/spd_copy_tables.cc @@ -216,7 +216,7 @@ int spider_udf_parse_copy_tables_param( ) { int error_num = 0; char *param_string = NULL; - char *sprit_ptr[2]; + char *sprit_ptr; char *tmp_ptr, *tmp_ptr2, *start_ptr; int title_length; SPIDER_PARAM_STRING_PARSE param_string_parse; @@ -243,23 +243,17 @@ int spider_udf_parse_copy_tables_param( } DBUG_PRINT("info",("spider param_string=%s", param_string)); - sprit_ptr[0] = param_string; + sprit_ptr = param_string; param_string_parse.init(param_string, ER_SPIDER_INVALID_UDF_PARAM_NUM); - while (sprit_ptr[0]) + while (sprit_ptr) { - if ((sprit_ptr[1] = strchr(sprit_ptr[0], ','))) - { - *sprit_ptr[1] = '\0'; - sprit_ptr[1]++; - } - tmp_ptr = sprit_ptr[0]; - sprit_ptr[0] = sprit_ptr[1]; + tmp_ptr = sprit_ptr; while (*tmp_ptr == ' ' || *tmp_ptr == '\r' || *tmp_ptr == '\n' || *tmp_ptr == '\t') tmp_ptr++; if (*tmp_ptr == '\0') - continue; + break; title_length = 0; start_ptr = tmp_ptr; @@ -272,6 +266,11 @@ int spider_udf_parse_copy_tables_param( start_ptr++; } param_string_parse.set_param_title(tmp_ptr, tmp_ptr + title_length); + if ((error_num = param_string_parse.get_next_parameter_head( + start_ptr, &sprit_ptr))) + { + goto error; + } switch (title_length) { diff --git a/storage/spider/spd_direct_sql.cc b/storage/spider/spd_direct_sql.cc index 7237d0877a7..09f23046455 100644 --- a/storage/spider/spd_direct_sql.cc +++ b/storage/spider/spd_direct_sql.cc @@ -1115,7 +1115,7 @@ int spider_udf_parse_direct_sql_param( ) { int error_num = 0, roop_count; char *param_string = NULL; - char *sprit_ptr[2]; + char *sprit_ptr; char *tmp_ptr, *tmp_ptr2, *start_ptr; int title_length; SPIDER_PARAM_STRING_PARSE param_string_parse; @@ -1154,23 +1154,17 @@ int spider_udf_parse_direct_sql_param( } DBUG_PRINT("info",("spider param_string=%s", param_string)); - sprit_ptr[0] = param_string; + sprit_ptr = param_string; param_string_parse.init(param_string, ER_SPIDER_INVALID_UDF_PARAM_NUM); - while (sprit_ptr[0]) + while (sprit_ptr) { - if ((sprit_ptr[1] = strchr(sprit_ptr[0], ','))) - { - *sprit_ptr[1] = '\0'; - sprit_ptr[1]++; - } - tmp_ptr = sprit_ptr[0]; - sprit_ptr[0] = sprit_ptr[1]; + tmp_ptr = sprit_ptr; while (*tmp_ptr == ' ' || *tmp_ptr == '\r' || *tmp_ptr == '\n' || *tmp_ptr == '\t') tmp_ptr++; if (*tmp_ptr == '\0') - continue; + break; title_length = 0; start_ptr = tmp_ptr; @@ -1183,6 +1177,11 @@ int spider_udf_parse_direct_sql_param( start_ptr++; } param_string_parse.set_param_title(tmp_ptr, tmp_ptr + title_length); + if ((error_num = param_string_parse.get_next_parameter_head( + start_ptr, &sprit_ptr))) + { + goto error; + } switch (title_length) { diff --git a/storage/spider/spd_table.cc b/storage/spider/spd_table.cc index ec7549a38c7..88effd38717 100644 --- a/storage/spider/spd_table.cc +++ b/storage/spider/spd_table.cc @@ -1978,7 +1978,7 @@ int spider_parse_connect_info( ) { int error_num = 0; char *connect_string = NULL; - char *sprit_ptr[2]; + char *sprit_ptr; char *tmp_ptr, *tmp_ptr2, *start_ptr; int roop_count; int title_length; @@ -2171,23 +2171,17 @@ int spider_parse_connect_info( break; } - sprit_ptr[0] = connect_string; + sprit_ptr = connect_string; connect_string_parse.init(connect_string, ER_SPIDER_INVALID_CONNECT_INFO_NUM); - while (sprit_ptr[0]) + while (sprit_ptr) { - if ((sprit_ptr[1] = strchr(sprit_ptr[0], ','))) - { - *sprit_ptr[1] = '\0'; - sprit_ptr[1]++; - } - tmp_ptr = sprit_ptr[0]; - sprit_ptr[0] = sprit_ptr[1]; + tmp_ptr = sprit_ptr; while (*tmp_ptr == ' ' || *tmp_ptr == '\r' || *tmp_ptr == '\n' || *tmp_ptr == '\t') tmp_ptr++; if (*tmp_ptr == '\0') - continue; + break; title_length = 0; start_ptr = tmp_ptr; @@ -2200,6 +2194,11 @@ int spider_parse_connect_info( start_ptr++; } connect_string_parse.set_param_title(tmp_ptr, tmp_ptr + title_length); + if ((error_num = connect_string_parse.get_next_parameter_head( + start_ptr, &sprit_ptr))) + { + goto error; + } switch (title_length) { diff --git a/storage/spider/spd_table.h b/storage/spider/spd_table.h index baeec2a9a3b..6aaac2046e4 100644 --- a/storage/spider/spd_table.h +++ b/storage/spider/spd_table.h @@ -180,6 +180,94 @@ typedef struct st_spider_param_string_parse DBUG_RETURN(error_num); } + inline int get_next_parameter_head(char *st, char **nx) + { + DBUG_ENTER("get_next_parameter_head"); + char *sq = strchr(st, '\''); + char *dq = strchr(st, '"'); + if (!sq && !dq) + { + DBUG_RETURN(print_param_error()); + } + else if (!sq || sq > dq) + { + while (1) + { + ++dq; + if (*dq == '\\') + { + ++dq; + } + else if (*dq == '"') + { + break; + } + else if (*dq == '\0') + { + DBUG_RETURN(print_param_error()); + } + } + while (1) + { + ++dq; + if (*dq == '\0') + { + *nx = dq; + break; + } + else if (*dq == ',') + { + *dq = '\0'; + *nx = dq + 1; + break; + } + else if (*dq != ' ' && *dq != '\r' && *dq != '\n' && *dq != '\t') + { + DBUG_RETURN(print_param_error()); + } + } + } + else + { + while (1) + { + ++sq; + if (*sq == '\\') + { + ++sq; + } + else if (*sq == '\'') + { + break; + } + else if (*sq == '\0') + { + DBUG_RETURN(print_param_error()); + } + } + while (1) + { + ++sq; + if (*sq == '\0') + { + *nx = sq; + break; + } + else if (*sq == ',') + { + *sq = '\0'; + *nx = sq + 1; + break; + } + else if (*sq != ' ' && *sq != '\r' && *sq != '\n' && *sq != '\t') + { + DBUG_RETURN(print_param_error()); + } + } + } + DBUG_RETURN(0); + } + /** Restore the current parameter's input delimiter characters in the parameter string. They were NULLed during parameter parsing. From 5796021174fd7096267003b999e02d6cf98f555b Mon Sep 17 00:00:00 2001 From: Julius Goryavsky Date: Tue, 11 Aug 2020 14:03:02 +0200 Subject: [PATCH 39/70] MDEV-21039: Server fails to start with unknown mysqld_safe options Adding any unknown option to the "[mysqld_safe]" section makes mysqld impossible to start with mysqld_multi. For example, after adding the unknown option "numa_interleave" to the "[mysqld_safe]" section, mysqld_multi exits with the following diagnostics: [ERROR] /usr/local/mysql/bin/mysqld: unknown option '--numa_interleave' To get rid of this behavior, this patch by default adds the "--loose-" prefix to all unknown (for mysqld_safe) options. This behavior can be enabled explicitly with the --ignore-unknown option and disabled with the --no-ignore-unknown option. --- scripts/mysqld_safe.sh | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/scripts/mysqld_safe.sh b/scripts/mysqld_safe.sh index 87dc81e8b5f..3d3d4141dc5 100644 --- a/scripts/mysqld_safe.sh +++ b/scripts/mysqld_safe.sh @@ -24,6 +24,7 @@ unsafe_my_cnf=0 wsrep_on=0 dry_run=0 defaults_group_suffix= +ignore_unknown=1 # Initial logging status: error log is not open, and not using syslog logging=init @@ -383,11 +384,22 @@ parse_arguments() { --help) usage ;; + --ignore-unknown) ignore_unknown=1 ;; + --no-ignore-unknown|--not-ignore-unknown) ignore_unknown=0 ;; + *) - case "$unrecognized_handling" in - collect) append_arg_to_args "$arg" ;; - complain) log_error "unknown option '$arg'" ;; - esac + if test $ignore_unknown -eq 0 + then + case "$unrecognized_handling" in + collect) append_arg_to_args "$arg" ;; + complain) log_error "unknown option '$arg'" + esac + else + case "$arg" in + "--loose-"*) append_arg_to_args "$arg" ;; + *) append_arg_to_args "--loose-$arg" + esac + fi esac done } From ece0b0623c9c14a2a1de61c53be9e1bcc2b6216c Mon Sep 17 00:00:00 2001 From: Oleksandr Byelkin Date: Sun, 16 Aug 2020 22:14:59 +0200 Subject: [PATCH 40/70] MDEV-23491: __bss_start breaks compilation of various platforms Remove __bss_start & Co, because systen call "write" check buffer address and return EFAULT if it is wrong. --- mysys/stacktrace.c | 122 +++++----------------------------- unittest/mysys/CMakeLists.txt | 2 +- unittest/mysys/stacktrace-t.c | 67 +++++++++++++++++++ 3 files changed, 84 insertions(+), 107 deletions(-) create mode 100644 unittest/mysys/stacktrace-t.c diff --git a/mysys/stacktrace.c b/mysys/stacktrace.c index db28acb9f7e..339111f6fee 100644 --- a/mysys/stacktrace.c +++ b/mysys/stacktrace.c @@ -34,107 +34,16 @@ #include #endif -#ifdef __linux__ -#define PTR_SANE(p) ((p) && (char*)(p) >= heap_start && (char*)(p) <= heap_end) -static char *heap_start; -char *__bss_start; -#else -#define PTR_SANE(p) (p) -#endif /* __linux */ - void my_init_stacktrace() { -#ifdef __linux__ - heap_start = (char*) &__bss_start; -#endif /* __linux__ */ } -#ifdef __linux__ - -static void print_buffer(char *buffer, size_t count) -{ - const char s[]= " "; - for (; count && *buffer; --count) - { - my_write_stderr(isprint(*buffer) ? buffer : s, 1); - ++buffer; - } -} - -/** - Access the pages of this process through /proc/self/task//mem - in order to safely print the contents of a memory address range. - - @param addr The address at the start of the memory region. - @param max_len The length of the memory region. - - @return Zero on success. -*/ -static int safe_print_str(const char *addr, int max_len) -{ - int fd; - pid_t tid; - off_t offset; - ssize_t nbytes= 0; - size_t total, count; - char buf[256]; - - tid= (pid_t) syscall(SYS_gettid); - - sprintf(buf, "/proc/self/task/%d/mem", tid); - - if ((fd= open(buf, O_RDONLY)) < 0) - return -1; - - /* Ensure that off_t can hold a pointer. */ - compile_time_assert(sizeof(off_t) >= sizeof(intptr)); - - total= max_len; - offset= (intptr) addr; - - /* Read up to the maximum number of bytes. */ - while (total) - { - count= MY_MIN(sizeof(buf), total); - - if ((nbytes= pread(fd, buf, count, offset)) < 0) - { - /* Just in case... */ - if (errno == EINTR) - continue; - else - break; - } - - /* Advance offset into memory. */ - total-= nbytes; - offset+= nbytes; - addr+= nbytes; - - /* Output the printable characters. */ - print_buffer(buf, nbytes); - - /* Break if less than requested... */ - if ((count - nbytes)) - break; - } - - if (nbytes == -1) - my_safe_printf_stderr("Can't read from address %p", addr); - - close(fd); - - return 0; -} - -#endif /* Attempt to print a char * pointer as a string. SYNOPSIS - Prints either until the end of string ('\0'), or max_len characters have - been printed. + Prints until max_len characters have been printed. RETURN VALUE 0 Pointer was within the heap address space. @@ -149,24 +58,25 @@ static int safe_print_str(const char *addr, int max_len) int my_safe_print_str(const char* val, int max_len) { -#ifdef __linux__ - char *heap_end; - - // Try and make use of /proc filesystem to safely print memory contents. - if (!safe_print_str(val, max_len)) - return 0; - - heap_end= (char*) sbrk(0); -#endif - - if (!PTR_SANE(val)) + const char *orig_val= val; + if (!val) { - my_safe_printf_stderr("%s", "is an invalid pointer"); + my_safe_printf_stderr("%s", "(null)"); return 1; } - for (; max_len && PTR_SANE(val) && *val; --max_len) - my_write_stderr((val++), 1); + for (; max_len; --max_len) + { + if (my_write_stderr((val++), 1) != 1) + { + if ((errno == EFAULT) &&(val == orig_val + 1)) + { + // We can not read the address from very beginning + my_safe_printf_stderr("Can't access address %p", orig_val); + } + break; + } + } my_safe_printf_stderr("%s", "\n"); return 0; diff --git a/unittest/mysys/CMakeLists.txt b/unittest/mysys/CMakeLists.txt index 9ad7e76f547..dd1aa85c9c6 100644 --- a/unittest/mysys/CMakeLists.txt +++ b/unittest/mysys/CMakeLists.txt @@ -15,7 +15,7 @@ MY_ADD_TESTS(bitmap base64 my_atomic my_rdtsc lf my_malloc my_getopt dynstring aes - queues LINK_LIBRARIES mysys) + queues stacktrace LINK_LIBRARIES mysys) MY_ADD_TESTS(my_vsnprintf LINK_LIBRARIES strings mysys) ADD_DEFINITIONS(${SSL_DEFINES}) diff --git a/unittest/mysys/stacktrace-t.c b/unittest/mysys/stacktrace-t.c new file mode 100644 index 00000000000..8fa0db15b36 --- /dev/null +++ b/unittest/mysys/stacktrace-t.c @@ -0,0 +1,67 @@ + +/* Copyright (c) 2020, MariaDB Corporation. + + 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ + +#include +#include +#include +#include +#include + +char b_bss[10]; + +void test_my_safe_print_str() +{ + char b_stack[10]; + char *b_heap= strdup("LEGAL"); + memcpy(b_stack, "LEGAL", 6); + memcpy(b_bss, "LEGAL", 6); + +#ifndef __SANITIZE_ADDRESS__ + fprintf(stderr, "\n===== stack =====\n"); + my_safe_print_str(b_stack, 65535); + fprintf(stderr, "\n===== heap =====\n"); + my_safe_print_str(b_heap, 65535); + fprintf(stderr, "\n===== BSS =====\n"); + my_safe_print_str(b_bss, 65535); + fprintf(stderr, "\n===== data =====\n"); + my_safe_print_str("LEGAL", 65535); + fprintf(stderr, "\n===== Above is a junk, but it is expected. =====\n"); +#endif /*__SANITIZE_ADDRESS__*/ + fprintf(stderr, "\n===== Nornal length test =====\n"); + my_safe_print_str("LEGAL", 5); + fprintf(stderr, "\n===== NULL =====\n"); + my_safe_print_str(0, 5); +#ifndef __SANITIZE_ADDRESS__ + fprintf(stderr, "\n===== (const char*) 1 =====\n"); + my_safe_print_str((const char*)1, 5); +#endif /*__SANITIZE_ADDRESS__*/ + + free(b_heap); + + ok(1, "test_my_safe_print_str"); +} + + +int main(int argc __attribute__((unused)), char **argv) +{ + MY_INIT(argv[0]); + plan(1); + + test_my_safe_print_str(); + + my_end(0); + return exit_status(); +} From 362b18c53672c4c2f8c49545b8f5cc586e26a325 Mon Sep 17 00:00:00 2001 From: Thirunarayanan Balathandayuthapani Date: Mon, 3 Aug 2020 16:51:41 +0530 Subject: [PATCH 41/70] MDEV-23380 InnoDB reads a page from disk despite parsing MLOG_INIT_FILE_PAGE2 record This problem is caused by 6697135c6d03935118c3dfa1c97faea7fa76afa6 (MDEV-21572). During recovery, InnoDB prefetches the siblings of change buffer index leaf page. It does asynchronous page read and recovery scenario wasn't handled in buf_read_page_background(). It leads to the refusal of startup of the server. Solution: ========= InnoDB shouldn't allow the change buffer index page siblings to be prefetched. --- storage/innobase/btr/btr0cur.cc | 5 +++-- storage/innobase/include/dict0mem.h | 3 +++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/storage/innobase/btr/btr0cur.cc b/storage/innobase/btr/btr0cur.cc index d7d15faa852..770c6d73585 100644 --- a/storage/innobase/btr/btr0cur.cc +++ b/storage/innobase/btr/btr0cur.cc @@ -3145,7 +3145,7 @@ fail: /* prefetch siblings of the leaf for the pessimistic operation, if the page is leaf. */ - if (page_is_leaf(page)) { + if (page_is_leaf(page) && !index->is_ibuf()) { btr_cur_prefetch_siblings(block); } fail_err: @@ -4041,6 +4041,7 @@ btr_cur_optimistic_update( if (rec_offs_any_extern(*offsets)) { any_extern: + ut_ad(!index->is_ibuf()); /* Externally stored fields are treated in pessimistic update */ @@ -4220,7 +4221,7 @@ func_exit: } } - if (err != DB_SUCCESS) { + if (err != DB_SUCCESS && !index->is_ibuf()) { /* prefetch siblings of the leaf for the pessimistic operation. */ btr_cur_prefetch_siblings(block); diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h index 0d4ee9d23ec..804176e2d5b 100644 --- a/storage/innobase/include/dict0mem.h +++ b/storage/innobase/include/dict0mem.h @@ -1034,6 +1034,9 @@ struct dict_index_t{ } } + /** @return whether this is the change buffer */ + bool is_ibuf() const { return UNIV_UNLIKELY(type & DICT_IBUF); } + #ifdef BTR_CUR_HASH_ADAPT /** @return a clone of this */ dict_index_t* clone() const; From 8268f26605c871f19cb78be08c84f621f4e0c4cb Mon Sep 17 00:00:00 2001 From: Thirunarayanan Balathandayuthapani Date: Fri, 7 Aug 2020 19:02:48 +0530 Subject: [PATCH 42/70] MDEV-22934 Table disappear after two alter table command Problem: ======= InnoDB drops the column which has foreign key relations on it. So it tries to load the foreign key during rename process of copy algorithm even though the foreign_key_check is disabled. Solution: ======== During alter copy algorithm, InnoDB ignores the error while loading the foreign key constraint if foreign key check is disabled. It should throw the warning about failure of the foreign key constraint when foreign key check is disabled. --- mysql-test/suite/innodb/r/foreign_key.result | 27 ++++++++++++++++++++ mysql-test/suite/innodb/r/innodb.result | 2 +- mysql-test/suite/innodb/t/foreign_key.test | 23 +++++++++++++++++ mysql-test/suite/innodb/t/innodb.test | 2 +- storage/innobase/row/row0mysql.cc | 10 +++++++- 5 files changed, 61 insertions(+), 3 deletions(-) diff --git a/mysql-test/suite/innodb/r/foreign_key.result b/mysql-test/suite/innodb/r/foreign_key.result index b0b4635157e..bab4ea16643 100644 --- a/mysql-test/suite/innodb/r/foreign_key.result +++ b/mysql-test/suite/innodb/r/foreign_key.result @@ -659,6 +659,7 @@ SET GLOBAL innodb_purge_rseg_truncate_frequency = @saved_frequency; # MDEV-17187 table doesn't exist in engine after ALTER other tables # with CONSTRAINTs # +call mtr.add_suppression("\\[Warning\\] InnoDB: In ALTER TABLE `test`\\.`t2` has or is referenced in foreign key constraints which are not compatible with the new table definition."); set foreign_key_checks=on; create table t1 (id int not null primary key) engine=innodb; create table t2 (id int not null primary key, fid int not null, @@ -714,4 +715,30 @@ drop table t1,t2; ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails drop table t1,t2; ERROR 42S02: Unknown table 'test.t2' +# +# MDEV-22934 Table disappear after two alter table command +# +CREATE TABLE t1(f1 INT NOT NULL AUTO_INCREMENT, +f2 INT NOT NULL, +PRIMARY KEY (f1), INDEX (f2))ENGINE=InnoDB; +CREATE TABLE t2(f1 INT NOT NULL, +f2 INT NOT NULL, f3 INT NOT NULL, +PRIMARY KEY(f1, f2), UNIQUE KEY(f2), +CONSTRAINT `t2_ibfk_1` FOREIGN KEY (f2) REFERENCES t1(f2) ON DELETE CASCADE, +CONSTRAINT `t2_ibfk_2` FOREIGN KEY (f1) REFERENCES t1(f1) ON DELETE CASCADE +) ENGINE=InnoDB; +SET FOREIGN_KEY_CHECKS=0; +ALTER TABLE t2 DROP PRIMARY KEY, ADD PRIMARY KEY(f3), ALGORITHM=INPLACE; +ALTER TABLE t2 DROP INDEX `f2`, ALGORITHM=COPY; +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `f1` int(11) NOT NULL, + `f2` int(11) NOT NULL, + `f3` int(11) NOT NULL, + PRIMARY KEY (`f3`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +CREATE TABLE t2 (f1 INT NOT NULL)ENGINE=InnoDB; +ERROR 42S01: Table 't2' already exists +DROP TABLE t2, t1; # End of 10.2 tests diff --git a/mysql-test/suite/innodb/r/innodb.result b/mysql-test/suite/innodb/r/innodb.result index 0d92968b095..921f9880d47 100644 --- a/mysql-test/suite/innodb/r/innodb.result +++ b/mysql-test/suite/innodb/r/innodb.result @@ -2598,7 +2598,6 @@ set foreign_key_checks=0; create table t2 (a varchar(10), foreign key (a) references t1(a)) engine = innodb; create table t1(a varchar(10) primary key) engine = innodb; alter table t1 modify column a int; -Got one of the listed errors set foreign_key_checks=1; drop table t2,t1; set foreign_key_checks=0; @@ -2607,6 +2606,7 @@ create table t1(a varchar(10) primary key) engine = innodb DEFAULT CHARSET=latin alter table t1 convert to character set utf8; set foreign_key_checks=1; drop table t2,t1; +call mtr.add_suppression("\\[Warning\\] InnoDB: In ALTER TABLE `test`.`t1` has or is referenced in foreign key constraints which are not compatible with the new table definition."); set foreign_key_checks=0; create table t2 (a varchar(10), foreign key (a) references t1(a)) engine = innodb DEFAULT CHARSET=latin1; create table t3(a varchar(10) primary key) engine = innodb DEFAULT CHARSET=utf8; diff --git a/mysql-test/suite/innodb/t/foreign_key.test b/mysql-test/suite/innodb/t/foreign_key.test index 27fa63f144e..40bc3a32a4f 100644 --- a/mysql-test/suite/innodb/t/foreign_key.test +++ b/mysql-test/suite/innodb/t/foreign_key.test @@ -657,6 +657,8 @@ SET GLOBAL innodb_purge_rseg_truncate_frequency = @saved_frequency; --echo # with CONSTRAINTs --echo # +call mtr.add_suppression("\\[Warning\\] InnoDB: In ALTER TABLE `test`\\.`t2` has or is referenced in foreign key constraints which are not compatible with the new table definition."); + set foreign_key_checks=on; create table t1 (id int not null primary key) engine=innodb; create table t2 (id int not null primary key, fid int not null, @@ -698,6 +700,27 @@ drop table t1,t2; --error ER_BAD_TABLE_ERROR drop table t1,t2; +--echo # +--echo # MDEV-22934 Table disappear after two alter table command +--echo # +CREATE TABLE t1(f1 INT NOT NULL AUTO_INCREMENT, + f2 INT NOT NULL, + PRIMARY KEY (f1), INDEX (f2))ENGINE=InnoDB; +CREATE TABLE t2(f1 INT NOT NULL, + f2 INT NOT NULL, f3 INT NOT NULL, + PRIMARY KEY(f1, f2), UNIQUE KEY(f2), +CONSTRAINT `t2_ibfk_1` FOREIGN KEY (f2) REFERENCES t1(f2) ON DELETE CASCADE, +CONSTRAINT `t2_ibfk_2` FOREIGN KEY (f1) REFERENCES t1(f1) ON DELETE CASCADE +) ENGINE=InnoDB; + +SET FOREIGN_KEY_CHECKS=0; +ALTER TABLE t2 DROP PRIMARY KEY, ADD PRIMARY KEY(f3), ALGORITHM=INPLACE; +ALTER TABLE t2 DROP INDEX `f2`, ALGORITHM=COPY; +SHOW CREATE TABLE t2; +--error ER_TABLE_EXISTS_ERROR +CREATE TABLE t2 (f1 INT NOT NULL)ENGINE=InnoDB; +DROP TABLE t2, t1; + --echo # End of 10.2 tests --source include/wait_until_count_sessions.inc diff --git a/mysql-test/suite/innodb/t/innodb.test b/mysql-test/suite/innodb/t/innodb.test index 661d7dff129..7aa146d7d99 100644 --- a/mysql-test/suite/innodb/t/innodb.test +++ b/mysql-test/suite/innodb/t/innodb.test @@ -1662,7 +1662,6 @@ drop table t1; set foreign_key_checks=0; create table t2 (a varchar(10), foreign key (a) references t1(a)) engine = innodb; create table t1(a varchar(10) primary key) engine = innodb; --- error 1025,1025 alter table t1 modify column a int; set foreign_key_checks=1; drop table t2,t1; @@ -1678,6 +1677,7 @@ drop table t2,t1; # test that RENAME does not allow invalid charsets when f_k_c is 0 +call mtr.add_suppression("\\[Warning\\] InnoDB: In ALTER TABLE `test`.`t1` has or is referenced in foreign key constraints which are not compatible with the new table definition."); set foreign_key_checks=0; create table t2 (a varchar(10), foreign key (a) references t1(a)) engine = innodb DEFAULT CHARSET=latin1; create table t3(a varchar(10) primary key) engine = innodb DEFAULT CHARSET=utf8; diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc index 7c61ad9b45b..3370cdca570 100644 --- a/storage/innobase/row/row0mysql.cc +++ b/storage/innobase/row/row0mysql.cc @@ -4536,12 +4536,20 @@ end: if (err != DB_SUCCESS) { if (old_is_tmp) { - ib::error() << "In ALTER TABLE " + /* In case of copy alter, ignore the + loading of foreign key constraint + when foreign_key_check is disabled */ + ib::error_or_warn(trx->check_foreigns) + << "In ALTER TABLE " << ut_get_name(trx, new_name) << " has or is referenced in foreign" " key constraints which are not" " compatible with the new table" " definition."; + if (!trx->check_foreigns) { + err = DB_SUCCESS; + goto funct_exit; + } } else { ib::error() << "In RENAME TABLE table " << ut_get_name(trx, new_name) From 064bfbaf0646f91f0a7ddc4f1e5f3c9844e7571f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 18 Aug 2020 15:14:12 +0300 Subject: [PATCH 43/70] MDEV-23499 Assertion c.same_type(*o) failed dict_col_t::same_encoding(), dict_col_t::same_format(): Allow an instantaneous change of a column to a compatible encoding, just like ha_innobase::can_convert_string() and similar functions do. --- mysql-test/suite/innodb/r/instant_alter_bugs.result | 6 ++++++ mysql-test/suite/innodb/t/instant_alter_bugs.test | 7 +++++++ storage/innobase/dict/dict0mem.cc | 2 +- storage/innobase/include/dict0mem.h | 2 +- 4 files changed, 15 insertions(+), 2 deletions(-) diff --git a/mysql-test/suite/innodb/r/instant_alter_bugs.result b/mysql-test/suite/innodb/r/instant_alter_bugs.result index 81d4db79be0..3da8fccd3c5 100644 --- a/mysql-test/suite/innodb/r/instant_alter_bugs.result +++ b/mysql-test/suite/innodb/r/instant_alter_bugs.result @@ -407,4 +407,10 @@ CREATE TABLE t (i INT PRIMARY KEY) ENGINE=InnoDB; INSERT INTO t SET i=1; ALTER TABLE t ADD e CHAR(255) CHARACTER SET UTF32 FIRST, ALGORITHM=INSTANT; DROP TABLE t; +# +# MDEV-23499 Assertion c.same_type(*o) failed +# +CREATE TABLE t (pk SERIAL, b TEXT CHARACTER SET utf8) ENGINE=InnoDB; +ALTER TABLE t MODIFY b TEXT CHARACTER SET utf8mb4 FIRST; +DROP TABLE t; SET GLOBAL innodb_purge_rseg_truncate_frequency=@save_frequency; diff --git a/mysql-test/suite/innodb/t/instant_alter_bugs.test b/mysql-test/suite/innodb/t/instant_alter_bugs.test index b6a3aecd7da..9522a960928 100644 --- a/mysql-test/suite/innodb/t/instant_alter_bugs.test +++ b/mysql-test/suite/innodb/t/instant_alter_bugs.test @@ -429,4 +429,11 @@ INSERT INTO t SET i=1; ALTER TABLE t ADD e CHAR(255) CHARACTER SET UTF32 FIRST, ALGORITHM=INSTANT; DROP TABLE t; +--echo # +--echo # MDEV-23499 Assertion c.same_type(*o) failed +--echo # +CREATE TABLE t (pk SERIAL, b TEXT CHARACTER SET utf8) ENGINE=InnoDB; +ALTER TABLE t MODIFY b TEXT CHARACTER SET utf8mb4 FIRST; +DROP TABLE t; + SET GLOBAL innodb_purge_rseg_truncate_frequency=@save_frequency; diff --git a/storage/innobase/dict/dict0mem.cc b/storage/innobase/dict/dict0mem.cc index e9e0d33bf9f..b72451e0f34 100644 --- a/storage/innobase/dict/dict0mem.cc +++ b/storage/innobase/dict/dict0mem.cc @@ -120,7 +120,7 @@ bool dict_col_t::same_encoding(uint16_t a, uint16_t b) { if (const CHARSET_INFO *acs= get_charset(a, MYF(MY_WME))) if (const CHARSET_INFO *bcs= get_charset(b, MYF(MY_WME))) - return Charset(acs).same_encoding(bcs); + return Charset(bcs).encoding_allows_reinterpret_as(acs); return false; } diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h index ed392df3c05..e20812b862b 100644 --- a/storage/innobase/include/dict0mem.h +++ b/storage/innobase/include/dict0mem.h @@ -728,7 +728,7 @@ public: bool same_format(const dict_col_t &other) const { return same_type(other) && len >= other.len && - mbminlen == other.mbminlen && mbmaxlen == other.mbmaxlen && + mbminlen == other.mbminlen && mbmaxlen >= other.mbmaxlen && !((prtype ^ other.prtype) & ~(DATA_NOT_NULL | DATA_VERSIONED | CHAR_COLL_MASK << 16 | DATA_LONG_TRUE_VARCHAR)); From 4c50120d1400eab236af70d36f1c683d2b30d59a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Fri, 14 Aug 2020 14:52:14 +0300 Subject: [PATCH 44/70] MDEV-23474 InnoDB fails to restart after SET GLOBAL innodb_log_checksums=OFF Regretfully, the parameter innodb_log_checksums was introduced in MySQL 5.7.9 (the first GA release of that series) by mysql/mysql-server@af0acedd885eb7103e319f79d25fda7386ef1506 which partly replaced a parameter that had been introduced in 5.7.8 mysql/mysql-server@22ba38218e1d76c24f69b5a5595ad3bf5933acb0 as innodb_log_checksum_algorithm. Given that the CRC-32C operations are accelerated on many processor implementations (AMD64 with SSE4.2; since MDEV-22669 also on IA-32 with SSE4.2, POWER 8 and later, ARMv8 with some extensions) and by lookup tables when only generic SISD instructions are available, there should be no valid reason to disable checksums. In MariaDB 10.5.2, as a preparation for MDEV-12353, MDEV-19543 deprecated and ignored the parameter innodb_log_checksums altogether. This should imply that after a clean shutdown with innodb_log_checksums=OFF one cannot upgrade to MariaDB Server 10.5 at all. Due to these problems, let us deprecate the parameter innodb_log_checksums and honor it only during server startup. The command SET GLOBAL innodb_log_checksums will always set the parameter to ON. --- extra/mariabackup/xtrabackup.cc | 4 --- .../encryption/r/innodb_encrypt_log.result | 2 +- .../innodb/r/innodb_xtradb_compat.result | 2 +- .../r/innodb_log_checksums_basic.result | 4 ++- .../suite/sys_vars/r/sysvars_innodb.result | 2 +- storage/innobase/handler/ha_innodb.cc | 26 +++++-------------- storage/innobase/handler/ha_xtradb.h | 23 +--------------- storage/innobase/include/log0log.h | 25 ++---------------- storage/innobase/include/log0log.ic | 25 +----------------- storage/innobase/log/log0log.cc | 9 +++---- storage/innobase/log/log0recv.cc | 5 +++- 11 files changed, 23 insertions(+), 104 deletions(-) diff --git a/extra/mariabackup/xtrabackup.cc b/extra/mariabackup/xtrabackup.cc index 02d232b59d6..9b3d9f9ea39 100644 --- a/extra/mariabackup/xtrabackup.cc +++ b/extra/mariabackup/xtrabackup.cc @@ -2023,10 +2023,6 @@ innodb_init_param(void) srv_undo_dir = (char*) "."; } - log_checksum_algorithm_ptr = innodb_log_checksums || srv_encrypt_log - ? log_block_calc_checksum_crc32 - : log_block_calc_checksum_none; - return(FALSE); error: diff --git a/mysql-test/suite/encryption/r/innodb_encrypt_log.result b/mysql-test/suite/encryption/r/innodb_encrypt_log.result index b999e8cb34a..cd37330f2b0 100644 --- a/mysql-test/suite/encryption/r/innodb_encrypt_log.result +++ b/mysql-test/suite/encryption/r/innodb_encrypt_log.result @@ -7,7 +7,7 @@ # SET GLOBAL innodb_log_checksums=0; Warnings: -Warning 138 innodb_encrypt_log implies innodb_log_checksums +Warning 138 innodb_log_checksums is deprecated and has no effect outside recovery SELECT @@global.innodb_log_checksums; @@global.innodb_log_checksums 1 diff --git a/mysql-test/suite/innodb/r/innodb_xtradb_compat.result b/mysql-test/suite/innodb/r/innodb_xtradb_compat.result index 20b6ac4c892..5722120356a 100644 --- a/mysql-test/suite/innodb/r/innodb_xtradb_compat.result +++ b/mysql-test/suite/innodb/r/innodb_xtradb_compat.result @@ -148,7 +148,7 @@ Warnings: Warning 1287 Using innodb_log_checksum_algorithm is deprecated and the parameter may be removed in future releases. Ignoning the parameter. select @@innodb_log_checksum_algorithm, @@innodb_log_checksums; @@innodb_log_checksum_algorithm @@innodb_log_checksums -NONE 0 +STRICT_INNODB 1 set global innodb_log_checksum_algorithm=STRICT_INNODB; Warnings: Warning 1287 Using innodb_log_checksum_algorithm is deprecated and the parameter may be removed in future releases. Ignoning the parameter. diff --git a/mysql-test/suite/sys_vars/r/innodb_log_checksums_basic.result b/mysql-test/suite/sys_vars/r/innodb_log_checksums_basic.result index 6679ca87249..7724ef9c2ee 100644 --- a/mysql-test/suite/sys_vars/r/innodb_log_checksums_basic.result +++ b/mysql-test/suite/sys_vars/r/innodb_log_checksums_basic.result @@ -28,9 +28,11 @@ SELECT @@global.innodb_log_checksums; @@global.innodb_log_checksums 1 SET GLOBAL innodb_log_checksums = OFF; +Warnings: +Warning 138 innodb_log_checksums is deprecated and has no effect outside recovery SELECT @@global.innodb_log_checksums; @@global.innodb_log_checksums -0 +1 SET GLOBAL innodb_log_checksums = default; SET GLOBAL innodb_log_checksums = ON; SELECT @@global.innodb_log_checksums; diff --git a/mysql-test/suite/sys_vars/r/sysvars_innodb.result b/mysql-test/suite/sys_vars/r/sysvars_innodb.result index 98d303ce4bb..bed23a777a8 100644 --- a/mysql-test/suite/sys_vars/r/sysvars_innodb.result +++ b/mysql-test/suite/sys_vars/r/sysvars_innodb.result @@ -1499,7 +1499,7 @@ SESSION_VALUE NULL DEFAULT_VALUE ON VARIABLE_SCOPE GLOBAL VARIABLE_TYPE BOOLEAN -VARIABLE_COMMENT Whether to compute and require checksums for InnoDB redo log blocks +VARIABLE_COMMENT DEPRECATED. Whether to require checksums for InnoDB redo log blocks. NUMERIC_MIN_VALUE NULL NUMERIC_MAX_VALUE NULL NUMERIC_BLOCK_SIZE NULL diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index f9439ee1ce9..8b58ca57a74 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -3599,8 +3599,7 @@ static const char* deprecated_mtflush_threads static my_bool innodb_instrument_semaphores; -/** Update log_checksum_algorithm_ptr with a pointer to the function -corresponding to whether checksums are enabled. +/** If applicable, emit a message that log checksums cannot be disabled. @param[in,out] thd client session, or NULL if at startup @param[in] check whether redo log block checksums are enabled @return whether redo log block checksums are enabled */ @@ -3608,34 +3607,21 @@ static inline bool innodb_log_checksums_func_update(THD* thd, bool check) { - static const char msg[] = "innodb_encrypt_log implies" - " innodb_log_checksums"; + static const char msg[] = "innodb_log_checksums is deprecated" + " and has no effect outside recovery"; ut_ad(!thd == !srv_was_started); if (!check) { - check = srv_encrypt_log; - if (!check) { - } else if (thd) { + if (thd) { push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, HA_ERR_UNSUPPORTED, msg); + check = true; } else { sql_print_warning(msg); } } - if (thd) { - log_mutex_enter(); - log_checksum_algorithm_ptr = check - ? log_block_calc_checksum_crc32 - : log_block_calc_checksum_none; - log_mutex_exit(); - } else { - log_checksum_algorithm_ptr = check - ? log_block_calc_checksum_crc32 - : log_block_calc_checksum_none; - } - return(check); } @@ -19905,7 +19891,7 @@ static MYSQL_SYSVAR_ENUM(checksum_algorithm, srv_checksum_algorithm, static MYSQL_SYSVAR_BOOL(log_checksums, innodb_log_checksums, PLUGIN_VAR_RQCMDARG, - "Whether to compute and require checksums for InnoDB redo log blocks", + "DEPRECATED. Whether to require checksums for InnoDB redo log blocks.", NULL, innodb_log_checksums_update, TRUE); static MYSQL_SYSVAR_BOOL(checksums, innobase_use_checksums, diff --git a/storage/innobase/handler/ha_xtradb.h b/storage/innobase/handler/ha_xtradb.h index 9e898818a01..b049905613c 100644 --- a/storage/innobase/handler/ha_xtradb.h +++ b/storage/innobase/handler/ha_xtradb.h @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 2000, 2016, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, 2018, MariaDB Corporation. +Copyright (c) 2017, 2020, MariaDB Corporation. Copyright (c) 2009, Percona Inc. Portions of this file contain modifications contributed and copyrighted @@ -507,18 +507,6 @@ set_log_checksum_algorithm(THD* thd, st_mysql_sys_var*, void*, const void* save) ER_WARN_DEPRECATED_SYNTAX, innodb_deprecated_msg, "innodb_log_checksum_algorithm"); - log_mutex_enter(); - srv_log_checksum_algorithm = *static_cast(save); - if (srv_log_checksum_algorithm == SRV_CHECKSUM_ALGORITHM_NONE) { - ib::info() << "Setting innodb_log_checksums = false"; - innodb_log_checksums = false; - log_checksum_algorithm_ptr = log_block_calc_checksum_none; - } else { - ib::info() << "Setting innodb_log_checksums = true"; - innodb_log_checksums = true; - log_checksum_algorithm_ptr = log_block_calc_checksum_crc32; - } - log_mutex_exit(); } static MYSQL_SYSVAR_ENUM(log_checksum_algorithm, srv_log_checksum_algorithm, PLUGIN_VAR_RQCMDARG, @@ -869,15 +857,6 @@ innodb_check_deprecated(void) if (srv_log_checksum_algorithm != SRV_CHECKSUM_ALGORITHM_DEPRECATED) { innodb_print_deprecation("innodb-log-checksum-algorithm"); - if (srv_log_checksum_algorithm == SRV_CHECKSUM_ALGORITHM_NONE) { - ib::info() << "Setting innodb_log_checksums = false"; - innodb_log_checksums = false; - log_checksum_algorithm_ptr = log_block_calc_checksum_none; - } else { - ib::info() << "Setting innodb_log_checksums = true"; - innodb_log_checksums = true; - log_checksum_algorithm_ptr = log_block_calc_checksum_crc32; - } } if (srv_max_changed_pages) { diff --git a/storage/innobase/include/log0log.h b/storage/innobase/include/log0log.h index 0fd983a1a10..612a27976e7 100644 --- a/storage/innobase/include/log0log.h +++ b/storage/innobase/include/log0log.h @@ -2,7 +2,7 @@ Copyright (c) 1995, 2017, Oracle and/or its affiliates. All rights reserved. Copyright (c) 2009, Google Inc. -Copyright (c) 2017, 2019, MariaDB Corporation. +Copyright (c) 2017, 2020, MariaDB Corporation. Portions of this file contain modifications contributed and copyrighted by Google, Inc. Those modifications are gratefully acknowledged and are described @@ -56,12 +56,6 @@ step which modifies the database, is started */ #define LOG_CHECKPOINT_FREE_PER_THREAD (4 * UNIV_PAGE_SIZE) #define LOG_CHECKPOINT_EXTRA_FREE (8 * UNIV_PAGE_SIZE) -typedef ulint (*log_checksum_func_t)(const byte* log_block); - -/** Pointer to the log checksum calculation function. Protected with -log_sys->mutex. */ -extern log_checksum_func_t log_checksum_algorithm_ptr; - /** Append a string to the log. @param[in] str string @param[in] len string length @@ -295,14 +289,6 @@ log_block_set_data_len( /*===================*/ byte* log_block, /*!< in/out: log block */ ulint len); /*!< in: data length */ -/************************************************************//** -Calculates the checksum for a log block. -@return checksum */ -UNIV_INLINE -ulint -log_block_calc_checksum( -/*====================*/ - const byte* block); /*!< in: log block */ /** Calculates the checksum for a log block using the CRC32 algorithm. @param[in] block log block @@ -312,13 +298,6 @@ ulint log_block_calc_checksum_crc32( const byte* block); -/** Calculates the checksum for a log block using the "no-op" algorithm. -@param[in] block the redo log block -@return the calculated checksum value */ -UNIV_INLINE -ulint -log_block_calc_checksum_none(const byte* block); - /************************************************************//** Gets a log block checksum field value. @return checksum */ @@ -403,7 +382,7 @@ log_group_close_all(void); void log_shutdown(); -/** Whether to generate and require checksums on the redo log pages */ +/** Whether to require checksums on the redo log pages */ extern my_bool innodb_log_checksums; /* Values used as flags */ diff --git a/storage/innobase/include/log0log.ic b/storage/innobase/include/log0log.ic index 36caaedfaa2..c366affcdef 100644 --- a/storage/innobase/include/log0log.ic +++ b/storage/innobase/include/log0log.ic @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1995, 2015, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, MariaDB Corporation. +Copyright (c) 2017, 2020, MariaDB Corporation. 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 @@ -190,18 +190,6 @@ log_block_convert_lsn_to_no( 0xFUL, 0x3FFFFFFFUL)) + 1); } -/************************************************************//** -Calculates the checksum for a log block. -@return checksum */ -UNIV_INLINE -ulint -log_block_calc_checksum( -/*====================*/ - const byte* block) /*!< in: log block */ -{ - return(log_checksum_algorithm_ptr(block)); -} - /** Calculate the checksum for a log block using the pre-5.7.9 algorithm. @param[in] block log block @return checksum */ @@ -242,17 +230,6 @@ log_block_calc_checksum_crc32( return(ut_crc32(block, OS_FILE_LOG_BLOCK_SIZE - LOG_BLOCK_TRL_SIZE)); } -/** Calculates the checksum for a log block using the "no-op" algorithm. -@param[in] block log block -@return checksum */ -UNIV_INLINE -ulint -log_block_calc_checksum_none( - const byte* block) -{ - return(LOG_NO_CHECKSUM_MAGIC); -} - /************************************************************//** Gets a log block checksum field value. @return checksum */ diff --git a/storage/innobase/log/log0log.cc b/storage/innobase/log/log0log.cc index 972bbe7c6c0..4c68f3743e9 100644 --- a/storage/innobase/log/log0log.cc +++ b/storage/innobase/log/log0log.cc @@ -2,7 +2,7 @@ Copyright (c) 1995, 2017, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2009, Google Inc. -Copyright (c) 2014, 2019, MariaDB Corporation. +Copyright (c) 2014, 2020, MariaDB Corporation. Portions of this file contain modifications contributed and copyrighted by Google, Inc. Those modifications are gratefully acknowledged and are described @@ -83,12 +83,9 @@ reduce the size of the log. /** Redo log system */ log_t* log_sys = NULL; -/** Whether to generate and require checksums on the redo log pages */ +/** Whether to require checksums on the redo log pages */ my_bool innodb_log_checksums; -/** Pointer to the log checksum calculation function */ -log_checksum_func_t log_checksum_algorithm_ptr; - /* Next log block number to do dummy record filling if no log records written for a while */ static ulint next_lbn_to_pad = 0; @@ -857,7 +854,7 @@ log_block_store_checksum( /*=====================*/ byte* block) /*!< in/out: pointer to a log block */ { - log_block_set_checksum(block, log_block_calc_checksum(block)); + log_block_set_checksum(block, log_block_calc_checksum_crc32(block)); } /******************************************************//** diff --git a/storage/innobase/log/log0recv.cc b/storage/innobase/log/log0recv.cc index 4980e92ea6d..c4fd5f84879 100644 --- a/storage/innobase/log/log0recv.cc +++ b/storage/innobase/log/log0recv.cc @@ -1223,7 +1223,10 @@ recv_log_recover_10_3() % univ_page_size.physical()), OS_FILE_LOG_BLOCK_SIZE, buf, NULL); - if (log_block_calc_checksum(buf) != log_block_get_checksum(buf)) { + const ulint cksum = log_block_get_checksum(buf); + + if (cksum != LOG_NO_CHECKSUM_MAGIC + && cksum != log_block_calc_checksum_crc32(buf)) { return(DB_CORRUPTION); } From 1509363970e9cb574005e3af560299c055dda983 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 18 Aug 2020 17:30:34 +0300 Subject: [PATCH 45/70] MDEV-23484 Rollback unnecessarily acquires dict_operation_lock for every row InnoDB transaction rollback includes an unnecessary work-around for a data corruption bug that was fixed by me in MySQL 5.6.12 mysql/mysql-server@935ba09d52c1908bde273ad1940b5ab919d9763d and ported to MariaDB 10.0.8 by commit c291ddfdf774b50c34b9741c6e39c57bae8fd1dc in 2013 and 2014, respectively. By acquiring and releasing dict_operation_lock in shared mode, row_undo() hopes to prevent the table from being dropped while the undo log record is being rolled back. But, thanks to mentioned fix, debug assertions (that we are adding) show that the rollback is protected by transactional locks (table IX lock, in addition to implicit or explicit exclusive locks on the records that had been modified). Because row_drop_table_for_mysql() would invoke row_add_table_to_background_drop_list() if any locks exist on the table, the mere existence of locks (which is guaranteed during ROLLBACK) is enough to protect the table from disappearing. Hence, acquiring and releasing dict_operation_lock for every row that is being rolled back is unnecessary. row_undo(): Remove the unnecessary acquisition and release of dict_operation_lock. Note: row_add_table_to_background_drop_list() is mostly working around bugs outside InnoDB: MDEV-21175 (insufficient MDL protection of FOREIGN KEY operations) MDEV-21602 (incorrect error handling of CREATE TABLE...SELECT). --- storage/innobase/row/row0uins.cc | 7 +++-- storage/innobase/row/row0umod.cc | 45 +++++--------------------------- storage/innobase/row/row0undo.cc | 17 ------------ 3 files changed, 11 insertions(+), 58 deletions(-) diff --git a/storage/innobase/row/row0uins.cc b/storage/innobase/row/row0uins.cc index 54fa244fca6..7e5aac1ba9f 100644 --- a/storage/innobase/row/row0uins.cc +++ b/storage/innobase/row/row0uins.cc @@ -81,6 +81,7 @@ row_undo_ins_remove_clust_rec( mtr.set_log_mode(MTR_LOG_NO_REDO); } else { mtr.set_named_space(index->space); + ut_ad(lock_table_has_locks(index->table)); } /* This is similar to row_undo_mod_clust(). The DDL thread may @@ -91,8 +92,7 @@ row_undo_ins_remove_clust_rec( online = dict_index_is_online_ddl(index); if (online) { - ut_ad(node->trx->dict_operation_lock_mode - != RW_X_LATCH); + ut_ad(!node->trx->dict_operation_lock_mode); ut_ad(node->table->id != DICT_INDEXES_ID); mtr_s_lock(dict_index_get_lock(index), &mtr); } @@ -491,6 +491,9 @@ row_undo_ins( return(DB_SUCCESS); } + ut_ad(node->table->is_temporary() + || lock_table_has_locks(node->table)); + /* Iterate over all the indexes and undo the insert.*/ node->index = dict_table_get_first_index(node->table); diff --git a/storage/innobase/row/row0umod.cc b/storage/innobase/row/row0umod.cc index 80d90f40379..b1cc994cdd8 100644 --- a/storage/innobase/row/row0umod.cc +++ b/storage/innobase/row/row0umod.cc @@ -264,10 +264,7 @@ row_undo_mod_clust( bool online; ut_ad(thr_get_trx(thr) == node->trx); - ut_ad(node->trx->dict_operation_lock_mode); ut_ad(node->trx->in_rollback); - ut_ad(rw_lock_own_flagged(&dict_operation_lock, - RW_LOCK_FLAG_X | RW_LOCK_FLAG_S)); log_free_check(); pcur = &node->pcur; @@ -278,11 +275,12 @@ row_undo_mod_clust( mtr.set_log_mode(MTR_LOG_NO_REDO); } else { mtr.set_named_space(index->space); + ut_ad(lock_table_has_locks(index->table)); } online = dict_index_is_online_ddl(index); if (online) { - ut_ad(node->trx->dict_operation_lock_mode != RW_X_LATCH); + ut_ad(!node->trx->dict_operation_lock_mode); mtr_s_lock(dict_index_get_lock(index), &mtr); } @@ -806,37 +804,6 @@ func_exit_no_pcur: return(err); } -/***********************************************************//** -Flags a secondary index corrupted. */ -static MY_ATTRIBUTE((nonnull)) -void -row_undo_mod_sec_flag_corrupted( -/*============================*/ - trx_t* trx, /*!< in/out: transaction */ - dict_index_t* index) /*!< in: secondary index */ -{ - ut_ad(!dict_index_is_clust(index)); - - switch (trx->dict_operation_lock_mode) { - case RW_S_LATCH: - /* Because row_undo() is holding an S-latch - on the data dictionary during normal rollback, - we can only mark the index corrupted in the - data dictionary cache. TODO: fix this somehow.*/ - mutex_enter(&dict_sys->mutex); - dict_set_corrupted_index_cache_only(index); - mutex_exit(&dict_sys->mutex); - break; - default: - ut_ad(0); - /* fall through */ - case RW_X_LATCH: - /* This should be the rollback of a data dictionary - transaction. */ - dict_set_corrupted(index, trx, "rollback"); - } -} - /***********************************************************//** Undoes a modify in secondary indexes when undo record type is UPD_DEL. @return DB_SUCCESS or DB_OUT_OF_FILE_SPACE */ @@ -950,8 +917,7 @@ row_undo_mod_del_mark_sec( } if (err == DB_DUPLICATE_KEY) { - row_undo_mod_sec_flag_corrupted( - thr_get_trx(thr), index); + index->type |= DICT_CORRUPT; err = DB_SUCCESS; /* Do not return any error to the caller. The duplicate will be reported by ALTER TABLE or @@ -1097,8 +1063,7 @@ row_undo_mod_upd_exist_sec( } if (err == DB_DUPLICATE_KEY) { - row_undo_mod_sec_flag_corrupted( - thr_get_trx(thr), index); + index->type |= DICT_CORRUPT; err = DB_SUCCESS; } else if (err != DB_SUCCESS) { break; @@ -1250,6 +1215,8 @@ row_undo_mod( return(DB_SUCCESS); } + ut_ad(node->table->is_temporary() + || lock_table_has_locks(node->table)); node->index = dict_table_get_first_index(node->table); ut_ad(dict_index_is_clust(node->index)); /* Skip the clustered index (the first index) */ diff --git a/storage/innobase/row/row0undo.cc b/storage/innobase/row/row0undo.cc index b65b173fedb..34b55f25527 100644 --- a/storage/innobase/row/row0undo.cc +++ b/storage/innobase/row/row0undo.cc @@ -279,18 +279,6 @@ row_undo( ? UNDO_NODE_INSERT : UNDO_NODE_MODIFY; } - /* Prevent DROP TABLE etc. while we are rolling back this row. - If we are doing a TABLE CREATE or some other dictionary operation, - then we already have dict_operation_lock locked in x-mode. Do not - try to lock again, because that would cause a hang. */ - - const bool locked_data_dict = (trx->dict_operation_lock_mode == 0); - - if (locked_data_dict) { - - row_mysql_freeze_data_dictionary(trx); - } - dberr_t err; if (node->state == UNDO_NODE_INSERT) { @@ -303,11 +291,6 @@ row_undo( err = row_undo_mod(node, thr); } - if (locked_data_dict) { - - row_mysql_unfreeze_data_dictionary(trx); - } - /* Do some cleanup */ btr_pcur_close(&(node->pcur)); From 8a6a0845780a9f8938379cc9e41faf2e3c851abe Mon Sep 17 00:00:00 2001 From: Daniele Sciascia Date: Tue, 18 Aug 2020 16:50:28 +0200 Subject: [PATCH 46/70] Re-record MTR tests galera_3nodes.galera_join_with_cc_{A|B|C} --- .../r/galera_join_with_cc_A.result | 41 +++++++++++++++++ .../r/galera_join_with_cc_B.result | 41 +++++++++++++++++ .../r/galera_join_with_cc_C.result | 44 +++++++++++++++++++ 3 files changed, 126 insertions(+) diff --git a/mysql-test/suite/galera_3nodes/r/galera_join_with_cc_A.result b/mysql-test/suite/galera_3nodes/r/galera_join_with_cc_A.result index 0461f1f1feb..a60e2bbb6cc 100644 --- a/mysql-test/suite/galera_3nodes/r/galera_join_with_cc_A.result +++ b/mysql-test/suite/galera_3nodes/r/galera_join_with_cc_A.result @@ -1,40 +1,81 @@ +connection node_2; +connection node_1; +connection node_1; CREATE TABLE t1 (pk INT PRIMARY KEY, node INT) ENGINE=innodb; INSERT INTO t1 VALUES (1, 1); +connection node_2; +connection node_1; SET GLOBAL wsrep_provider_options='gmcast.isolate=1'; +connection node_2; +connection node_3; INSERT INTO t1 VALUES (2, 3); +connection node_2; +connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1; SET wsrep_sync_wait = 0; SET wsrep_on = OFF; SET GLOBAL wsrep_provider_options = 'dbug=d,after_shift_to_joining'; +connection node_1; SET GLOBAL wsrep_provider_options='gmcast.isolate=0'; +connection node_2; INSERT INTO t1 VALUES (3, 2); +connection node_1a; SET SESSION wsrep_on = 0; SET SESSION wsrep_on = 0; +connection node_3; +connection node_1; SET GLOBAL wsrep_provider_options='gmcast.isolate=1'; +connection node_2; +connection node_3; INSERT INTO t1 VALUES (4, 3); +connection node_2; +connection node_1; SET GLOBAL wsrep_provider_options='gmcast.isolate=0'; +connection node_2; INSERT INTO t1 VALUES (5, 2); +connection node_3; +connection node_1a; SET GLOBAL wsrep_provider_options = 'dbug=d,before_send_state_request'; SET GLOBAL wsrep_provider_options = 'signal=after_shift_to_joining'; SET SESSION wsrep_on = 0; SET SESSION wsrep_on = 0; +connection node_1; SET GLOBAL wsrep_provider_options='gmcast.isolate=1'; +connection node_2; +connection node_3; INSERT INTO t1 VALUES (6, 3); +connection node_2; +connection node_1; SET GLOBAL wsrep_provider_options='gmcast.isolate=0'; +connection node_2; INSERT INTO t1 VALUES (7, 2); +connection node_3; +connection node_1; SET GLOBAL wsrep_provider_options='gmcast.isolate=1'; +connection node_2; +connection node_3; INSERT INTO t1 VALUES (8, 3); +connection node_2; +connection node_1; SET GLOBAL wsrep_provider_options='gmcast.isolate=0'; +connection node_2; +connection node_1a; SET GLOBAL wsrep_provider_options = 'dbug=d,process_primary_configuration'; SET GLOBAL wsrep_provider_options = 'signal=before_send_state_request'; SET SESSION wsrep_on = 0; SET SESSION wsrep_on = 0; +connection node_2; INSERT INTO t1 VALUES (9, 2); +connection node_3; +connection node_1a; SET GLOBAL wsrep_provider_options = 'signal=process_primary_configuration'; SET SESSION wsrep_on = 0; SET SESSION wsrep_on = 0; SET GLOBAL wsrep_provider_options = 'signal=process_primary_configuration'; SET GLOBAL wsrep_provider_options = 'dbug='; +connection node_1; DROP TABLE t1; call mtr.add_suppression("WSREP: Rejecting JOIN message from \(.*\): new State Transfer required."); +connection node_2; call mtr.add_suppression("WSREP: Rejecting JOIN message from \(.*\): new State Transfer required."); +connection node_3; call mtr.add_suppression("WSREP: Rejecting JOIN message from \(.*\): new State Transfer required."); diff --git a/mysql-test/suite/galera_3nodes/r/galera_join_with_cc_B.result b/mysql-test/suite/galera_3nodes/r/galera_join_with_cc_B.result index d878f60ca6b..7e75bc4b08a 100644 --- a/mysql-test/suite/galera_3nodes/r/galera_join_with_cc_B.result +++ b/mysql-test/suite/galera_3nodes/r/galera_join_with_cc_B.result @@ -1,18 +1,39 @@ +connection node_2; +connection node_1; +connection node_1; CREATE TABLE t1 (pk INT PRIMARY KEY, node INT) ENGINE=innodb; INSERT INTO t1 VALUES (1, 1); +connection node_2; +connection node_1; SET GLOBAL wsrep_provider_options='gmcast.isolate=1'; +connection node_2; +connection node_3; INSERT INTO t1 VALUES (2, 3); +connection node_2; +connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1; SET wsrep_sync_wait = 0; SET wsrep_on = OFF; SET GLOBAL wsrep_provider_options = 'dbug=d,after_shift_to_joining'; +connection node_1; SET GLOBAL wsrep_provider_options='gmcast.isolate=0'; +connection node_2; INSERT INTO t1 VALUES (3, 2); +connection node_1a; SET SESSION wsrep_on = 0; SET SESSION wsrep_on = 0; +connection node_3; +connection node_1; SET GLOBAL wsrep_provider_options='gmcast.isolate=1'; +connection node_2; +connection node_3; INSERT INTO t1 VALUES (4, 3); +connection node_2; +connection node_1; SET GLOBAL wsrep_provider_options='gmcast.isolate=0'; +connection node_2; INSERT INTO t1 VALUES (5, 2); +connection node_3; +connection node_1a; SET GLOBAL wsrep_provider_options = 'dbug=d,before_send_state_request'; SET GLOBAL wsrep_provider_options = 'signal=after_shift_to_joining'; SET SESSION wsrep_on = 0; @@ -24,18 +45,35 @@ SET SESSION wsrep_on = 0; SELECT * FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_debug_sync_waiters'; VARIABLE_NAME VARIABLE_VALUE WSREP_DEBUG_SYNC_WAITERS after_shift_to_joining +connection node_1; SET GLOBAL wsrep_provider_options='gmcast.isolate=1'; +connection node_2; +connection node_3; INSERT INTO t1 VALUES (6, 3); +connection node_2; +connection node_1; SET GLOBAL wsrep_provider_options='gmcast.isolate=0'; +connection node_2; INSERT INTO t1 VALUES (7, 2); +connection node_3; +connection node_1; SET GLOBAL wsrep_provider_options='gmcast.isolate=1'; +connection node_2; +connection node_3; INSERT INTO t1 VALUES (8, 3); +connection node_2; +connection node_1; SET GLOBAL wsrep_provider_options='gmcast.isolate=0'; +connection node_2; +connection node_1a; SET GLOBAL wsrep_provider_options = 'dbug=d,process_primary_configuration'; SET GLOBAL wsrep_provider_options = 'signal=after_shift_to_joining'; SET SESSION wsrep_on = 0; SET SESSION wsrep_on = 0; +connection node_2; INSERT INTO t1 VALUES (9, 2); +connection node_3; +connection node_1a; SET GLOBAL wsrep_provider_options = 'signal=process_primary_configuration'; SET SESSION wsrep_on = 0; SET SESSION wsrep_on = 0; @@ -44,7 +82,10 @@ VARIABLE_NAME VARIABLE_VALUE WSREP_DEBUG_SYNC_WAITERS process_primary_configuration SET GLOBAL wsrep_provider_options = 'signal=process_primary_configuration'; SET GLOBAL wsrep_provider_options = 'dbug='; +connection node_1; DROP TABLE t1; call mtr.add_suppression("WSREP: Rejecting JOIN message from \(.*\): new State Transfer required."); +connection node_2; call mtr.add_suppression("WSREP: Rejecting JOIN message from \(.*\): new State Transfer required."); +connection node_3; call mtr.add_suppression("WSREP: Rejecting JOIN message from \(.*\): new State Transfer required."); diff --git a/mysql-test/suite/galera_3nodes/r/galera_join_with_cc_C.result b/mysql-test/suite/galera_3nodes/r/galera_join_with_cc_C.result index df0a924029c..ea10edfc62c 100644 --- a/mysql-test/suite/galera_3nodes/r/galera_join_with_cc_C.result +++ b/mysql-test/suite/galera_3nodes/r/galera_join_with_cc_C.result @@ -1,44 +1,85 @@ +connection node_2; +connection node_1; +connection node_1; CREATE TABLE t1 (pk INT PRIMARY KEY, node INT) ENGINE=innodb; INSERT INTO t1 VALUES (1, 1); +connection node_2; +connection node_1; SET GLOBAL wsrep_provider_options='gmcast.isolate=1'; +connection node_2; +connection node_3; INSERT INTO t1 VALUES (2, 3); +connection node_2; +connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1; SET wsrep_sync_wait = 0; SET wsrep_on = OFF; SET GLOBAL wsrep_provider_options = 'dbug=d,after_shift_to_joining'; +connection node_1; SET GLOBAL wsrep_provider_options='gmcast.isolate=0'; +connection node_2; INSERT INTO t1 VALUES (3, 2); +connection node_1a; SET SESSION wsrep_on = 0; SET SESSION wsrep_on = 0; +connection node_3; +connection node_1; SET GLOBAL wsrep_provider_options='gmcast.isolate=1'; +connection node_2; +connection node_3; INSERT INTO t1 VALUES (4, 3); +connection node_2; +connection node_1; SET GLOBAL wsrep_provider_options='gmcast.isolate=0'; +connection node_2; INSERT INTO t1 VALUES (5, 2); +connection node_3; +connection node_1a; SET GLOBAL wsrep_provider_options = 'dbug=d,before_send_state_request'; SET GLOBAL wsrep_provider_options = 'signal=after_shift_to_joining'; SET SESSION wsrep_on = 0; SET SESSION wsrep_on = 0; SET GLOBAL wsrep_provider_options = 'dbug='; +connection node_1; SET GLOBAL wsrep_provider_options='gmcast.isolate=1'; +connection node_2; +connection node_3; +connection node_1a; SET GLOBAL wsrep_provider_options = 'dbug=d,after_shift_to_joining'; SET GLOBAL wsrep_provider_options = 'signal=before_send_state_request'; 4 SELECT * FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_debug_sync_waiters'; VARIABLE_NAME VARIABLE_VALUE WSREP_DEBUG_SYNC_WAITERS +connection node_3; INSERT INTO t1 VALUES (6, 3); +connection node_2; +connection node_1; SET GLOBAL wsrep_provider_options='gmcast.isolate=0'; +connection node_2; INSERT INTO t1 VALUES (7, 2); +connection node_3; +connection node_1a; SET SESSION wsrep_on = 0; SET SESSION wsrep_on = 0; SET GLOBAL wsrep_provider_options = 'dbug='; SET GLOBAL wsrep_provider_options = 'dbug=d,process_primary_configuration'; SET GLOBAL wsrep_provider_options = 'signal=after_shift_to_joining'; +connection node_1; SET GLOBAL wsrep_provider_options='gmcast.isolate=1'; +connection node_2; +connection node_3; INSERT INTO t1 VALUES (8, 3); +connection node_2; +connection node_1; SET GLOBAL wsrep_provider_options='gmcast.isolate=0'; +connection node_2; +connection node_1a; SET SESSION wsrep_on = 0; SET SESSION wsrep_on = 0; +connection node_2; INSERT INTO t1 VALUES (9, 2); +connection node_3; +connection node_1a; SET GLOBAL wsrep_provider_options = 'signal=process_primary_configuration'; SET SESSION wsrep_on = 0; SET SESSION wsrep_on = 0; @@ -48,8 +89,11 @@ SET SESSION wsrep_on = 0; SET SESSION wsrep_on = 0; SET GLOBAL wsrep_provider_options = 'dbug='; SET GLOBAL wsrep_provider_options = 'signal=after_shift_to_joining'; +connection node_1; DROP TABLE t1; call mtr.add_suppression("WSREP: Send action {\(.*\), STATE_REQUEST} returned -107 \\(Transport endpoint is not connected\\)"); call mtr.add_suppression("WSREP: Rejecting JOIN message from \(.*\): new State Transfer required."); +connection node_2; call mtr.add_suppression("WSREP: Rejecting JOIN message from \(.*\): new State Transfer required."); +connection node_3; call mtr.add_suppression("WSREP: Rejecting JOIN message from \(.*\): new State Transfer required."); From 309302a3dad5f06cb62b0846dcb8a3671d91ff29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 19 Aug 2020 11:18:56 +0300 Subject: [PATCH 47/70] MDEV-23475 InnoDB performance regression for write-heavy workloads In commit fe39d02f51b96536dccca7ff89faf05e13548877 (MDEV-20638) we removed some wake-up signaling of the master thread that should have been there, to ensure a steady log checkpointing workload. Common sense suggests that the commit omitted some necessary calls to srv_inc_activity_count(). But, an attempt to add the call to trx_flush_log_if_needed_low() as well as to reinstate the function innobase_active_small() did not restore the performance for the case where sync_binlog=1 is set. Therefore, we will revert the entire commit in MariaDB Server 10.2. In MariaDB Server 10.5, adding a srv_inc_activity_count() call to trx_flush_log_if_needed_low() did restore the performance, so we will not revert MDEV-20638 across all versions. --- extra/mariabackup/xtrabackup.cc | 6 ++ storage/innobase/buf/buf0flu.cc | 4 +- storage/innobase/handler/ha_innodb.cc | 48 +++++++++++ storage/innobase/handler/handler0alter.cc | 5 ++ storage/innobase/include/srv0srv.h | 25 ++++-- storage/innobase/row/row0mysql.cc | 2 +- storage/innobase/row/row0trunc.cc | 2 +- storage/innobase/srv/srv0srv.cc | 100 +++++++++++++++++----- storage/innobase/srv/srv0start.cc | 4 +- storage/innobase/trx/trx0roll.cc | 3 + storage/innobase/trx/trx0trx.cc | 6 ++ 11 files changed, 170 insertions(+), 35 deletions(-) diff --git a/extra/mariabackup/xtrabackup.cc b/extra/mariabackup/xtrabackup.cc index 9b3d9f9ea39..4845f51e6b2 100644 --- a/extra/mariabackup/xtrabackup.cc +++ b/extra/mariabackup/xtrabackup.cc @@ -254,6 +254,12 @@ my_bool innobase_locks_unsafe_for_binlog; my_bool innobase_rollback_on_timeout; my_bool innobase_create_status_file; +/* The following counter is used to convey information to InnoDB +about server activity: in selects it is not sensible to call +srv_active_wake_master_thread after each fetch or search, we only do +it every INNOBASE_WAKE_INTERVAL'th step. */ + +#define INNOBASE_WAKE_INTERVAL 32 ulong innobase_active_counter = 0; diff --git a/storage/innobase/buf/buf0flu.cc b/storage/innobase/buf/buf0flu.cc index 84f95f4b5ec..26610337d0d 100644 --- a/storage/innobase/buf/buf0flu.cc +++ b/storage/innobase/buf/buf0flu.cc @@ -3141,7 +3141,7 @@ DECLARE_THREAD(buf_flush_page_cleaner_coordinator)(void*) /* The page_cleaner skips sleep if the server is idle and there are no pending IOs in the buffer pool and there is work to do. */ - if (srv_check_activity(&last_activity) + if (srv_check_activity(last_activity) || buf_get_n_pending_read_ios() || n_flushed == 0) { @@ -3233,7 +3233,7 @@ DECLARE_THREAD(buf_flush_page_cleaner_coordinator)(void*) n_flushed = n_flushed_lru + n_flushed_list; - } else if (srv_check_activity(&last_activity)) { + } else if (srv_check_activity(last_activity)) { ulint n_to_flush; lsn_t lsn_limit = 0; diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 8b58ca57a74..4db7f58b513 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -446,6 +446,14 @@ static TYPELIB innodb_lock_schedule_algorithm_typelib = { NULL }; +/* The following counter is used to convey information to InnoDB +about server activity: in case of normal DML ops it is not +sensible to call srv_active_wake_master_thread after each +operation, we only do it every INNOBASE_WAKE_INTERVAL'th step. */ + +#define INNOBASE_WAKE_INTERVAL 32 +static ulong innobase_active_counter = 0; + /** Allowed values of innodb_change_buffering */ static const char* innobase_change_buffering_values[IBUF_USE_COUNT] = { "none", /* IBUF_USE_NONE */ @@ -1885,6 +1893,23 @@ thd_to_trx_id( } #endif /* WITH_WSREP */ +/********************************************************************//** +Increments innobase_active_counter and every INNOBASE_WAKE_INTERVALth +time calls srv_active_wake_master_thread. This function should be used +when a single database operation may introduce a small need for +server utility activity, like checkpointing. */ +inline +void +innobase_active_small(void) +/*=======================*/ +{ + innobase_active_counter++; + + if ((innobase_active_counter % INNOBASE_WAKE_INTERVAL) == 0) { + srv_active_wake_master_thread(); + } +} + /********************************************************************//** Converts an InnoDB error code to a MySQL error code and also tells to MySQL about a possible transaction rollback inside InnoDB caused by a lock wait @@ -6607,6 +6632,11 @@ ha_innobase::close() MONITOR_INC(MONITOR_TABLE_CLOSE); + /* Tell InnoDB server that there might be work for + utility threads: */ + + srv_active_wake_master_thread(); + DBUG_RETURN(0); } @@ -8321,6 +8351,8 @@ report_error: } func_exit: + innobase_active_small(); + DBUG_RETURN(error_result); } @@ -8991,6 +9023,11 @@ func_exit: error, m_prebuilt->table->flags, m_user_thd); } + /* Tell InnoDB server that there might be work for + utility threads: */ + + innobase_active_small(); + #ifdef WITH_WSREP if (error == DB_SUCCESS && trx->is_wsrep() && wsrep_thd_exec_mode(m_user_thd) == LOCAL_STATE && @@ -9046,6 +9083,11 @@ ha_innobase::delete_row( innobase_srv_conc_exit_innodb(m_prebuilt); + /* Tell the InnoDB server that there might be work for + utility threads: */ + + innobase_active_small(); + #ifdef WITH_WSREP if (error == DB_SUCCESS && trx->is_wsrep() && wsrep_thd_exec_mode(m_user_thd) == LOCAL_STATE @@ -12933,6 +12975,7 @@ create_table_info_t::create_table_update_dict() if (m_flags2 & DICT_TF2_FTS) { if (!innobase_fts_load_stopword(innobase_table, NULL, m_thd)) { dict_table_close(innobase_table, FALSE, FALSE); + srv_active_wake_master_thread(); trx_free_for_mysql(m_trx); DBUG_RETURN(-1); } @@ -13078,6 +13121,11 @@ ha_innobase::create( error = info.create_table_update_dict(); + /* Tell the InnoDB server that there might be work for + utility threads: */ + + srv_active_wake_master_thread(); + DBUG_RETURN(error); } diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index 0f5ac81f663..f0aae491eae 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -8641,6 +8641,11 @@ foreign_fail: log_append_on_checkpoint(NULL); + /* Tell the InnoDB server that there might be work for + utility threads: */ + + srv_active_wake_master_thread(); + if (fail) { for (inplace_alter_handler_ctx** pctx = ctx_array; *pctx; pctx++) { diff --git a/storage/innobase/include/srv0srv.h b/storage/innobase/include/srv0srv.h index 20130541d60..5214953f308 100644 --- a/storage/innobase/include/srv0srv.h +++ b/storage/innobase/include/srv0srv.h @@ -809,6 +809,19 @@ srv_reset_io_thread_op_info(); /** Wake up the purge threads if there is work to do. */ void srv_wake_purge_thread_if_not_active(); +/** Wake up the InnoDB master thread if it was suspended (not sleeping). */ +void +srv_active_wake_master_thread_low(); + +#define srv_active_wake_master_thread() \ + do { \ + if (!srv_read_only_mode) { \ + srv_active_wake_master_thread_low(); \ + } \ + } while (0) +/** Wake up the master thread if it is suspended or being suspended. */ +void +srv_wake_master_thread(); /******************************************************************//** Outputs to a file the output of the InnoDB Monitor. @@ -837,13 +850,13 @@ reading this value as it is only used in heuristics. ulint srv_get_activity_count(void); /*========================*/ - -/** Check if there has been any activity. -@param[in,out] activity_count recent activity count to be returned -if there is a change +/*******************************************************************//** +Check if there has been any activity. @return FALSE if no change in activity counter. */ -bool srv_check_activity(ulint *activity_count); - +ibool +srv_check_activity( +/*===============*/ + ulint old_activity_count); /*!< old activity count */ /******************************************************************//** Increment the server activity counter. */ void diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc index 3370cdca570..446895b8f09 100644 --- a/storage/innobase/row/row0mysql.cc +++ b/storage/innobase/row/row0mysql.cc @@ -3820,7 +3820,7 @@ funct_exit: trx->op_info = ""; - srv_inc_activity_count(); + srv_wake_master_thread(); DBUG_RETURN(err); } diff --git a/storage/innobase/row/row0trunc.cc b/storage/innobase/row/row0trunc.cc index 209767d0fe1..618e161bee4 100644 --- a/storage/innobase/row/row0trunc.cc +++ b/storage/innobase/row/row0trunc.cc @@ -1249,7 +1249,7 @@ row_truncate_complete( ut_ad(!trx_is_started(trx)); - srv_inc_activity_count(); + srv_wake_master_thread(); DBUG_EXECUTE_IF("ib_trunc_crash_after_truncate_done", DBUG_SUICIDE();); diff --git a/storage/innobase/srv/srv0srv.cc b/storage/innobase/srv/srv0srv.cc index 6bf8e3dd8f6..f1216dcd51e 100644 --- a/storage/innobase/srv/srv0srv.cc +++ b/storage/innobase/srv/srv0srv.cc @@ -1982,6 +1982,33 @@ srv_get_active_thread_type(void) return(ret); } +/** Wake up the InnoDB master thread if it was suspended (not sleeping). */ +void +srv_active_wake_master_thread_low() +{ + ut_ad(!srv_read_only_mode); + ut_ad(!srv_sys_mutex_own()); + + srv_inc_activity_count(); + + if (my_atomic_loadlint(&srv_sys.n_threads_active[SRV_MASTER]) == 0) { + srv_slot_t* slot; + + srv_sys_mutex_enter(); + + slot = &srv_sys.sys_threads[SRV_MASTER_SLOT]; + + /* Only if the master thread has been started. */ + + if (slot->in_use) { + ut_a(srv_slot_get_type(slot) == SRV_MASTER); + os_event_set(slot->event); + } + + srv_sys_mutex_exit(); + } +} + /** Wake up the purge threads if there is work to do. */ void srv_wake_purge_thread_if_not_active() @@ -1996,6 +2023,14 @@ srv_wake_purge_thread_if_not_active() } } +/** Wake up the master thread if it is suspended or being suspended. */ +void +srv_wake_master_thread() +{ + srv_inc_activity_count(); + srv_release_threads(SRV_MASTER, 1); +} + /*******************************************************************//** Get current server activity count. We don't hold srv_sys::mutex while reading this value as it is only used in heuristics. @@ -2007,20 +2042,15 @@ srv_get_activity_count(void) return(srv_sys.activity_count); } -/** Check if there has been any activity. -@param[in,out] activity_count recent activity count to be returned -if there is a change +/*******************************************************************//** +Check if there has been any activity. @return FALSE if no change in activity counter. */ -bool srv_check_activity(ulint *activity_count) +ibool +srv_check_activity( +/*===============*/ + ulint old_activity_count) /*!< in: old activity count */ { - ulint new_activity_count= srv_sys.activity_count; - if (new_activity_count != *activity_count) - { - *activity_count= new_activity_count; - return true; - } - - return false; + return(srv_sys.activity_count != old_activity_count); } /********************************************************************//** @@ -2427,30 +2457,52 @@ DECLARE_THREAD(srv_master_thread)( slot = srv_reserve_slot(SRV_MASTER); ut_a(slot == srv_sys.sys_threads); +loop: while (srv_shutdown_state <= SRV_SHUTDOWN_INITIATED) { srv_master_sleep(); MONITOR_INC(MONITOR_MASTER_THREAD_SLEEP); - if (srv_check_activity(&old_activity_count)) { + if (srv_check_activity(old_activity_count)) { + old_activity_count = srv_get_activity_count(); srv_master_do_active_tasks(); } else { srv_master_do_idle_tasks(); } } - ut_ad(srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS - || srv_shutdown_state == SRV_SHUTDOWN_CLEANUP); - - if (srv_shutdown_state == SRV_SHUTDOWN_CLEANUP - && srv_fast_shutdown < 2) { - srv_shutdown(srv_fast_shutdown == 0); + switch (srv_shutdown_state) { + case SRV_SHUTDOWN_NONE: + case SRV_SHUTDOWN_INITIATED: + break; + case SRV_SHUTDOWN_FLUSH_PHASE: + case SRV_SHUTDOWN_LAST_PHASE: + ut_ad(0); + /* fall through */ + case SRV_SHUTDOWN_EXIT_THREADS: + /* srv_init_abort() must have been invoked */ + case SRV_SHUTDOWN_CLEANUP: + if (srv_shutdown_state == SRV_SHUTDOWN_CLEANUP + && srv_fast_shutdown < 2) { + srv_shutdown(srv_fast_shutdown == 0); + } + srv_suspend_thread(slot); + my_thread_end(); + os_thread_exit(); } + srv_main_thread_op_info = "suspending"; + srv_suspend_thread(slot); - my_thread_end(); - os_thread_exit(); - OS_THREAD_DUMMY_RETURN; + + /* DO NOT CHANGE THIS STRING. innobase_start_or_create_for_mysql() + waits for database activity to die down when converting < 4.1.x + databases, and relies on this string being exactly as it is. InnoDB + manual also mentions this string in several places. */ + srv_main_thread_op_info = "waiting for server activity"; + + srv_resume_thread(slot); + goto loop; } /** Check if purge should stop. @@ -2647,13 +2699,15 @@ srv_do_purge(ulint* n_total_purged ++n_use_threads; } - } else if (srv_check_activity(&old_activity_count) + } else if (srv_check_activity(old_activity_count) && n_use_threads > 1) { /* History length same or smaller since last snapshot, use fewer threads. */ --n_use_threads; + + old_activity_count = srv_get_activity_count(); } /* Ensure that the purge threads are less than what diff --git a/storage/innobase/srv/srv0start.cc b/storage/innobase/srv/srv0start.cc index a8f2b78d0a8..0d8ebbe98cd 100644 --- a/storage/innobase/srv/srv0start.cc +++ b/storage/innobase/srv/srv0start.cc @@ -1238,7 +1238,7 @@ srv_shutdown_all_bg_threads() if (srv_start_state_is_set(SRV_START_STATE_MASTER)) { /* c. We wake the master thread so that it exits */ - srv_inc_activity_count(); + srv_wake_master_thread(); } if (srv_start_state_is_set(SRV_START_STATE_PURGE)) { @@ -2762,7 +2762,7 @@ srv_shutdown_bg_undo_sources() fts_optimize_shutdown(); dict_stats_shutdown(); while (row_get_background_drop_list_len_low()) { - srv_inc_activity_count(); + srv_wake_master_thread(); os_thread_yield(); } srv_undo_sources = false; diff --git a/storage/innobase/trx/trx0roll.cc b/storage/innobase/trx/trx0roll.cc index ef3d93cd65e..c5f70452bf2 100644 --- a/storage/innobase/trx/trx0roll.cc +++ b/storage/innobase/trx/trx0roll.cc @@ -124,6 +124,9 @@ trx_rollback_to_savepoint_low( mem_heap_free(heap); + /* There might be work for utility threads.*/ + srv_active_wake_master_thread(); + MONITOR_DEC(MONITOR_TRX_ACTIVE); } diff --git a/storage/innobase/trx/trx0trx.cc b/storage/innobase/trx/trx0trx.cc index 0dbd985b6c3..d4cd020b321 100644 --- a/storage/innobase/trx/trx0trx.cc +++ b/storage/innobase/trx/trx0trx.cc @@ -1804,6 +1804,12 @@ trx_commit_in_memory( } trx->commit_lsn = lsn; + + /* Tell server some activity has happened, since the trx + does changes something. Background utility threads like + master thread, purge thread or page_cleaner thread might + have some work to do. */ + srv_active_wake_master_thread(); } ut_ad(!trx->rsegs.m_noredo.undo); From 09dd06f14aaf4ba8088f837625020617e5eca7ea Mon Sep 17 00:00:00 2001 From: Daniele Sciascia Date: Tue, 18 Aug 2020 10:47:15 +0200 Subject: [PATCH 48/70] MDEV-22443 wsrep::runtime_error on START TRANSACTION This happens with global wsrep_on disabled and local wsrep_on enabled. The fix consists in avoiding sync wait when global wsrep_on is disabled. --- mysql-test/suite/wsrep/r/MDEV-22443.result | 3 +++ mysql-test/suite/wsrep/t/MDEV-22443.cnf | 8 ++++++++ mysql-test/suite/wsrep/t/MDEV-22443.test | 12 ++++++++++++ sql/wsrep_mysqld.cc | 2 +- 4 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 mysql-test/suite/wsrep/r/MDEV-22443.result create mode 100644 mysql-test/suite/wsrep/t/MDEV-22443.cnf create mode 100644 mysql-test/suite/wsrep/t/MDEV-22443.test diff --git a/mysql-test/suite/wsrep/r/MDEV-22443.result b/mysql-test/suite/wsrep/r/MDEV-22443.result new file mode 100644 index 00000000000..ea07cbec5a0 --- /dev/null +++ b/mysql-test/suite/wsrep/r/MDEV-22443.result @@ -0,0 +1,3 @@ +SET SESSION wsrep_sync_wait=15; +SET SESSION wsrep_on=1; +START TRANSACTION READ WRITE; diff --git a/mysql-test/suite/wsrep/t/MDEV-22443.cnf b/mysql-test/suite/wsrep/t/MDEV-22443.cnf new file mode 100644 index 00000000000..851f2999a83 --- /dev/null +++ b/mysql-test/suite/wsrep/t/MDEV-22443.cnf @@ -0,0 +1,8 @@ +!include ../my.cnf + +[mysqld.1] +wsrep-on=OFF +binlog-format=ROW +wsrep-provider=none +wsrep-cluster-address='gcomm://' +innodb_autoinc_lock_mode=2 diff --git a/mysql-test/suite/wsrep/t/MDEV-22443.test b/mysql-test/suite/wsrep/t/MDEV-22443.test new file mode 100644 index 00000000000..674cb5ae2d8 --- /dev/null +++ b/mysql-test/suite/wsrep/t/MDEV-22443.test @@ -0,0 +1,12 @@ +# +# MDEV-22443: terminate called after throwing an instance of +# 'wsrep::runtime_error' in std::terminate on START TRANSACTION +# + +--source include/have_innodb.inc +--source include/have_wsrep.inc +--source include/have_binlog_format_row.inc + +SET SESSION wsrep_sync_wait=15; +SET SESSION wsrep_on=1; +START TRANSACTION READ WRITE; diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc index 14be333c107..fab47fc03d0 100644 --- a/sql/wsrep_mysqld.cc +++ b/sql/wsrep_mysqld.cc @@ -1092,7 +1092,7 @@ bool wsrep_must_sync_wait (THD* thd, uint mask) mysql_mutex_lock(&thd->LOCK_thd_data); ret= (thd->variables.wsrep_sync_wait & mask) && thd->wsrep_client_thread && - thd->variables.wsrep_on && + WSREP_ON && thd->variables.wsrep_on && !(thd->variables.wsrep_dirty_reads && !is_update_query(thd->lex->sql_command)) && !thd->in_active_multi_stmt_transaction() && From fe3284b2cc8cc4f948aa234b3c6f9f2f8cffa027 Mon Sep 17 00:00:00 2001 From: Daniele Sciascia Date: Tue, 18 Aug 2020 10:56:56 +0200 Subject: [PATCH 49/70] MDEV-23092 SIGABRT when setting invalid wsrep_provider Some invalid wsrep_provider paths may be interpreted as a valid directory. For example '/invalid/libgalera_smm.so' with UTF character set is interpreted as '/', which is a valid directory. A early check that wsrep_provider should not be a directory fixes it. --- mysql-test/suite/wsrep/r/MDEV-23092.result | 13 +++++++++++++ mysql-test/suite/wsrep/t/MDEV-23092.cnf | 8 ++++++++ mysql-test/suite/wsrep/t/MDEV-23092.test | 22 ++++++++++++++++++++++ sql/wsrep_var.cc | 6 ++++++ 4 files changed, 49 insertions(+) create mode 100644 mysql-test/suite/wsrep/r/MDEV-23092.result create mode 100644 mysql-test/suite/wsrep/t/MDEV-23092.cnf create mode 100644 mysql-test/suite/wsrep/t/MDEV-23092.test diff --git a/mysql-test/suite/wsrep/r/MDEV-23092.result b/mysql-test/suite/wsrep/r/MDEV-23092.result new file mode 100644 index 00000000000..d88aacf7d5c --- /dev/null +++ b/mysql-test/suite/wsrep/r/MDEV-23092.result @@ -0,0 +1,13 @@ +SET COLLATION_CONNECTION='utf16le_bin'; +SET GLOBAL wsrep_provider='/invalid/path/libgalera_smm.so'; +ERROR 42000: Variable 'wsrep_provider' can't be set to the value of '/' +SET GLOBAL wsrep_cluster_address='OFF'; +SET GLOBAL wsrep_slave_threads=10; +SELECT 1; +1 +1 +SET GLOBAL wsrep_cluster_address='gcomm://'; +SET GLOBAL wsrep_slave_threads=DEFAULT; +CALL mtr.add_suppression("wsrep_load()"); +CALL mtr.add_suppression("Failed to create a new provider"); +CALL mtr.add_suppression("Failed to load provider"); diff --git a/mysql-test/suite/wsrep/t/MDEV-23092.cnf b/mysql-test/suite/wsrep/t/MDEV-23092.cnf new file mode 100644 index 00000000000..851f2999a83 --- /dev/null +++ b/mysql-test/suite/wsrep/t/MDEV-23092.cnf @@ -0,0 +1,8 @@ +!include ../my.cnf + +[mysqld.1] +wsrep-on=OFF +binlog-format=ROW +wsrep-provider=none +wsrep-cluster-address='gcomm://' +innodb_autoinc_lock_mode=2 diff --git a/mysql-test/suite/wsrep/t/MDEV-23092.test b/mysql-test/suite/wsrep/t/MDEV-23092.test new file mode 100644 index 00000000000..92a6e392013 --- /dev/null +++ b/mysql-test/suite/wsrep/t/MDEV-23092.test @@ -0,0 +1,22 @@ +# +# MDEV-23092: SIGABRT in wsrep::server_state::provider when setting +# invalid wsrep_provider (on optimized builds) +# + +--source include/have_innodb.inc +--source include/have_wsrep.inc +--source include/have_binlog_format_row.inc + +SET COLLATION_CONNECTION='utf16le_bin'; +--error 1231 +SET GLOBAL wsrep_provider='/invalid/path/libgalera_smm.so'; +SET GLOBAL wsrep_cluster_address='OFF'; +SET GLOBAL wsrep_slave_threads=10; +SELECT 1; + +SET GLOBAL wsrep_cluster_address='gcomm://'; +SET GLOBAL wsrep_slave_threads=DEFAULT; + +CALL mtr.add_suppression("wsrep_load()"); +CALL mtr.add_suppression("Failed to create a new provider"); +CALL mtr.add_suppression("Failed to load provider"); diff --git a/sql/wsrep_var.cc b/sql/wsrep_var.cc index 64362d1c9e2..3649153e172 100644 --- a/sql/wsrep_var.cc +++ b/sql/wsrep_var.cc @@ -320,6 +320,12 @@ static int wsrep_provider_verify (const char* provider_str) { return 1; } + + if (MY_S_ISDIR(f_stat.st_mode)) + { + return 1; + } + return 0; } From f8bf5b0f8431493975f8f4488d0bef6e0e4e289e Mon Sep 17 00:00:00 2001 From: Daniele Sciascia Date: Tue, 18 Aug 2020 11:03:12 +0200 Subject: [PATCH 50/70] MDEV-23466 SIGABRT on SELECT WSREP_LAST_SEEN_GTID SELECT WSREP_LAST_SEEN_GTID aborts the server if no provider is loaded. --- mysql-test/suite/wsrep/r/MDEV-23466.result | 3 +++ mysql-test/suite/wsrep/t/MDEV-23466.cnf | 8 ++++++++ mysql-test/suite/wsrep/t/MDEV-23466.test | 10 ++++++++++ sql/item_strfunc.cc | 10 +++++++--- 4 files changed, 28 insertions(+), 3 deletions(-) create mode 100644 mysql-test/suite/wsrep/r/MDEV-23466.result create mode 100644 mysql-test/suite/wsrep/t/MDEV-23466.cnf create mode 100644 mysql-test/suite/wsrep/t/MDEV-23466.test diff --git a/mysql-test/suite/wsrep/r/MDEV-23466.result b/mysql-test/suite/wsrep/r/MDEV-23466.result new file mode 100644 index 00000000000..6d167c9c95e --- /dev/null +++ b/mysql-test/suite/wsrep/r/MDEV-23466.result @@ -0,0 +1,3 @@ +SELECT WSREP_LAST_SEEN_GTID(); +WSREP_LAST_SEEN_GTID() +00000000-0000-0000-0000-000000000000:-1 diff --git a/mysql-test/suite/wsrep/t/MDEV-23466.cnf b/mysql-test/suite/wsrep/t/MDEV-23466.cnf new file mode 100644 index 00000000000..851f2999a83 --- /dev/null +++ b/mysql-test/suite/wsrep/t/MDEV-23466.cnf @@ -0,0 +1,8 @@ +!include ../my.cnf + +[mysqld.1] +wsrep-on=OFF +binlog-format=ROW +wsrep-provider=none +wsrep-cluster-address='gcomm://' +innodb_autoinc_lock_mode=2 diff --git a/mysql-test/suite/wsrep/t/MDEV-23466.test b/mysql-test/suite/wsrep/t/MDEV-23466.test new file mode 100644 index 00000000000..2615298226e --- /dev/null +++ b/mysql-test/suite/wsrep/t/MDEV-23466.test @@ -0,0 +1,10 @@ +# +# MDEV-23466: SIGABRT in wsrep::server_state::provider on +# SELECT WSREP_LAST_SEEN_GTID() on optimized builds +# + +--source include/have_innodb.inc +--source include/have_wsrep.inc +--source include/have_binlog_format_row.inc + +SELECT WSREP_LAST_SEEN_GTID(); diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index c735f697986..ea14e9d44f8 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -5379,9 +5379,13 @@ String *Item_func_wsrep_last_written_gtid::val_str_ascii(String *str) String *Item_func_wsrep_last_seen_gtid::val_str_ascii(String *str) { - /* TODO: Should call Wsrep_server_state.instance().last_committed_gtid() - instead. */ - wsrep::gtid gtid= Wsrep_server_state::instance().provider().last_committed_gtid(); + wsrep::gtid gtid= wsrep::gtid::undefined(); + if (Wsrep_server_state::instance().is_provider_loaded()) + { + /* TODO: Should call Wsrep_server_state.instance().last_committed_gtid() + instead. */ + gtid= Wsrep_server_state::instance().provider().last_committed_gtid(); + } if (gtid_str.alloc(wsrep::gtid_c_str_len())) { my_error(ER_OUTOFMEMORY, wsrep::gtid_c_str_len()); From b205e478a3ba7dfce69bba9e6187d412823b4949 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 19 Aug 2020 15:47:11 +0300 Subject: [PATCH 51/70] Work around MDEV-23416 (change Warning to Note) Ever since MDEV-15053 changed something in the page flushing, we are occasionally observing pending I/O for a data file that is about to be deleted. fil_check_pending_io(): Change the Warning to a note. This message was already made less frequent in commit dcc0baf5405b220384b9e1e07d8b9e3ff97b60f4 (10.5.4) and commit 65f831d17c84900c1faea49164688e2f5ce59563 (10.3.24, 10.4.14). --- storage/innobase/fil/fil0fil.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc index 5e6bd9575b1..d8b588b4e30 100644 --- a/storage/innobase/fil/fil0fil.cc +++ b/storage/innobase/fil/fil0fil.cc @@ -1995,7 +1995,7 @@ fil_check_pending_io( /* Give a warning every 10 second, starting after 1 second */ if ((count % 500) == 50) { - ib::warn() << "Trying to delete" + ib::info() << "Trying to delete" " tablespace '" << space->name << "' but there are " << space->n_pending_flushes From 22c4a7512f8dc3f2d2586a856b362ad97ab2bf7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Thu, 20 Aug 2020 08:34:55 +0300 Subject: [PATCH 52/70] MDEV-23514 Race conditions between ROLLBACK and ALTER TABLE Since commit 1509363970e9cb574005e3af560299c055dda983 (MDEV-23484) the rollback of InnoDB transactions is no longer protected by dict_operation_lock. Removing that protection revealed a race condition between transaction rollback and the rollback of an online table-rebuilding operation (OPTIMIZE TABLE, or any online ALTER TABLE that is rebuilding the table). row_undo_mod_clust(): Re-check dict_index_is_online_ddl() after acquiring index->lock, similar to how row_undo_ins_remove_clust_rec() is doing it. Because innobase_online_rebuild_log_free() is holding exclusive index->lock while invoking row_log_free(), this re-check will ensure that row_log_table_low() will not be invoked when index->online_log=NULL. A different race condition is possible between the rollback of a recovered transaction and the start of online secondary index creation. Because prepare_inplace_alter_table_dict() is not acquiring an InnoDB table lock in this case, and because recovered transactions are not covered by metadata locks (MDL), the dict_table_t::indexes could be modified by prepare_inplace_alter_table_dict() while the rollback of a recovered transaction is being executed. Normal transactions would be covered by MDL, and during prepare_inplace_alter_table_dict() we do hold MDL_EXCLUSIVE, that is, an online ALTER TABLE operation may not execute concurrently with other transactions that have accessed the table. row_undo(): To prevent a race condition with prepare_inplace_alter_table_dict(), acquire dict_operation_lock for all recovered transactions. Before MDEV-23484 we used to acquire it for all transactions, not only recovered ones. Note: row_merge_drop_indexes() would not invoke dict_index_remove_from_cache() while transactional locks exist on the table, or while any thread is holding an open table handle. OK, it does that for FULLTEXT INDEX, but ADD FULLTEXT INDEX is not supported as an online operation, and therefore prepare_inplace_alter_table_dict() would acquire a table S lock, which cannot succeed as long as recovered transactions on the table exist, because they would hold a conflicting IX lock on the table. --- storage/innobase/handler/handler0alter.cc | 4 ++-- storage/innobase/row/row0umod.cc | 12 +----------- storage/innobase/row/row0undo.cc | 17 +++++++++++++++++ 3 files changed, 20 insertions(+), 13 deletions(-) diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index f0aae491eae..09bfc5f5503 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -8267,11 +8267,11 @@ ha_innobase::commit_inplace_alter_table( /* Exclusively lock the table, to ensure that no other transaction is holding locks on the table while we - change the table definition. The MySQL meta-data lock + change the table definition. The meta-data lock (MDL) should normally guarantee that no conflicting locks exist. However, FOREIGN KEY constraints checks and any transactions collected during crash recovery could be - holding InnoDB locks only, not MySQL locks. */ + holding InnoDB locks only, not MDL. */ dberr_t error = row_merge_lock_table( m_prebuilt->trx, ctx->old_table, LOCK_X); diff --git a/storage/innobase/row/row0umod.cc b/storage/innobase/row/row0umod.cc index b1cc994cdd8..0de0760834e 100644 --- a/storage/innobase/row/row0umod.cc +++ b/storage/innobase/row/row0umod.cc @@ -319,17 +319,7 @@ row_undo_mod_clust( ut_ad(err == DB_SUCCESS || err == DB_OUT_OF_FILE_SPACE); } - /* Online rebuild cannot be initiated while we are holding - dict_operation_lock and index->lock. (It can be aborted.) */ - ut_ad(online || !dict_index_is_online_ddl(index)); - - if (err == DB_SUCCESS && online) { - - ut_ad(rw_lock_own_flagged( - &index->lock, - RW_LOCK_FLAG_S | RW_LOCK_FLAG_X - | RW_LOCK_FLAG_SX)); - + if (err == DB_SUCCESS && online && dict_index_is_online_ddl(index)) { switch (node->rec_type) { case TRX_UNDO_DEL_MARK_REC: row_log_table_insert( diff --git a/storage/innobase/row/row0undo.cc b/storage/innobase/row/row0undo.cc index 34b55f25527..185a71e670b 100644 --- a/storage/innobase/row/row0undo.cc +++ b/storage/innobase/row/row0undo.cc @@ -279,6 +279,19 @@ row_undo( ? UNDO_NODE_INSERT : UNDO_NODE_MODIFY; } + /* Prevent prepare_inplace_alter_table_dict() from adding + dict_table_t::indexes while we are processing the record. + Recovered transactions are not protected by MDL, and the + secondary index creation is not protected by table locks + for online operation. (A table lock would only be acquired + when committing the ALTER TABLE operation.) */ + const bool locked_data_dict = UNIV_UNLIKELY(trx->is_recovered) + && !trx->dict_operation_lock_mode; + + if (UNIV_UNLIKELY(locked_data_dict)) { + row_mysql_freeze_data_dictionary(trx); + } + dberr_t err; if (node->state == UNDO_NODE_INSERT) { @@ -291,6 +304,10 @@ row_undo( err = row_undo_mod(node, thr); } + if (UNIV_UNLIKELY(locked_data_dict)) { + row_mysql_unfreeze_data_dictionary(trx); + } + /* Do some cleanup */ btr_pcur_close(&(node->pcur)); From e9d6f1c7ac0b33f565301ca1f269a36adc35270b Mon Sep 17 00:00:00 2001 From: Thirunarayanan Balathandayuthapani Date: Tue, 18 Aug 2020 13:41:03 +0530 Subject: [PATCH 53/70] MDEV-23452 Assertion `buf_page_get_io_fix(bpage) == BUF_IO_NONE' failed in buf_page_set_sticky commit a1f899a8abb6bb0b046db28d6da9dd4b7fc3c8c4 (MDEV-23233) added the code to make page sticky. So that InnoDB can't allow the page to be grabbed by other thread while doing lazy drop of ahi. But the block could be in flush list and it could have io_fix value as BUF_IO_WRITE. It could lead to the failure in buf_page_set_sticky(). buf_page_create(): If btr_search_drop_page_hash_index() must be invoked, take x-latch on the block. If the block io_fix value is other than BUF_IO_NONE, release the buffer pool mutex and page hash lock and wait for I/O to complete. --- storage/innobase/buf/buf0buf.cc | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc index ad53a11ea66..a1fd7c48301 100644 --- a/storage/innobase/buf/buf0buf.cc +++ b/storage/innobase/buf/buf0buf.cc @@ -5591,7 +5591,21 @@ buf_page_create( if (drop_hash_entry) { mutex_enter(&block->mutex); - buf_page_set_sticky(&block->page); + /* Avoid a hang if I/O is going on. Release + the buffer pool mutex and page hash lock + and wait for I/O to complete */ + while (buf_block_get_io_fix(block) != BUF_IO_NONE) { + buf_block_fix(block); + mutex_exit(&block->mutex); + buf_pool_mutex_exit(buf_pool); + rw_lock_x_unlock(hash_lock); + + buf_pool_mutex_enter(buf_pool); + rw_lock_x_lock(hash_lock); + mutex_enter(&block->mutex); + buf_block_unfix(block); + } + rw_lock_x_lock(&block->lock); mutex_exit(&block->mutex); } #endif @@ -5603,11 +5617,7 @@ buf_page_create( #ifdef BTR_CUR_HASH_ADAPT if (drop_hash_entry) { btr_search_drop_page_hash_index(block); - buf_pool_mutex_enter(buf_pool); - mutex_enter(&block->mutex); - buf_page_unset_sticky(&block->page); - mutex_exit(&block->mutex); - buf_pool_mutex_exit(buf_pool); + rw_lock_x_unlock(&block->lock); } #endif /* BTR_CUR_HASH_ADAPT */ From a79c25789474f32097e083d3b4953927c04909bc Mon Sep 17 00:00:00 2001 From: Thirunarayanan Balathandayuthapani Date: Thu, 20 Aug 2020 11:38:10 +0530 Subject: [PATCH 54/70] MDEV-23452 Assertion `buf_page_get_io_fix(bpage) == BUF_IO_NONE' failed in buf_page_set_sticky - Adding os_thread_yield() in buf_page_create() to avoid the continuous buffer pool mutex acquistions. --- storage/innobase/buf/buf0buf.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc index a1fd7c48301..5858d9cd2d3 100644 --- a/storage/innobase/buf/buf0buf.cc +++ b/storage/innobase/buf/buf0buf.cc @@ -5600,6 +5600,8 @@ buf_page_create( buf_pool_mutex_exit(buf_pool); rw_lock_x_unlock(hash_lock); + os_thread_yield(); + buf_pool_mutex_enter(buf_pool); rw_lock_x_lock(hash_lock); mutex_enter(&block->mutex); From 65c43bcfe276dba545b1985443322fbb07c1a49a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Thu, 20 Aug 2020 13:35:26 +0300 Subject: [PATCH 55/70] After-merge fix of the Windows build --- include/my_stacktrace.h | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/include/my_stacktrace.h b/include/my_stacktrace.h index 27dcd9ff130..20b86f45232 100644 --- a/include/my_stacktrace.h +++ b/include/my_stacktrace.h @@ -42,19 +42,21 @@ C_MODE_START #if defined(HAVE_STACKTRACE) || defined(HAVE_BACKTRACE) -void my_setup_stacktrace(void); void my_print_stacktrace(uchar* stack_bottom, ulong thread_stack, my_bool silent); int my_safe_print_str(const char* val, size_t max_len); void my_write_core(int sig); -#if BACKTRACE_DEMANGLE +# if BACKTRACE_DEMANGLE char *my_demangle(const char *mangled_name, int *status); -#endif /* BACKTRACE_DEMANGLE */ -#ifdef __WIN__ +# endif /* BACKTRACE_DEMANGLE */ +# ifdef __WIN__ +# define my_setup_stacktrace() void my_set_exception_pointers(EXCEPTION_POINTERS *ep); -#endif /* __WIN__ */ +# else +void my_setup_stacktrace(void); +# endif /* __WIN__ */ #else -#define my_setup_stacktrace() +# define my_setup_stacktrace() #endif /* ! (defined(HAVE_STACKTRACE) || defined(HAVE_BACKTRACE)) */ #ifndef _WIN32 From 76a922700184f9aef021719f3f5b165a60a1ed50 Mon Sep 17 00:00:00 2001 From: Monty Date: Thu, 20 Aug 2020 17:28:12 +0300 Subject: [PATCH 56/70] Added support of WITH_GPROF to cmake --- BUILD/SETUP.sh | 5 +++-- CMakeLists.txt | 7 ++++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/BUILD/SETUP.sh b/BUILD/SETUP.sh index 82262098d7a..d9d8b977644 100755 --- a/BUILD/SETUP.sh +++ b/BUILD/SETUP.sh @@ -315,10 +315,11 @@ gcov_configs="--with-gcov" # gprof -gprof_compile_flags="-O2 -pg -g" +gprof_compile_flags="-O2" +# Rest of the flags are set in CmakeFile.txt gprof_link_flags="--disable-shared $static_link" -disable_gprof_plugins="--with-zlib-dir=bundled --without-plugin-oqgraph --without-plugin-mroonga" +disable_gprof_plugins="--with-zlib-dir=bundled --without-plugin-oqgraph --without-plugin-mroonga --with-gprof" disable_asan_plugins="--without-plugin-rocksdb" diff --git a/CMakeLists.txt b/CMakeLists.txt index 80fac4b2ccc..36922e04368 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -242,13 +242,18 @@ IF (WITH_MSAN) MY_CHECK_AND_SET_COMPILER_FLAG("-fsanitize=memory -fsanitize-memory-track-origins -U_FORTIFY_SOURCE" DEBUG RELWITHDEBINFO) ENDIF() +OPTION(WITH_GPROF "Enable profilingg with gprof" OFF) +IF (WITH_GPROF) + MY_CHECK_AND_SET_COMPILER_FLAG("-pg -g -no-pie -fPIC") +ENDIF() + # Be nice to profilers etc MY_CHECK_AND_SET_COMPILER_FLAG("-fno-omit-frame-pointer" RELWITHDEBINFO) # enable security hardening features, like most distributions do # in our benchmarks that costs about ~1% of performance, depending on the load OPTION(SECURITY_HARDENED "Use security-enhancing compiler features (stack protector, relro, etc)" ON) -IF(SECURITY_HARDENED AND NOT WITH_ASAN AND NOT WITH_UBSAN AND NOT WITH_TSAN) +IF(SECURITY_HARDENED AND NOT WITH_ASAN AND NOT WITH_UBSAN AND NOT WITH_TSAN AND NOT WITH_GPROF) # security-enhancing flags MY_CHECK_AND_SET_COMPILER_FLAG("-pie -fPIC") MY_CHECK_AND_SET_LINKER_FLAG("-Wl,-z,relro,-z,now") From 2c9be1e6ee2c611fde9b3ec4014997682c7295df Mon Sep 17 00:00:00 2001 From: Monty Date: Thu, 20 Aug 2020 17:29:40 +0300 Subject: [PATCH 57/70] Fixed wrong value of "wsrep" in SHOW STATUS If WSREP was not initalized SHOW GLOBAL STATUS could have a random value of "wsrep" --- sql/wsrep_var.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sql/wsrep_var.cc b/sql/wsrep_var.cc index 70a4bc8c470..40689b7cf88 100644 --- a/sql/wsrep_var.cc +++ b/sql/wsrep_var.cc @@ -948,6 +948,11 @@ int wsrep_show_status (THD *thd, SHOW_VAR *var, char *buff) var->type= SHOW_ARRAY; var->value= (char *) &mysql_status_vars; } + else + { + var->type= SHOW_CHAR; + var->value= (char*) "0"; + } return 0; } From b1ba3a199cf00b9e4e39d73710a89a80964b7eef Mon Sep 17 00:00:00 2001 From: Monty Date: Thu, 20 Aug 2020 17:32:00 +0300 Subject: [PATCH 58/70] Reduce number of syncs to create a transactional aria table from 6 to 3 This was possible because we can create any missing aria files from the aria transactional log The 3 remaining syncs are: - .frm file - Directory where frm file is - Aria log file --- storage/maria/ma_create.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/storage/maria/ma_create.c b/storage/maria/ma_create.c index 510edce5853..25c44f7c90e 100644 --- a/storage/maria/ma_create.c +++ b/storage/maria/ma_create.c @@ -1173,7 +1173,14 @@ int maria_create(const char *name, enum data_file_type datafile_type, FALSE, TRUE)) goto err; my_free(log_data); + + /* + We don't need to sync directory as we can use the log to recreate + the index and data files if needed. + */ + sync_dir= 0; } + DBUG_ASSERT(!internal_table || sync_dir == 0); if (!(flags & HA_DONT_TOUCH_DATA)) { @@ -1211,7 +1218,7 @@ int maria_create(const char *name, enum data_file_type datafile_type, if ((dfile= mysql_file_create_with_symlink(key_file_dfile, dlinkname_ptr, dfilename, 0, create_mode, - MYF(MY_WME | create_flag | sync_dir))) < 0) + MYF(MY_WME | create_flag))) < 0) goto err; errpos=3; From 3ef65f27839c0896e28dc37c1d3d3340f571b79c Mon Sep 17 00:00:00 2001 From: Monty Date: Thu, 20 Aug 2020 19:33:33 +0300 Subject: [PATCH 59/70] Added DBUG_PUSH_EMPTY and DBUG_POP_EMPTY to speed up DBUG --- include/my_dbug.h | 5 +++++ mysys/thr_mutex.c | 4 ++-- sql/filesort.cc | 4 ++-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/include/my_dbug.h b/include/my_dbug.h index f0c74ab485c..fa5b4c126d1 100644 --- a/include/my_dbug.h +++ b/include/my_dbug.h @@ -106,6 +106,9 @@ extern int (*dbug_sanity)(void); (_db_keyword_(0,(keyword), 1) ? (a1) : (a2)) #define DBUG_PRINT(keyword,arglist) \ do if (_db_pargs_(__LINE__,keyword)) _db_doprnt_ arglist; while(0) + +#define DBUG_PUSH_EMPTY if (_dbug_on_) { DBUG_PUSH(""); } +#define DBUG_POP_EMPTY if (_dbug_on_) { DBUG_POP(); } #define DBUG_PUSH(a1) _db_push_ (a1) #define DBUG_POP() _db_pop_ () #define DBUG_SET(a1) _db_set_ (a1) @@ -172,6 +175,8 @@ extern void _db_suicide_(void); #define DBUG_EVALUATE(keyword,a1,a2) (a2) #define DBUG_EVALUATE_IF(keyword,a1,a2) (a2) #define DBUG_PRINT(keyword,arglist) do { } while(0) +#define DBUG_PUSH_EMPTY do { } while(0) +#define DBUG_POP_EMPTY do { } while(0) #define DBUG_PUSH(a1) do { } while(0) #define DBUG_SET(a1) do { } while(0) #define DBUG_SET_INITIAL(a1) do { } while(0) diff --git a/mysys/thr_mutex.c b/mysys/thr_mutex.c index 9db1e0efabf..2a8e54621c0 100644 --- a/mysys/thr_mutex.c +++ b/mysys/thr_mutex.c @@ -233,7 +233,7 @@ int safe_mutex_lock(safe_mutex_t *mp, myf my_flags, const char *file, int error; DBUG_PRINT("mutex", ("%s (0x%lx) locking", mp->name ? mp->name : "Null", (ulong) mp)); - DBUG_PUSH(""); + DBUG_PUSH_EMPTY; pthread_mutex_lock(&mp->global); if (!mp->file) @@ -395,7 +395,7 @@ int safe_mutex_lock(safe_mutex_t *mp, myf my_flags, const char *file, } end: - DBUG_POP(); + DBUG_POP_EMPTY; if (!error) DBUG_PRINT("mutex", ("%s (0x%lx) locked", mp->name, (ulong) mp)); return error; diff --git a/sql/filesort.cc b/sql/filesort.cc index 90fbde6f6c8..2ce532308a2 100644 --- a/sql/filesort.cc +++ b/sql/filesort.cc @@ -215,7 +215,7 @@ SORT_INFO *filesort(THD *thd, TABLE *table, Filesort *filesort, DBUG_EXECUTE("info",TEST_filesort(filesort->sortorder, s_length);); #ifdef SKIP_DBUG_IN_FILESORT - DBUG_PUSH(""); /* No DBUG here */ + DBUG_PUSH_EMPTY; /* No DBUG here */ #endif SORT_INFO *sort; TABLE_LIST *tab= table->pos_in_table_list; @@ -493,7 +493,7 @@ SORT_INFO *filesort(THD *thd, TABLE *table, Filesort *filesort, sort->examined_rows= param.examined_rows; sort->return_rows= num_rows; #ifdef SKIP_DBUG_IN_FILESORT - DBUG_POP(); /* Ok to DBUG */ + DBUG_POP_EMPTY; /* Ok to DBUG */ #endif DBUG_PRINT("exit", From 29d9df16ffd725cb236238d33bd75f0722256573 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Fri, 21 Aug 2020 08:52:45 +0300 Subject: [PATCH 60/70] Revert "MDEV-21039: Server fails to start with unknown mysqld_safe options" This reverts commit 5796021174fd7096267003b999e02d6cf98f555b. --- scripts/mysqld_safe.sh | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/scripts/mysqld_safe.sh b/scripts/mysqld_safe.sh index 3d3d4141dc5..87dc81e8b5f 100644 --- a/scripts/mysqld_safe.sh +++ b/scripts/mysqld_safe.sh @@ -24,7 +24,6 @@ unsafe_my_cnf=0 wsrep_on=0 dry_run=0 defaults_group_suffix= -ignore_unknown=1 # Initial logging status: error log is not open, and not using syslog logging=init @@ -384,22 +383,11 @@ parse_arguments() { --help) usage ;; - --ignore-unknown) ignore_unknown=1 ;; - --no-ignore-unknown|--not-ignore-unknown) ignore_unknown=0 ;; - *) - if test $ignore_unknown -eq 0 - then - case "$unrecognized_handling" in - collect) append_arg_to_args "$arg" ;; - complain) log_error "unknown option '$arg'" - esac - else - case "$arg" in - "--loose-"*) append_arg_to_args "$arg" ;; - *) append_arg_to_args "--loose-$arg" - esac - fi + case "$unrecognized_handling" in + collect) append_arg_to_args "$arg" ;; + complain) log_error "unknown option '$arg'" ;; + esac esac done } From 688fb6301c190a16987c91f5e14bdcc85d9b0ffa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Fri, 21 Aug 2020 10:37:52 +0300 Subject: [PATCH 61/70] MDEV-23526 InnoDB leaks memory for some static objects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A leak of the contents of fil_system.ssd that was introduced in commit 10dd290b4b8b8b235c8cf42e100f0a4415629e79 (MDEV-17380) was caught by implementing SAFEMALLOC instrumentation of operator new. I did not try to find out how to make AddressSanitizer or Valgrind detect it. fil_system_t::close(): Clear fil_system.ssd. The leak was identified and a fix suggested by Michael Widenius and Vicențiu Ciorbaru. --- storage/innobase/fil/fil0fil.cc | 34 +++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc index d47e9f3f5bf..5f263611cc1 100644 --- a/storage/innobase/fil/fil0fil.cc +++ b/storage/innobase/fil/fil0fil.cc @@ -1610,22 +1610,28 @@ void fil_system_t::create(ulint hash_size) void fil_system_t::close() { - ut_ad(this == &fil_system); - ut_a(!UT_LIST_GET_LEN(LRU)); - ut_a(unflushed_spaces.empty()); - ut_a(!UT_LIST_GET_LEN(space_list)); - ut_ad(!sys_space); - ut_ad(!temp_space); + ut_ad(this == &fil_system); + ut_a(!UT_LIST_GET_LEN(LRU)); + ut_a(unflushed_spaces.empty()); + ut_a(!UT_LIST_GET_LEN(space_list)); + ut_ad(!sys_space); + ut_ad(!temp_space); - if (is_initialised()) { - m_initialised = false; - hash_table_free(spaces); - spaces = NULL; - mutex_free(&mutex); - fil_space_crypt_cleanup(); - } + if (is_initialised()) + { + m_initialised= false; + hash_table_free(spaces); + spaces = nullptr; + mutex_free(&mutex); + fil_space_crypt_cleanup(); + } - ut_ad(!spaces); + ut_ad(!spaces); + +#ifdef UNIV_LINUX + ssd.clear(); + ssd.shrink_to_fit(); +#endif /* UNIV_LINUX */ } /*******************************************************************//** From 0775717479a2b371c56e8811dd7bf24f6d94f7b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Fri, 21 Aug 2020 11:53:30 +0300 Subject: [PATCH 62/70] MDEV-23466: Fix the result for different GTID format in 10.5 --- mysql-test/suite/wsrep/r/MDEV-23466.result | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/suite/wsrep/r/MDEV-23466.result b/mysql-test/suite/wsrep/r/MDEV-23466.result index 6d167c9c95e..a019704d7d3 100644 --- a/mysql-test/suite/wsrep/r/MDEV-23466.result +++ b/mysql-test/suite/wsrep/r/MDEV-23466.result @@ -1,3 +1,3 @@ SELECT WSREP_LAST_SEEN_GTID(); WSREP_LAST_SEEN_GTID() -00000000-0000-0000-0000-000000000000:-1 +0-0-0 From d98ccbe1e1a8190d295fe91942ba739a12d9e245 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Fri, 21 Aug 2020 11:54:16 +0300 Subject: [PATCH 63/70] MDEV-23526 InnoDB leaks memory for some static objects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Leaks of some members of statically allocated objects are not being reported by AddressSanitizer or Valgrind, but they can be reported by implementing SAFEMALLOC instrumentation. These leaks were identified and original fixes provided by Michael Widenius and Vicențiu Ciorbaru. --- storage/innobase/include/log0log.h | 5 ++ storage/innobase/include/log0recv.h | 2 +- storage/innobase/log/log0log.cc | 11 +++-- storage/innobase/log/log0recv.cc | 76 ++++++++++++++--------------- storage/innobase/srv/srv0srv.cc | 12 ++--- 5 files changed, 55 insertions(+), 51 deletions(-) diff --git a/storage/innobase/include/log0log.h b/storage/innobase/include/log0log.h index 8a4953d7533..9eae5369d48 100644 --- a/storage/innobase/include/log0log.h +++ b/storage/innobase/include/log0log.h @@ -480,6 +480,11 @@ public: bool writes_are_durable() const noexcept; dberr_t write(os_offset_t offset, span buf) noexcept; dberr_t flush() noexcept; + void free() + { + m_path.clear(); + m_path.shrink_to_fit(); + } private: std::unique_ptr m_file; diff --git a/storage/innobase/include/log0recv.h b/storage/innobase/include/log0recv.h index fe36b3a5c83..b8d7e40246c 100644 --- a/storage/innobase/include/log0recv.h +++ b/storage/innobase/include/log0recv.h @@ -302,7 +302,7 @@ public: void read(os_offset_t offset, span buf); inline size_t files_size(); - void close_files() { files.clear(); } + void close_files() { files.clear(); files.shrink_to_fit(); } private: /** Attempt to initialize a page based on redo log records. diff --git a/storage/innobase/log/log0log.cc b/storage/innobase/log/log0log.cc index 62de68790ed..3e2a64a3902 100644 --- a/storage/innobase/log/log0log.cc +++ b/storage/innobase/log/log0log.cc @@ -823,11 +823,12 @@ void log_t::file::flush() void log_t::file::close_file() { - if (!fd.is_opened()) - return; - - if (const dberr_t err= fd.close()) - ib::fatal() << "close(" << fd.get_path() << ") returned " << err; + if (fd.is_opened()) + { + if (const dberr_t err= fd.close()) + ib::fatal() << "close(" << fd.get_path() << ") returned " << err; + } + fd.free(); // Free path } /** Initialize the redo log. */ diff --git a/storage/innobase/log/log0recv.cc b/storage/innobase/log/log0recv.cc index 791e13e014e..46830db1323 100644 --- a/storage/innobase/log/log0recv.cc +++ b/storage/innobase/log/log0recv.cc @@ -907,37 +907,34 @@ fil_name_process(char* name, ulint len, ulint space_id, bool deleted) /** Clean up after recv_sys_t::create() */ void recv_sys_t::close() { - ut_ad(this == &recv_sys); - ut_ad(!recv_writer_thread_active); + ut_ad(this == &recv_sys); + ut_ad(!recv_writer_thread_active); - if (is_initialised()) { - dblwr.pages.clear(); - ut_d(mutex_enter(&mutex)); - clear(); - ut_d(mutex_exit(&mutex)); + if (is_initialised()) + { + dblwr.pages.clear(); + ut_d(mutex_enter(&mutex)); + clear(); + ut_d(mutex_exit(&mutex)); - if (flush_start) { - os_event_destroy(flush_start); - } + os_event_destroy(flush_start); + os_event_destroy(flush_end); - if (flush_end) { - os_event_destroy(flush_end); - } + if (buf) + { + ut_free_dodump(buf, RECV_PARSING_BUF_SIZE); + buf= nullptr; + } - if (buf) { - ut_free_dodump(buf, RECV_PARSING_BUF_SIZE); - buf = NULL; - } + last_stored_lsn= 0; + mutex_free(&writer_mutex); + mutex_free(&mutex); + } - last_stored_lsn = 0; - mutex_free(&writer_mutex); - mutex_free(&mutex); - } + recv_spaces.clear(); + mlog_init.clear(); - recv_spaces.clear(); - mlog_init.clear(); - - files.clear(); + close_files(); } /******************************************************************//** @@ -1060,24 +1057,25 @@ inline void recv_sys_t::clear() /** Free most recovery data structures. */ void recv_sys_t::debug_free() { - ut_ad(this == &recv_sys); - ut_ad(is_initialised()); - mutex_enter(&mutex); + ut_ad(this == &recv_sys); + ut_ad(is_initialised()); + mutex_enter(&mutex); - pages.clear(); - ut_free_dodump(buf, RECV_PARSING_BUF_SIZE); + pages.clear(); + ut_free_dodump(buf, RECV_PARSING_BUF_SIZE); - buf = NULL; + buf= nullptr; - /* wake page cleaner up to progress */ - if (!srv_read_only_mode) { - ut_ad(!recv_recovery_is_on()); - ut_ad(!recv_writer_thread_active); - os_event_reset(buf_flush_event); - os_event_set(flush_start); - } + /* wake page cleaner up to progress */ + if (!srv_read_only_mode) + { + ut_ad(!recv_recovery_is_on()); + ut_ad(!recv_writer_thread_active); + os_event_reset(buf_flush_event); + os_event_set(flush_start); + } - mutex_exit(&mutex); + mutex_exit(&mutex); } inline void *recv_sys_t::alloc(size_t len) diff --git a/storage/innobase/srv/srv0srv.cc b/storage/innobase/srv/srv0srv.cc index aa8a5ea2d14..ceb9245f659 100644 --- a/storage/innobase/srv/srv0srv.cc +++ b/storage/innobase/srv/srv0srv.cc @@ -73,7 +73,7 @@ Created 10/8/1995 Heikki Tuuri #include "fil0crypt.h" #include "fil0pagecompress.h" #include "trx0types.h" - +#include #include /* The following is the maximum allowed duration of a lock wait. */ @@ -2110,7 +2110,7 @@ static uint32_t srv_do_purge(ulint* n_total_purged) } -static std::queue purge_thds; +static std::list purge_thds; static std::mutex purge_thd_mutex; extern void* thd_attach_thd(THD*); extern void thd_detach_thd(void *); @@ -2120,11 +2120,11 @@ THD* acquire_thd(void **ctx) std::unique_lock lk(purge_thd_mutex); if (purge_thds.empty()) { THD* thd = current_thd; - purge_thds.push(innobase_create_background_thd("InnoDB purge worker")); + purge_thds.push_back(innobase_create_background_thd("InnoDB purge worker")); set_current_thd(thd); } THD* thd = purge_thds.front(); - purge_thds.pop(); + purge_thds.pop_front(); lk.unlock(); /* Set current thd, and thd->mysys_var as well, @@ -2137,7 +2137,7 @@ void release_thd(THD *thd, void *ctx) { thd_detach_thd(ctx); std::unique_lock lk(purge_thd_mutex); - purge_thds.push(thd); + purge_thds.push_back(thd); lk.unlock(); set_current_thd(0); } @@ -2236,7 +2236,7 @@ static void srv_shutdown_purge_tasks() while (!purge_thds.empty()) { innobase_destroy_background_thd(purge_thds.front()); - purge_thds.pop(); + purge_thds.pop_front(); } } From a19cb3884f443e68eecfa7b96ea109768a0a6188 Mon Sep 17 00:00:00 2001 From: Andrei Elkin Date: Thu, 20 Aug 2020 15:32:35 +0300 Subject: [PATCH 64/70] MDEV-23511 shutdown_server 10 times out, causing server kill at shutdown Shutdown of mtr tests may be too impatient, esp on CI environment where 10 seconds of `arg` of `shutdown_server arg` may not be enough for the clean shutdown to complete. This is fixed to remove explicit non-zero timeout argument to `shutdown_server` from all mtr tests. mysqltest computes 60 seconds default value for the timeout for the argless `shutdown_server` command. This policy is additionally ensured with a compile time assert. --- client/mysqltest.cc | 6 ++++-- mysql-test/include/restart_mysqld.inc | 2 +- mysql-test/include/rpl_stop_server.inc | 4 ++-- mysql-test/include/search_pattern_in_file.inc | 2 +- mysql-test/include/shutdown_mysqld.inc | 2 +- .../suite/binlog/t/binlog_max_extension.test | 4 ++-- .../suite/binlog_encryption/restart_server.inc | 2 +- mysql-test/suite/encryption/t/innochecksum.test | 2 +- .../suite/innodb/t/innodb-corrupted-table.test | 2 +- mysql-test/suite/innodb/t/innodb_bug60196.test | 4 ++-- mysql-test/suite/multi_source/info_logs.test | 2 +- ...percona_slow_extended-slave_innodb_stats.test | 2 +- mysql-test/suite/roles/acl_load_mutex-5170.test | 2 +- mysql-test/suite/rpl/t/rpl_gtid_crash.test | 2 +- mysql-test/suite/rpl/t/rpl_gtid_stop_start.test | 16 ++++++++-------- mysql-test/suite/rpl/t/rpl_mdev382.test | 2 +- .../suite/rpl/t/rpl_parallel_partition.test | 2 +- .../suite/storage_engine/alter_tablespace.test | 2 +- .../suite/storage_engine/trx/xa_recovery.test | 2 +- mysql-test/t/empty_server_name-8224.test | 2 +- mysql-test/t/host_cache_size_functionality.test | 4 ++-- mysql-test/t/init_file_set_password-7656.test | 2 +- mysql-test/t/log_errchk.test | 2 +- .../include/restart_mysqld_with_option.inc | 2 +- .../rocksdb/t/check_ignore_unknown_options.test | 2 +- .../rocksdb/t/insert_optimized_config.test | 4 ++-- .../rocksdb/mysql-test/rocksdb/t/mysqldump2.test | 2 +- .../mysql-test/rocksdb/t/optimize_table.test | 2 +- .../mysql-test/rocksdb/t/persistent_cache.test | 4 ++-- .../rocksdb/mysql-test/rocksdb/t/shutdown.test | 2 +- .../mysql-test/rocksdb/t/validate_datadic.test | 8 ++++---- ...rocksdb_rate_limiter_bytes_per_sec_basic.test | 4 ++-- 32 files changed, 52 insertions(+), 50 deletions(-) diff --git a/client/mysqltest.cc b/client/mysqltest.cc index 7d2b4b3b0a7..2a9560e8903 100644 --- a/client/mysqltest.cc +++ b/client/mysqltest.cc @@ -185,7 +185,7 @@ static uint opt_tail_lines= 0; static uint opt_connect_timeout= 0; static uint opt_wait_for_pos_timeout= 0; - +static const uint default_wait_for_pos_timeout= 300; static char delimiter[MAX_DELIMITER_LENGTH]= ";"; static uint delimiter_length= 1; @@ -5074,6 +5074,8 @@ void do_shutdown_server(struct st_command *command) }; DBUG_ENTER("do_shutdown_server"); + /* the wait-for-pos' default based value of 'timeout' must fit to MDEV-23511 */ + compile_time_assert(default_wait_for_pos_timeout / 5 >= 60); check_command_args(command, command->first_argument, shutdown_args, sizeof(shutdown_args)/sizeof(struct command_arg), ' '); @@ -7058,7 +7060,7 @@ static struct my_option my_long_options[] = {"wait_for_pos_timeout", 0, "Number of seconds to wait for master_pos_wait", &opt_wait_for_pos_timeout, &opt_wait_for_pos_timeout, 0, GET_UINT, - REQUIRED_ARG, 300, 0, 3600 * 12, 0, 0, 0}, + REQUIRED_ARG, default_wait_for_pos_timeout, 0, 3600 * 12, 0, 0, 0}, {"plugin_dir", 0, "Directory for client-side plugins.", &opt_plugin_dir, &opt_plugin_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, diff --git a/mysql-test/include/restart_mysqld.inc b/mysql-test/include/restart_mysqld.inc index 3d3e55db4ac..689f3b8cc1f 100644 --- a/mysql-test/include/restart_mysqld.inc +++ b/mysql-test/include/restart_mysqld.inc @@ -1,6 +1,6 @@ # ==== Usage ==== # -# [--let $shutdown_timeout= 30] +# [--let $shutdown_timeout= 60] # [--let $allow_rpl_inited= 1] # --source include/restart_mysqld.inc diff --git a/mysql-test/include/rpl_stop_server.inc b/mysql-test/include/rpl_stop_server.inc index 978cfec1885..049c3d5bbd2 100644 --- a/mysql-test/include/rpl_stop_server.inc +++ b/mysql-test/include/rpl_stop_server.inc @@ -47,8 +47,8 @@ if ($rpl_debug) --exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.$rpl_server_number.expect # Send shutdown to the connected server and give -# it 60 seconds to die before zapping it -shutdown_server 60; +# it 60 seconds (of mysqltest's default) to die before zapping it +shutdown_server; --source include/wait_until_disconnected.inc diff --git a/mysql-test/include/search_pattern_in_file.inc b/mysql-test/include/search_pattern_in_file.inc index 6bead628fb0..5e66bbb7db0 100644 --- a/mysql-test/include/search_pattern_in_file.inc +++ b/mysql-test/include/search_pattern_in_file.inc @@ -36,7 +36,7 @@ # # Stop the server # let $restart_file= $MYSQLTEST_VARDIR/tmp/mysqld.1.expect; # --exec echo "wait" > $restart_file -# --shutdown_server 10 +# --shutdown_server # --source include/wait_until_disconnected.inc # # --error 1 diff --git a/mysql-test/include/shutdown_mysqld.inc b/mysql-test/include/shutdown_mysqld.inc index c8ab6d00f0d..74a3028946d 100644 --- a/mysql-test/include/shutdown_mysqld.inc +++ b/mysql-test/include/shutdown_mysqld.inc @@ -1,6 +1,6 @@ # ==== Usage ==== # -# [--let $shutdown_timeout= 30] +# [--let $shutdown_timeout= 60] # [--let $allow_rpl_inited= 1] # --source include/shutdown_mysqld.inc diff --git a/mysql-test/suite/binlog/t/binlog_max_extension.test b/mysql-test/suite/binlog/t/binlog_max_extension.test index 199a31ea05c..81e357448f6 100644 --- a/mysql-test/suite/binlog/t/binlog_max_extension.test +++ b/mysql-test/suite/binlog/t/binlog_max_extension.test @@ -41,7 +41,7 @@ RESET MASTER; # 1. Stop master server -- exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect --- shutdown_server 10 +-- shutdown_server -- source include/wait_until_disconnected.inc # 2. Prepare log and index file @@ -70,7 +70,7 @@ FLUSH LOGS; # 1. Stop the server -- exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect --- shutdown_server 10 +-- shutdown_server -- source include/wait_until_disconnected.inc # 2. Undo changes to index and log files diff --git a/mysql-test/suite/binlog_encryption/restart_server.inc b/mysql-test/suite/binlog_encryption/restart_server.inc index 6cd0788cf43..8f0fe7d8970 100644 --- a/mysql-test/suite/binlog_encryption/restart_server.inc +++ b/mysql-test/suite/binlog_encryption/restart_server.inc @@ -22,7 +22,7 @@ --enable_reconnect --exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.$rpl_server_number.expect -shutdown_server 10; +shutdown_server; --source include/wait_until_disconnected.inc diff --git a/mysql-test/suite/encryption/t/innochecksum.test b/mysql-test/suite/encryption/t/innochecksum.test index 47da8525130..5423a70f5d9 100644 --- a/mysql-test/suite/encryption/t/innochecksum.test +++ b/mysql-test/suite/encryption/t/innochecksum.test @@ -63,7 +63,7 @@ let MYSQLD_DATADIR=`select @@datadir`; --echo # We give 30 seconds to do a clean shutdown because we do not want --echo # to redo apply the pages of t1.ibd at the time of recovery. --echo # We want SQL to initiate the first access to t1.ibd. -shutdown_server 30; +shutdown_server; --echo # Wait until disconnected. --source include/wait_until_disconnected.inc diff --git a/mysql-test/suite/innodb/t/innodb-corrupted-table.test b/mysql-test/suite/innodb/t/innodb-corrupted-table.test index a7f4ad4afd4..a81235a9dd4 100644 --- a/mysql-test/suite/innodb/t/innodb-corrupted-table.test +++ b/mysql-test/suite/innodb/t/innodb-corrupted-table.test @@ -24,7 +24,7 @@ alter table t1 add primary key (pk); --echo # Stop the server, replace the frm with the old one and restart the server --exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect ---shutdown_server 10 +--shutdown_server --source include/wait_until_disconnected.inc --remove_file $datadir/test/t1.frm diff --git a/mysql-test/suite/innodb/t/innodb_bug60196.test b/mysql-test/suite/innodb/t/innodb_bug60196.test index e479b8d6b82..7f1f5c40585 100644 --- a/mysql-test/suite/innodb/t/innodb_bug60196.test +++ b/mysql-test/suite/innodb/t/innodb_bug60196.test @@ -50,7 +50,7 @@ SELECT * FROM bug_60196; -- exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect # Send a shutdown request to the server --- shutdown_server 10 +-- shutdown_server # Call script that will poll the server waiting for it to disapear -- source include/wait_until_disconnected.inc @@ -124,7 +124,7 @@ SELECT * FROM Bug_60309; -- exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect # Send a shutdown request to the server --- shutdown_server 10 +-- shutdown_server # Call script that will poll the server waiting for it to disapear -- source include/wait_until_disconnected.inc diff --git a/mysql-test/suite/multi_source/info_logs.test b/mysql-test/suite/multi_source/info_logs.test index ef504e06a2f..234e317e5ce 100644 --- a/mysql-test/suite/multi_source/info_logs.test +++ b/mysql-test/suite/multi_source/info_logs.test @@ -150,7 +150,7 @@ show all slaves status; --append_file $MYSQLTEST_VARDIR/tmp/mysqld.3.expect restart EOF ---shutdown_server 60 +--shutdown_server --source include/wait_until_connected_again.inc --source include/wait_for_slave_to_start.inc set default_master_connection = 'MASTER 2.2'; diff --git a/mysql-test/suite/percona/slow_extended.patch/percona_slow_extended-slave_innodb_stats.test b/mysql-test/suite/percona/slow_extended.patch/percona_slow_extended-slave_innodb_stats.test index b0a6c98870c..43af0460118 100644 --- a/mysql-test/suite/percona/slow_extended.patch/percona_slow_extended-slave_innodb_stats.test +++ b/mysql-test/suite/percona/slow_extended.patch/percona_slow_extended-slave_innodb_stats.test @@ -23,7 +23,7 @@ STOP SLAVE; --write_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect wait EOF ---shutdown_server 10 +--shutdown_server --source include/wait_until_disconnected.inc --append_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect restart diff --git a/mysql-test/suite/roles/acl_load_mutex-5170.test b/mysql-test/suite/roles/acl_load_mutex-5170.test index 22b9dffb5fd..76d817be055 100644 --- a/mysql-test/suite/roles/acl_load_mutex-5170.test +++ b/mysql-test/suite/roles/acl_load_mutex-5170.test @@ -10,7 +10,7 @@ flush tables; --append_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect wait EOF ---shutdown_server 60 +--shutdown_server --source include/wait_until_disconnected.inc --enable_reconnect --append_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect diff --git a/mysql-test/suite/rpl/t/rpl_gtid_crash.test b/mysql-test/suite/rpl/t/rpl_gtid_crash.test index b81cbd38cd3..cf749dd8d65 100644 --- a/mysql-test/suite/rpl/t/rpl_gtid_crash.test +++ b/mysql-test/suite/rpl/t/rpl_gtid_crash.test @@ -624,7 +624,7 @@ SELECT * FROM t1 WHERE a >= 30 ORDER BY a; --write_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect wait EOF -shutdown_server 10; +shutdown_server; --source include/wait_until_disconnected.inc --remove_file $datadir/master-bin.state diff --git a/mysql-test/suite/rpl/t/rpl_gtid_stop_start.test b/mysql-test/suite/rpl/t/rpl_gtid_stop_start.test index 09b35011f1f..3d605f3f213 100644 --- a/mysql-test/suite/rpl/t/rpl_gtid_stop_start.test +++ b/mysql-test/suite/rpl/t/rpl_gtid_stop_start.test @@ -29,7 +29,7 @@ CHANGE MASTER TO master_use_gtid=current_pos; wait EOF FLUSH LOGS; ---shutdown_server 30 +--shutdown_server --source include/wait_until_disconnected.inc --connection server_1 @@ -70,7 +70,7 @@ SHOW BINLOG EVENTS IN 'master-bin.000004' LIMIT 1,1; --write_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect wait EOF ---shutdown_server 30 +--shutdown_server --source include/wait_until_disconnected.inc --append_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect @@ -103,7 +103,7 @@ SELECT * FROM t1 ORDER BY a; --write_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect wait EOF ---shutdown_server 30 +--shutdown_server --source include/wait_until_disconnected.inc --append_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect @@ -148,7 +148,7 @@ SELECT * FROM t1 ORDER BY a; --write_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect wait EOF ---shutdown_server 30 +--shutdown_server --source include/wait_until_disconnected.inc --append_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect @@ -191,7 +191,7 @@ SET sql_log_bin= 1; --write_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect wait EOF ---shutdown_server 30 +--shutdown_server --source include/wait_until_disconnected.inc --append_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect @@ -221,7 +221,7 @@ SELECT * FROM t1 ORDER BY a; --write_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect wait EOF ---shutdown_server 30 +--shutdown_server --source include/wait_until_disconnected.inc --append_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect @@ -259,7 +259,7 @@ SELECT domain_id, COUNT(*) FROM mysql.gtid_slave_pos GROUP BY domain_id; --write_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect wait EOF ---shutdown_server 30 +--shutdown_server --source include/wait_until_disconnected.inc --append_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect @@ -291,7 +291,7 @@ SET sql_log_bin=1; --write_file $MYSQLTEST_VARDIR/tmp/mysqld.2.expect wait EOF ---shutdown_server 30 +--shutdown_server --source include/wait_until_disconnected.inc # Let the slave mysqld server start again. diff --git a/mysql-test/suite/rpl/t/rpl_mdev382.test b/mysql-test/suite/rpl/t/rpl_mdev382.test index cb67052b47d..606508ccde1 100644 --- a/mysql-test/suite/rpl/t/rpl_mdev382.test +++ b/mysql-test/suite/rpl/t/rpl_mdev382.test @@ -212,7 +212,7 @@ SELECT * FROM `db1``; select 'oops!'`.`t``1` ORDER BY 1; wait-rpl_mdev382.test EOF ---shutdown_server 30 +--shutdown_server --append_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect restart-rpl_mdev382.test diff --git a/mysql-test/suite/rpl/t/rpl_parallel_partition.test b/mysql-test/suite/rpl/t/rpl_parallel_partition.test index 37dce9fef80..ea6c5dca6be 100644 --- a/mysql-test/suite/rpl/t/rpl_parallel_partition.test +++ b/mysql-test/suite/rpl/t/rpl_parallel_partition.test @@ -42,7 +42,7 @@ ALTER TABLE `E` REMOVE PARTITIONING; --write_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect wait EOF ---shutdown_server 30 +--shutdown_server --source include/wait_until_disconnected.inc --connection default --source include/wait_until_disconnected.inc diff --git a/mysql-test/suite/storage_engine/alter_tablespace.test b/mysql-test/suite/storage_engine/alter_tablespace.test index 3c4910069a0..1899da28320 100644 --- a/mysql-test/suite/storage_engine/alter_tablespace.test +++ b/mysql-test/suite/storage_engine/alter_tablespace.test @@ -46,7 +46,7 @@ wait EOF --enable_reconnect - --shutdown_server 60 + --shutdown_server --source include/wait_until_disconnected.inc diff --git a/mysql-test/suite/storage_engine/trx/xa_recovery.test b/mysql-test/suite/storage_engine/trx/xa_recovery.test index e17bb9d2ea4..f53640578cd 100644 --- a/mysql-test/suite/storage_engine/trx/xa_recovery.test +++ b/mysql-test/suite/storage_engine/trx/xa_recovery.test @@ -12,7 +12,7 @@ --append_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect restart EOF ---shutdown_server 60 +--shutdown_server --source include/wait_until_connected_again.inc diff --git a/mysql-test/t/empty_server_name-8224.test b/mysql-test/t/empty_server_name-8224.test index b15e9d82eb8..5c5140be2e0 100644 --- a/mysql-test/t/empty_server_name-8224.test +++ b/mysql-test/t/empty_server_name-8224.test @@ -4,7 +4,7 @@ --source include/not_embedded.inc create server '' foreign data wrapper w2 options (host '127.0.0.1'); --exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect ---shutdown_server 10 +--shutdown_server --source include/wait_until_disconnected.inc --exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect diff --git a/mysql-test/t/host_cache_size_functionality.test b/mysql-test/t/host_cache_size_functionality.test index db4f64fd493..9ec26010ab6 100644 --- a/mysql-test/t/host_cache_size_functionality.test +++ b/mysql-test/t/host_cache_size_functionality.test @@ -44,7 +44,7 @@ select @@global.Host_Cache_Size > 0; let $restart_file= $MYSQLTEST_VARDIR/tmp/mysqld.1.expect; --exec echo "wait" > $restart_file ---shutdown_server 10 +--shutdown_server --source include/wait_until_disconnected.inc -- exec echo "restart:--host_cache_size=1 " > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect -- enable_reconnect @@ -143,7 +143,7 @@ SELECT Host_Cache_Size = @@SESSION.Host_Cache_Size; #let $restart_file= $MYSQLTEST_VARDIR/tmp/mysqld.1.expect; #--exec echo "wait" > $restart_file -#--shutdown_server 10 +#--shutdown_server #--source include/wait_until_disconnected.inc #-- exec echo "restart:--bind-address=$bind_ip " > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect #-- enable_reconnect diff --git a/mysql-test/t/init_file_set_password-7656.test b/mysql-test/t/init_file_set_password-7656.test index ecee3924355..b3c785a28d9 100644 --- a/mysql-test/t/init_file_set_password-7656.test +++ b/mysql-test/t/init_file_set_password-7656.test @@ -15,7 +15,7 @@ EOF --exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect ---shutdown_server 10 +--shutdown_server --source include/wait_until_disconnected.inc --exec echo "restart:--init-file=$MYSQLTEST_VARDIR/init.file " > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect diff --git a/mysql-test/t/log_errchk.test b/mysql-test/t/log_errchk.test index 2808458e9f1..1afc0e29f3a 100644 --- a/mysql-test/t/log_errchk.test +++ b/mysql-test/t/log_errchk.test @@ -31,7 +31,7 @@ --echo # and slow query log file. # Restart server with fifo file as general log file. --exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect ---shutdown_server 60 +--shutdown_server --source include/wait_until_disconnected.inc --enable_reconnect # Write file to make mysql-test-run.pl start up the server again diff --git a/storage/rocksdb/mysql-test/rocksdb/include/restart_mysqld_with_option.inc b/storage/rocksdb/mysql-test/rocksdb/include/restart_mysqld_with_option.inc index 4250b368b1a..81cd2200ae0 100644 --- a/storage/rocksdb/mysql-test/rocksdb/include/restart_mysqld_with_option.inc +++ b/storage/rocksdb/mysql-test/rocksdb/include/restart_mysqld_with_option.inc @@ -15,7 +15,7 @@ if ($rpl_inited) # Send shutdown to the connected server and give # it 10 seconds to die before zapping it -shutdown_server 10; +shutdown_server; # Write file to make mysql-test-run.pl start up the server again --exec echo "restart:$_mysqld_option" > $_expect_file_name diff --git a/storage/rocksdb/mysql-test/rocksdb/t/check_ignore_unknown_options.test b/storage/rocksdb/mysql-test/rocksdb/t/check_ignore_unknown_options.test index c8c12626139..15a7d319c04 100644 --- a/storage/rocksdb/mysql-test/rocksdb/t/check_ignore_unknown_options.test +++ b/storage/rocksdb/mysql-test/rocksdb/t/check_ignore_unknown_options.test @@ -41,7 +41,7 @@ perl; EOF --exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect ---shutdown_server 10 +--shutdown_server --error 1 --exec $MYSQLD_CMD --plugin_load=$HA_ROCKSDB_SO --rocksdb_ignore_unknown_options=0 --log-error=$error_log diff --git a/storage/rocksdb/mysql-test/rocksdb/t/insert_optimized_config.test b/storage/rocksdb/mysql-test/rocksdb/t/insert_optimized_config.test index 46ea7f0eb0a..a24851d9d8c 100644 --- a/storage/rocksdb/mysql-test/rocksdb/t/insert_optimized_config.test +++ b/storage/rocksdb/mysql-test/rocksdb/t/insert_optimized_config.test @@ -8,7 +8,7 @@ DROP TABLE IF EXISTS t1; # reload with load optimized config let $restart_file= $MYSQLTEST_VARDIR/tmp/mysqld.1.expect; --exec echo "wait" > $restart_file ---shutdown_server 10 +--shutdown_server --source include/wait_until_disconnected.inc -- exec echo "restart:--rocksdb_write_disable_wal=1 --rocksdb_flush_log_at_trx_commit=0 --rocksdb_default_cf_options=write_buffer_size=16k;target_file_size_base=16k;level0_file_num_compaction_trigger=4;level0_slowdown_writes_trigger=256;level0_stop_writes_trigger=256;max_write_buffer_number=16;compression_per_level=kNoCompression;memtable=vector:1024 --rocksdb_override_cf_options=__system__={memtable=skip_list:16} --rocksdb_compaction_sequential_deletes=0 --rocksdb_compaction_sequential_deletes_window=0 --rocksdb_allow_concurrent_memtable_write=0" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect -- enable_reconnect @@ -39,7 +39,7 @@ select count(*), sum(id), sum(i1), sum(i2) from t1; # reload without load optimized config let $restart_file= $MYSQLTEST_VARDIR/tmp/mysqld.1.expect; --exec echo "wait" > $restart_file ---shutdown_server 10 +--shutdown_server --source include/wait_until_disconnected.inc -- exec echo "restart:--rocksdb_write_disable_wal=0 --rocksdb_default_cf_options=write_buffer_size=64k;target_file_size_base=64k;max_bytes_for_level_base=1m;compression_per_level=kNoCompression;" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect -- enable_reconnect diff --git a/storage/rocksdb/mysql-test/rocksdb/t/mysqldump2.test b/storage/rocksdb/mysql-test/rocksdb/t/mysqldump2.test index ca9eb5d2ecf..4f4f5ed092b 100644 --- a/storage/rocksdb/mysql-test/rocksdb/t/mysqldump2.test +++ b/storage/rocksdb/mysql-test/rocksdb/t/mysqldump2.test @@ -21,7 +21,7 @@ optimize table t1; #wiping block cache let $restart_file= $MYSQLTEST_VARDIR/tmp/mysqld.1.expect; --exec echo "wait" > $restart_file ---shutdown_server 10 +--shutdown_server --source include/wait_until_disconnected.inc -- exec echo "restart:--rocksdb_default_cf_options=write_buffer_size=64k;target_file_size_base=64k;max_bytes_for_level_base=1m;compression_per_level=kNoCompression;disable_auto_compactions=true;level0_stop_writes_trigger=1000 " > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect -- enable_reconnect diff --git a/storage/rocksdb/mysql-test/rocksdb/t/optimize_table.test b/storage/rocksdb/mysql-test/rocksdb/t/optimize_table.test index 7a8f4fc7085..50df3f9c102 100644 --- a/storage/rocksdb/mysql-test/rocksdb/t/optimize_table.test +++ b/storage/rocksdb/mysql-test/rocksdb/t/optimize_table.test @@ -32,7 +32,7 @@ while ($t <= 6) { # Disable auto compaction so that effects of optimize table are stable let $restart_file= $MYSQLTEST_VARDIR/tmp/mysqld.1.expect; --exec echo "wait" > $restart_file ---shutdown_server 10 +--shutdown_server --source include/wait_until_disconnected.inc -- exec echo "restart:--rocksdb_default_cf_options=write_buffer_size=64k;target_file_size_base=64k;max_bytes_for_level_base=1m;compression_per_level=kNoCompression;disable_auto_compactions=true;level0_stop_writes_trigger=1000 " > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect -- enable_reconnect diff --git a/storage/rocksdb/mysql-test/rocksdb/t/persistent_cache.test b/storage/rocksdb/mysql-test/rocksdb/t/persistent_cache.test index 03d1d0a60bc..49e5e5c1172 100644 --- a/storage/rocksdb/mysql-test/rocksdb/t/persistent_cache.test +++ b/storage/rocksdb/mysql-test/rocksdb/t/persistent_cache.test @@ -10,7 +10,7 @@ DROP TABLE IF EXISTS t1; --exec echo "wait" >$_expect_file_name # restart server with correct parameters -shutdown_server 10; +shutdown_server; --exec echo "restart:--rocksdb_persistent_cache_path=$_cache_file_name --rocksdb_persistent_cache_size_mb=100" >$_expect_file_name --sleep 5 --enable_reconnect @@ -28,7 +28,7 @@ select * from t1 where a = 1; # restart server to re-read cache --exec echo "wait" >$_expect_file_name -shutdown_server 10; +shutdown_server; --exec echo "restart:--rocksdb_persistent_cache_path=$_cache_file_name --rocksdb_persistent_cache_size_mb=100" >$_expect_file_name --sleep 5 --enable_reconnect diff --git a/storage/rocksdb/mysql-test/rocksdb/t/shutdown.test b/storage/rocksdb/mysql-test/rocksdb/t/shutdown.test index ba625deb514..f76bc9f6153 100644 --- a/storage/rocksdb/mysql-test/rocksdb/t/shutdown.test +++ b/storage/rocksdb/mysql-test/rocksdb/t/shutdown.test @@ -23,7 +23,7 @@ while ($i <= $max) { # Restart the server let $restart_file= $MYSQLTEST_VARDIR/tmp/mysqld.1.expect; --exec echo "wait" > $restart_file ---shutdown_server 10 +--shutdown_server --source include/wait_until_disconnected.inc -- exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect -- enable_reconnect diff --git a/storage/rocksdb/mysql-test/rocksdb/t/validate_datadic.test b/storage/rocksdb/mysql-test/rocksdb/t/validate_datadic.test index ec48dc03ec8..e7ab37d2658 100644 --- a/storage/rocksdb/mysql-test/rocksdb/t/validate_datadic.test +++ b/storage/rocksdb/mysql-test/rocksdb/t/validate_datadic.test @@ -25,7 +25,7 @@ CREATE TABLE t2 (pk int primary key) ENGINE=ROCKSDB PARTITION BY KEY(pk) PARTITI # Send shutdown to the connected server and give it 10 seconds to die before # zapping it -shutdown_server 10; +shutdown_server; # Write file to make mysql-test-run.pl start up the server again --exec echo "restart" >$_expect_file_name @@ -42,7 +42,7 @@ shutdown_server 10; # Now shut down again and rename one of the .frm files --exec echo "wait" >$_expect_file_name -shutdown_server 10; +shutdown_server; # Rename the file --move_file $MYSQLTEST_VARDIR/mysqld.1/data/test/t1.frm $MYSQLTEST_VARDIR/mysqld.1/data/test/t1.frm.tmp @@ -70,7 +70,7 @@ shutdown_server 10; # Now shut down again and rename one the .frm file back and make a copy of it --exec echo "wait" >$_expect_file_name -shutdown_server 10; +shutdown_server; --remove_file $LOG # Rename the file --move_file $MYSQLTEST_VARDIR/mysqld.1/data/test/t1.frm.tmp $MYSQLTEST_VARDIR/mysqld.1/data/test/t1.frm @@ -92,7 +92,7 @@ shutdown_server 10; # Shut down an clean up --exec echo "wait" >$_expect_file_name -shutdown_server 10; +shutdown_server; --remove_file $MYSQLTEST_VARDIR/mysqld.1/data/test/t1_dummy.frm --exec echo "restart" >$_expect_file_name --enable_reconnect diff --git a/storage/rocksdb/mysql-test/rocksdb_sys_vars/t/rocksdb_rate_limiter_bytes_per_sec_basic.test b/storage/rocksdb/mysql-test/rocksdb_sys_vars/t/rocksdb_rate_limiter_bytes_per_sec_basic.test index 8277011831a..743f942af9c 100644 --- a/storage/rocksdb/mysql-test/rocksdb_sys_vars/t/rocksdb_rate_limiter_bytes_per_sec_basic.test +++ b/storage/rocksdb/mysql-test/rocksdb_sys_vars/t/rocksdb_rate_limiter_bytes_per_sec_basic.test @@ -13,7 +13,7 @@ SET @@global.rocksdb_rate_limiter_bytes_per_sec = 10000; # Send shutdown to the connected server and give it 10 seconds to die before # zapping it -shutdown_server 10; +shutdown_server; # Attempt to restart the server with the rate limiter on --exec echo "restart:--rocksdb_rate_limiter_bytes_per_sec=10000" >$_expect_file_name @@ -53,7 +53,7 @@ SET @@global.rocksdb_rate_limiter_bytes_per_sec = -1; # Restart the server without the rate limiter --exec echo "wait" >$_expect_file_name -shutdown_server 10; +shutdown_server; --exec echo "restart" >$_expect_file_name --sleep 5 From f3160ee44f8f3ae4e5eeea768e289ec40253f35e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Fri, 21 Aug 2020 18:22:55 +0300 Subject: [PATCH 65/70] MDEV-22782 AddressSanitizer race condition in trx_free() In trx_free() we used to declare the entire trx_t unaccessible and then declare that some data members are accessible. This involves a race condition with other threads that may concurrently access the data members that must remain accessible. One type of error is "AddressSanitizer: unknown-crash", whose exact cause we have not determined. Another type of error (reported in MDEV-23472) is "use-after-poison", where the reported shadow bytes would in fact be 00, indicating that the memory was no longer poisoned. The poison-access-unpoison race condition was confirmed by "rr replay". We eliminate the race condition by invoking MEM_NOACCESS on each individual data member of trx_t before freeing the memory to the pool. The memory would not be unpoisoned until the pool is freed or the memory is being reused for another allocation. trx_t::free(): Replaces trx_free(). trx_t::active_commit_ordered: Changed to bool, so that MEM_NOACCESS can be invoked. Removed some accessor functions. Pool: Remove all MEM_ instrumentation. TrxFactory: Move the MEM_ instrumentation from Pool. TrxFactory::debug(): Removed. Moved to trx_t::free(). Because the memory was already marked unaccessible in trx_t::free(), the Factory::debug() call in Pool::putl() would be unable to access it. trx_allocate_for_background(): Replaces trx_create_low(). trx_t::free(): Perform all consistency checks while avoiding duplication, and declare most data members unaccessible. --- storage/innobase/fts/fts0fts.cc | 4 +- storage/innobase/handler/ha_innodb.cc | 38 +--- storage/innobase/include/trx0trx.h | 15 +- storage/innobase/include/ut0pool.h | 30 ---- storage/innobase/trx/trx0trx.cc | 238 ++++++++++++++------------ 5 files changed, 149 insertions(+), 176 deletions(-) diff --git a/storage/innobase/fts/fts0fts.cc b/storage/innobase/fts/fts0fts.cc index 980c4c9ad5f..683104695e3 100644 --- a/storage/innobase/fts/fts0fts.cc +++ b/storage/innobase/fts/fts0fts.cc @@ -4234,7 +4234,7 @@ fts_sync_commit( << " ins/sec"; } - /* Avoid assertion in trx_free(). */ + /* Avoid assertion in trx_t::free(). */ trx->dict_operation_lock_mode = 0; trx_free_for_background(trx); @@ -4288,7 +4288,7 @@ fts_sync_rollback( fts_sql_rollback(trx); - /* Avoid assertion in trx_free(). */ + /* Avoid assertion in trx_t::free(). */ trx->dict_operation_lock_mode = 0; trx_free_for_background(trx); } diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 4db7f58b513..3ab1e9c7cc2 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -2800,18 +2800,6 @@ trx_is_registered_for_2pc( return(trx->is_registered == 1); } -/*********************************************************************//** -Note that innobase_commit_ordered() was run. */ -static inline -void -trx_set_active_commit_ordered( -/*==========================*/ - trx_t* trx) /* in: transaction */ -{ - ut_a(trx_is_registered_for_2pc(trx)); - trx->active_commit_ordered = 1; -} - /*********************************************************************//** Note that a transaction has been registered with MySQL 2PC coordinator. */ static inline @@ -2821,7 +2809,7 @@ trx_register_for_2pc( trx_t* trx) /* in: transaction */ { trx->is_registered = 1; - ut_ad(trx->active_commit_ordered == 0); + ut_ad(!trx->active_commit_ordered); } /*********************************************************************//** @@ -2832,19 +2820,8 @@ trx_deregister_from_2pc( /*====================*/ trx_t* trx) /* in: transaction */ { - trx->is_registered = 0; - trx->active_commit_ordered = 0; -} - -/*********************************************************************//** -Check whether a transaction has active_commit_ordered set */ -static inline -bool -trx_is_active_commit_ordered( -/*=========================*/ - const trx_t* trx) /* in: transaction */ -{ - return(trx->active_commit_ordered == 1); + trx->is_registered= false; + trx->active_commit_ordered= false; } /*********************************************************************//** @@ -4617,8 +4594,7 @@ innobase_commit_ordered( (!thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))); innobase_commit_ordered_2(trx, thd); - - trx_set_active_commit_ordered(trx); + trx->active_commit_ordered = true; DBUG_VOID_RETURN; } @@ -4671,7 +4647,7 @@ innobase_commit( DBUG_SUICIDE();); /* Run the fast part of commit if we did not already. */ - if (!trx_is_active_commit_ordered(trx)) { + if (!trx->active_commit_ordered) { innobase_commit_ordered_2(trx, thd); } @@ -5185,12 +5161,12 @@ static void innobase_kill_query(handlerton*, THD* thd, enum thd_kill_levels) trx_mutex_enter(trx); /* It is possible that innobase_close_connection() is concurrently being executed on our victim. In that case, trx->mysql_thd would - be reset before invoking trx_free(). Even if the trx object is later + be reset before invoking trx_t::free(). Even if the trx object is later reused for another client connection or a background transaction, its trx->mysql_thd will differ from our thd. If trx never performed any changes, nothing is really protecting - the trx_free() call or the changes of trx_t::state when the + the trx_t::free() call or the changes of trx_t::state when the transaction is being rolled back and trx_commit_low() is being executed. diff --git a/storage/innobase/include/trx0trx.h b/storage/innobase/include/trx0trx.h index 57ecf7717d1..4161d4d8563 100644 --- a/storage/innobase/include/trx0trx.h +++ b/storage/innobase/include/trx0trx.h @@ -73,12 +73,9 @@ Creates a transaction object for MySQL. trx_t* trx_allocate_for_mysql(void); /*========================*/ -/********************************************************************//** -Creates a transaction object for background operations by the master thread. -@return own: transaction object */ -trx_t* -trx_allocate_for_background(void); -/*=============================*/ + +/** @return allocated transaction object for internal operations */ +trx_t *trx_allocate_for_background(); /** Frees and initialize a transaction object instantinated during recovery. @param trx trx object to free and initialize during recovery */ @@ -917,7 +914,8 @@ public: the coordinator using the XA API, and is set to false after commit or rollback. */ - unsigned active_commit_ordered:1;/* 1 if owns prepare mutex */ + /** whether this is holding the prepare mutex */ + bool active_commit_ordered; /*------------------------------*/ bool check_unique_secondary; /*!< normally TRUE, but if the user @@ -1204,6 +1202,9 @@ public: ut_ad(old_n_ref > 0); } + /** Free the memory to trx_pools */ + inline void free(); + private: /** Assign a rollback segment for modifying temporary tables. diff --git a/storage/innobase/include/ut0pool.h b/storage/innobase/include/ut0pool.h index 957157fa815..749c4188edf 100644 --- a/storage/innobase/include/ut0pool.h +++ b/storage/innobase/include/ut0pool.h @@ -87,15 +87,6 @@ struct Pool { for (Element* elem = m_start; elem != m_last; ++elem) { ut_ad(elem->m_pool == this); -#ifdef __SANITIZE_ADDRESS__ - /* Unpoison the memory for AddressSanitizer */ - MEM_UNDEFINED(&elem->m_type, sizeof elem->m_type); -#endif -#ifdef HAVE_valgrind - /* Declare the contents as initialized for Valgrind; - we checked this in mem_free(). */ - MEM_MAKE_DEFINED(&elem->m_type, sizeof elem->m_type); -#endif Factory::destroy(&elem->m_type); } @@ -130,22 +121,6 @@ struct Pool { elem = NULL; } -#if defined HAVE_valgrind || defined __SANITIZE_ADDRESS__ - if (elem) { -# ifdef __SANITIZE_ADDRESS__ - /* Unpoison the memory for AddressSanitizer */ - MEM_UNDEFINED(&elem->m_type, sizeof elem->m_type); -# endif -# ifdef HAVE_valgrind - /* Declare the memory initialized for Valgrind. - The trx_t that are released to the pool are - actually initialized; we checked that by - MEM_CHECK_DEFINED() in mem_free() below. */ -# endif - MEM_MAKE_DEFINED(&elem->m_type, sizeof elem->m_type); - } -#endif - m_lock_strategy.exit(); return elem ? &elem->m_type : NULL; } @@ -158,12 +133,10 @@ struct Pool { byte* p = reinterpret_cast(ptr + 1); elem = reinterpret_cast(p - sizeof(*elem)); - MEM_CHECK_DEFINED(&elem->m_type, sizeof elem->m_type); elem->m_pool->m_lock_strategy.enter(); elem->m_pool->putl(elem); - MEM_NOACCESS(&elem->m_type, sizeof elem->m_type); elem->m_pool->m_lock_strategy.exit(); } @@ -186,9 +159,6 @@ private: void putl(Element* elem) { ut_ad(elem >= m_start && elem < m_last); - - ut_ad(Factory::debug(&elem->m_type)); - m_pqueue.push(elem); } diff --git a/storage/innobase/trx/trx0trx.cc b/storage/innobase/trx/trx0trx.cc index d4cd020b321..13b4efb973b 100644 --- a/storage/innobase/trx/trx0trx.cc +++ b/storage/innobase/trx/trx0trx.cc @@ -105,7 +105,7 @@ trx_init( trx->op_info = ""; - trx->active_commit_ordered = 0; + trx->active_commit_ordered = false; trx->isolation_level = TRX_ISO_REPEATABLE_READ; @@ -202,6 +202,15 @@ struct TrxFactory { @param trx the transaction for which to release resources */ static void destroy(trx_t* trx) { +#ifdef __SANITIZE_ADDRESS__ + /* Unpoison the memory for AddressSanitizer */ + MEM_UNDEFINED(trx, sizeof *trx); +#else + /* Declare the contents as initialized for Valgrind; + we checked this in trx_t::free(). */ + MEM_MAKE_DEFINED(trx, sizeof *trx); +#endif + ut_a(trx->magic_n == TRX_MAGIC_N); ut_ad(!trx->in_rw_trx_list); ut_ad(!trx->in_mysql_trx_list); @@ -229,39 +238,6 @@ struct TrxFactory { trx->lock.table_locks.~lock_list(); } - - /** Enforce any invariants here, this is called before the transaction - is added to the pool. - @return true if all OK */ - static bool debug(const trx_t* trx) - { - ut_a(trx->error_state == DB_SUCCESS); - - ut_a(trx->magic_n == TRX_MAGIC_N); - - ut_ad(!trx->read_only); - - ut_ad(trx->state == TRX_STATE_NOT_STARTED); - - ut_ad(trx->dict_operation == TRX_DICT_OP_NONE); - - ut_ad(trx->mysql_thd == 0); - - ut_ad(!trx->in_rw_trx_list); - ut_ad(!trx->in_mysql_trx_list); - - ut_a(trx->lock.wait_thr == NULL); - ut_a(trx->lock.wait_lock == NULL); - ut_a(trx->dict_operation_lock_mode == 0); - - ut_a(UT_LIST_GET_LEN(trx->lock.trx_locks) == 0); - - ut_ad(trx->autoinc_locks == NULL); - - ut_ad(trx->lock.table_locks.empty()); - - return(true); - } }; /** The lock strategy for TrxPool */ @@ -338,13 +314,23 @@ trx_pool_close() trx_pools = 0; } -/** @return a trx_t instance from trx_pools. */ -static -trx_t* -trx_create_low() +/** @return allocated transaction object for internal operations */ +trx_t *trx_allocate_for_background() { trx_t* trx = trx_pools->get(); +#ifdef __SANITIZE_ADDRESS__ + /* Unpoison the memory for AddressSanitizer. + It may have been poisoned in trx_t::free().*/ + MEM_UNDEFINED(trx, sizeof *trx); +#else + /* Declare the memory initialized for Valgrind. + The trx_t that are released to the pool are + actually initialized; we checked that by + MEM_CHECK_DEFINED() in trx_t::free(). */ + MEM_MAKE_DEFINED(trx, sizeof *trx); +#endif + assert_trx_is_free(trx); mem_heap_t* heap; @@ -360,14 +346,9 @@ trx_create_low() alloc = ib_heap_allocator_create(heap); - /* Remember to free the vector explicitly in trx_free(). */ trx->autoinc_locks = ib_vector_create(alloc, sizeof(void**), 4); - /* Should have been either just initialized or .clear()ed by - trx_free(). */ ut_ad(trx->mod_tables.empty()); - ut_ad(trx->lock.table_locks.empty()); - ut_ad(UT_LIST_GET_LEN(trx->lock.trx_locks) == 0); ut_ad(trx->lock.n_rec_locks == 0); ut_ad(trx->lock.table_cached == 0); ut_ad(trx->lock.rec_cached == 0); @@ -379,71 +360,119 @@ trx_create_low() return(trx); } -/** -Release a trx_t instance back to the pool. -@param trx the instance to release. */ -static -void -trx_free(trx_t*& trx) +/** Free the memory to trx_pools */ +inline void trx_t::free() { - assert_trx_is_free(trx); + assert_trx_is_inactive(this); - trx->mysql_thd = 0; - trx->mysql_log_file_name = 0; + MEM_CHECK_DEFINED(this, sizeof *this); - // FIXME: We need to avoid this heap free/alloc for each commit. - if (trx->autoinc_locks != NULL) { - ut_ad(ib_vector_is_empty(trx->autoinc_locks)); - /* We allocated a dedicated heap for the vector. */ - ib_vector_free(trx->autoinc_locks); - trx->autoinc_locks = NULL; - } + ut_ad(!read_view); + ut_ad(!will_lock); + ut_ad(error_state == DB_SUCCESS); + ut_ad(magic_n == TRX_MAGIC_N); + ut_ad(!read_only); + ut_ad(!in_mysql_trx_list); + ut_ad(!lock.wait_lock); - trx->mod_tables.clear(); + mysql_thd= NULL; + mysql_log_file_name= NULL; - ut_ad(trx->read_view == NULL); + // FIXME: We need to avoid this heap free/alloc for each commit. + if (autoinc_locks) + { + ut_ad(ib_vector_is_empty(autoinc_locks)); + /* We allocated a dedicated heap for the vector. */ + ib_vector_free(autoinc_locks); + autoinc_locks= NULL; + } - /* trx locking state should have been reset before returning trx - to pool */ - ut_ad(trx->will_lock == 0); + mod_tables.clear(); - trx_pools->mem_free(trx); -#ifdef __SANITIZE_ADDRESS__ - /* Unpoison the memory for innodb_monitor_set_option; - it is operating also on the freed transaction objects. */ - MEM_UNDEFINED(&trx->mutex, sizeof trx->mutex); - MEM_UNDEFINED(&trx->undo_mutex, sizeof trx->undo_mutex); - /* For innobase_kill_connection() */ - MEM_UNDEFINED(&trx->state, sizeof trx->state); - MEM_UNDEFINED(&trx->mysql_thd, sizeof trx->mysql_thd); + MEM_NOACCESS(&n_ref, sizeof n_ref); + /* do not poison mutex */ + MEM_NOACCESS(&id, sizeof id); + MEM_NOACCESS(&no, sizeof no); + /* state is accessed by innobase_kill_connection() */ + MEM_NOACCESS(&is_recovered, sizeof is_recovered); +#ifdef WITH_WSREP + MEM_NOACCESS(&wsrep, sizeof wsrep); #endif -#ifdef HAVE_valgrind_or_MSAN - /* Unpoison the memory for innodb_monitor_set_option; - it is operating also on the freed transaction objects. - We checked that these were initialized in - trx_pools->mem_free(trx). */ - MEM_MAKE_DEFINED(&trx->mutex, sizeof trx->mutex); - MEM_MAKE_DEFINED(&trx->undo_mutex, sizeof trx->undo_mutex); - /* For innobase_kill_connection() */ - MEM_MAKE_DEFINED(&trx->state, sizeof trx->state); - MEM_MAKE_DEFINED(&trx->mysql_thd, sizeof trx->mysql_thd); -#endif - - trx = NULL; -} - -/********************************************************************//** -Creates a transaction object for background operations by the master thread. -@return own: transaction object */ -trx_t* -trx_allocate_for_background(void) -/*=============================*/ -{ - trx_t* trx; - - trx = trx_create_low(); - - return(trx); + MEM_NOACCESS(&read_view, sizeof read_view); + MEM_NOACCESS(&trx_list, sizeof trx_list); + MEM_NOACCESS(&no_list, sizeof no_list); + MEM_NOACCESS(&lock, sizeof lock); + MEM_NOACCESS(&op_info, sizeof op_info); + MEM_NOACCESS(&isolation_level, sizeof isolation_level); + MEM_NOACCESS(&check_foreigns, sizeof check_foreigns); + MEM_NOACCESS(&is_registered, sizeof is_registered); + MEM_NOACCESS(&active_commit_ordered, sizeof active_commit_ordered); + MEM_NOACCESS(&check_unique_secondary, sizeof check_unique_secondary); + MEM_NOACCESS(&flush_log_later, sizeof flush_log_later); + MEM_NOACCESS(&must_flush_log_later, sizeof must_flush_log_later); + MEM_NOACCESS(&duplicates, sizeof duplicates); + MEM_NOACCESS(&dict_operation, sizeof dict_operation); + MEM_NOACCESS(&declared_to_be_inside_innodb, sizeof declared_to_be_inside_innodb); + MEM_NOACCESS(&n_tickets_to_enter_innodb, sizeof n_tickets_to_enter_innodb); + MEM_NOACCESS(&dict_operation_lock_mode, sizeof dict_operation_lock_mode); + MEM_NOACCESS(&start_time, sizeof start_time); + MEM_NOACCESS(&start_time_micro, sizeof start_time_micro); + MEM_NOACCESS(&commit_lsn, sizeof commit_lsn); + MEM_NOACCESS(&table_id, sizeof table_id); + /* mysql_thd is accessed by innobase_kill_connection() */ + MEM_NOACCESS(&mysql_log_file_name, sizeof mysql_log_file_name); + MEM_NOACCESS(&mysql_log_offset, sizeof mysql_log_offset); + MEM_NOACCESS(&n_mysql_tables_in_use, sizeof n_mysql_tables_in_use); + MEM_NOACCESS(&mysql_n_tables_locked, sizeof mysql_n_tables_locked); +#ifdef UNIV_DEBUG + MEM_NOACCESS(&in_rw_trx_list, sizeof in_rw_trx_list); +#endif /* UNIV_DEBUG */ + MEM_NOACCESS(&mysql_trx_list, sizeof mysql_trx_list); +#ifdef UNIV_DEBUG + MEM_NOACCESS(&in_mysql_trx_list, sizeof in_mysql_trx_list); +#endif /* UNIV_DEBUG */ + MEM_NOACCESS(&error_state, sizeof error_state); + MEM_NOACCESS(&error_info, sizeof error_info); + MEM_NOACCESS(&error_key_num, sizeof error_key_num); + MEM_NOACCESS(&graph, sizeof graph); + MEM_NOACCESS(&trx_savepoints, sizeof trx_savepoints); + /* do not poison undo_mutex */ + MEM_NOACCESS(&undo_no, sizeof undo_no); + MEM_NOACCESS(&undo_rseg_space, sizeof undo_rseg_space); + MEM_NOACCESS(&last_sql_stat_start, sizeof last_sql_stat_start); + MEM_NOACCESS(&rsegs, sizeof rsegs); + MEM_NOACCESS(&roll_limit, sizeof roll_limit); +#ifdef UNIV_DEBUG + MEM_NOACCESS(&in_rollback, sizeof in_rollback); +#endif /* UNIV_DEBUG */ + MEM_NOACCESS(&pages_undone, sizeof pages_undone); + MEM_NOACCESS(&n_autoinc_rows, sizeof n_autoinc_rows); + MEM_NOACCESS(&autoinc_locks, sizeof autoinc_locks); + MEM_NOACCESS(&read_only, sizeof read_only); + MEM_NOACCESS(&auto_commit, sizeof auto_commit); + MEM_NOACCESS(&will_lock, sizeof will_lock); + MEM_NOACCESS(&fts_trx, sizeof fts_trx); + MEM_NOACCESS(&fts_next_doc_id, sizeof fts_next_doc_id); + MEM_NOACCESS(&flush_tables, sizeof flush_tables); + MEM_NOACCESS(&ddl, sizeof ddl); + MEM_NOACCESS(&internal, sizeof internal); +#ifdef UNIV_DEBUG + MEM_NOACCESS(&start_line, sizeof start_line); + MEM_NOACCESS(&start_file, sizeof start_file); +#endif /* UNIV_DEBUG */ + MEM_NOACCESS(&xid, sizeof xid); + MEM_NOACCESS(&mod_tables, sizeof mod_tables); + MEM_NOACCESS(&detailed_error, sizeof detailed_error); + MEM_NOACCESS(&flush_observer, sizeof flush_observer); + MEM_NOACCESS(&n_rec_lock_waits, sizeof n_rec_lock_waits); + MEM_NOACCESS(&n_table_lock_waits, sizeof n_table_lock_waits); + MEM_NOACCESS(&total_rec_lock_wait_time, sizeof total_rec_lock_wait_time); + MEM_NOACCESS(&total_table_lock_wait_time, sizeof total_table_lock_wait_time); +#ifdef WITH_WSREP + MEM_NOACCESS(&wsrep_event, sizeof wsrep_event); +#endif /* WITH_WSREP */ + MEM_NOACCESS(&magic_n, sizeof magic_n); + trx_pools->mem_free(this); } /********************************************************************//** @@ -517,8 +546,7 @@ trx_free_resurrected(trx_t* trx) trx_validate_state_before_free(trx); trx_init(trx); - - trx_free(trx); + trx->free(); } /** Free a transaction that was allocated by background or user threads. @@ -527,8 +555,7 @@ void trx_free_for_background(trx_t* trx) { trx_validate_state_before_free(trx); - - trx_free(trx); + trx->free(); } /** Transition to committed state, to release implicit locks. */ @@ -617,8 +644,7 @@ trx_free_prepared( trx->state = TRX_STATE_NOT_STARTED; ut_ad(!UT_LIST_GET_LEN(trx->lock.trx_locks)); trx->id = 0; - - trx_free(trx); + trx->free(); } /** Disconnect a transaction from MySQL and optionally mark it as if From 151fc0ed887db7e51ab90a2bf822f7cc3a725f62 Mon Sep 17 00:00:00 2001 From: Yuqi Gu Date: Thu, 13 Aug 2020 06:41:21 +0000 Subject: [PATCH 66/70] MDEV-23495: Refine Arm64 PMULL runtime check in MariaDB Raspberry Pi 4 supports crc32 but doesn't support pmull (MDEV-23030). The PR #1645 offers a solution to fix this issue. But it does not consider the condition that the target platform does support crc32 but not support PMULL. In this condition, it should leverage the Arm64 crc32 instruction (__crc32c) and just only skip parallel computation (pmull/vmull) rather than skip all hardware crc32 instruction of computation. The PR also removes unnecessary CRC32_ZERO branch in 'crc32c_aarch64' for MariaDB, formats the indent and coding style. Change-Id: I76371a6bd767b4985600e8cca10983d71b7e9459 Signed-off-by: Yuqi Gu --- include/my_sys.h | 4 +- mysys/crc32/crc32_arm64.c | 402 ++++++++++++++------------------ storage/innobase/ut/ut0crc32.cc | 6 +- 3 files changed, 180 insertions(+), 232 deletions(-) diff --git a/include/my_sys.h b/include/my_sys.h index d2aaa5192a4..98a3cfd275a 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -911,9 +911,7 @@ extern MYSQL_PLUGIN_IMPORT my_crc32_t my_checksum; #if defined(__GNUC__) && defined(HAVE_ARMV8_CRC) int crc32_aarch64_available(void); -#if defined(HAVE_ARMV8_CRYPTO) -int crc32c_aarch64_available(void); -#endif +const char *crc32c_aarch64_available(void); #endif #ifdef DBUG_ASSERT_EXISTS diff --git a/mysys/crc32/crc32_arm64.c b/mysys/crc32/crc32_arm64.c index aae6f769002..a7eb2a47442 100644 --- a/mysys/crc32/crc32_arm64.c +++ b/mysys/crc32/crc32_arm64.c @@ -8,40 +8,49 @@ #include #ifndef HWCAP_CRC32 -#define HWCAP_CRC32 (1 << 7) +# define HWCAP_CRC32 (1 << 7) #endif +#ifndef HWCAP_PMULL +# define HWCAP_PMULL (1 << 4) +#endif + +static int pmull_supported; + /* ARM made crc32 default from ARMv8.1 but optional in ARMv8A -so the runtime check. */ + * Runtime check API. + */ int crc32_aarch64_available(void) { unsigned long auxv= getauxval(AT_HWCAP); return (auxv & HWCAP_CRC32) != 0; } -#if defined(HAVE_ARMV8_CRYPTO) - -#ifndef HWCAP_PMULL -#define HWCAP_PMULL (1 << 4) -#endif - -/* Check if target ARM machine support crc32 + pmull for computing crc32c */ -int crc32c_aarch64_available(void) +const char *crc32c_aarch64_available(void) { - return !(~getauxval(AT_HWCAP) & (HWCAP_CRC32 | HWCAP_PMULL)); + unsigned long auxv= getauxval(AT_HWCAP); + + if (!(auxv & HWCAP_CRC32)) + return NULL; + + pmull_supported= (auxv & HWCAP_PMULL) != 0; + if (pmull_supported) + return "Using ARMv8 crc32 + pmull instructions"; + else + return "Using ARMv8 crc32 instructions"; } -#endif /* HAVE_ARMV8_CRYPTO */ -#endif /* HAVE_ARMV8_CRC */ + +#endif /* __GNUC__ && HAVE_ARMV8_CRC */ #ifndef HAVE_ARMV8_CRC_CRYPTO_INTRINSICS /* Request crc extension capabilities from the assembler */ asm(".arch_extension crc"); -#ifdef HAVE_ARMV8_CRYPTO +# ifdef HAVE_ARMV8_CRYPTO /* crypto extension */ asm(".arch_extension crypto"); -#endif +# endif #define CRC32CX(crc, value) __asm__("crc32cx %w[c], %w[c], %x[v]":[c]"+r"(crc):[v]"r"(value)) #define CRC32CW(crc, value) __asm__("crc32cw %w[c], %w[c], %w[v]":[c]"+r"(crc):[v]"r"(value)) @@ -49,12 +58,9 @@ asm(".arch_extension crypto"); #define CRC32CB(crc, value) __asm__("crc32cb %w[c], %w[c], %w[v]":[c]"+r"(crc):[v]"r"(value)) #define CRC32C3X8(buffer, ITR) \ - __asm__("crc32cx %w[c1], %w[c1], %x[v]":[c1]"+r"(crc1):[v]"r"(*((const uint64_t *)buffer + 42*1 + (ITR))));\ - __asm__("crc32cx %w[c2], %w[c2], %x[v]":[c2]"+r"(crc2):[v]"r"(*((const uint64_t *)buffer + 42*2 + (ITR))));\ - __asm__("crc32cx %w[c0], %w[c0], %x[v]":[c0]"+r"(crc0):[v]"r"(*((const uint64_t *)buffer + 42*0 + (ITR)))); - -#define CRC32C3X8_ZERO \ - __asm__("crc32cx %w[c0], %w[c0], xzr":[c0]"+r"(crc0)); + __asm__("crc32cx %w[c1], %w[c1], %x[v]":[c1]"+r"(crc1):[v]"r"(*((const uint64_t *)buffer + 42*1 + (ITR))));\ + __asm__("crc32cx %w[c2], %w[c2], %x[v]":[c2]"+r"(crc2):[v]"r"(*((const uint64_t *)buffer + 42*2 + (ITR))));\ + __asm__("crc32cx %w[c0], %w[c0], %x[v]":[c0]"+r"(crc0):[v]"r"(*((const uint64_t *)buffer + 42*0 + (ITR)))); #else /* HAVE_ARMV8_CRC_CRYPTO_INTRINSICS */ @@ -68,250 +74,194 @@ asm(".arch_extension crypto"); #define CRC32CB(crc, value) (crc) = __crc32cb((crc), (value)) #define CRC32C3X8(buffer, ITR) \ - crc1 = __crc32cd(crc1, *((const uint64_t *)buffer + 42*1 + (ITR)));\ - crc2 = __crc32cd(crc2, *((const uint64_t *)buffer + 42*2 + (ITR)));\ - crc0 = __crc32cd(crc0, *((const uint64_t *)buffer + 42*0 + (ITR))); - -#define CRC32C3X8_ZERO \ - crc0 = __crc32cd(crc0, (const uint64_t)0); + crc1 = __crc32cd(crc1, *((const uint64_t *)buffer + 42*1 + (ITR)));\ + crc2 = __crc32cd(crc2, *((const uint64_t *)buffer + 42*2 + (ITR)));\ + crc0 = __crc32cd(crc0, *((const uint64_t *)buffer + 42*0 + (ITR))); #endif /* HAVE_ARMV8_CRC_CRYPTO_INTRINSICS */ #define CRC32C7X3X8(buffer, ITR) do {\ - CRC32C3X8(buffer, ((ITR) * 7 + 0)) \ - CRC32C3X8(buffer, ((ITR) * 7 + 1)) \ - CRC32C3X8(buffer, ((ITR) * 7 + 2)) \ - CRC32C3X8(buffer, ((ITR) * 7 + 3)) \ - CRC32C3X8(buffer, ((ITR) * 7 + 4)) \ - CRC32C3X8(buffer, ((ITR) * 7 + 5)) \ - CRC32C3X8(buffer, ((ITR) * 7 + 6)) \ - } while(0) - -#define CRC32C7X3X8_ZERO do {\ - CRC32C3X8_ZERO \ - CRC32C3X8_ZERO \ - CRC32C3X8_ZERO \ - CRC32C3X8_ZERO \ - CRC32C3X8_ZERO \ - CRC32C3X8_ZERO \ - CRC32C3X8_ZERO \ - } while(0) + CRC32C3X8(buffer, ((ITR) * 7 + 0)) \ + CRC32C3X8(buffer, ((ITR) * 7 + 1)) \ + CRC32C3X8(buffer, ((ITR) * 7 + 2)) \ + CRC32C3X8(buffer, ((ITR) * 7 + 3)) \ + CRC32C3X8(buffer, ((ITR) * 7 + 4)) \ + CRC32C3X8(buffer, ((ITR) * 7 + 5)) \ + CRC32C3X8(buffer, ((ITR) * 7 + 6)) \ +} while(0) #define PREF4X64L1(buffer, PREF_OFFSET, ITR) \ - __asm__("PRFM PLDL1KEEP, [%x[v],%[c]]"::[v]"r"(buffer), [c]"I"((PREF_OFFSET) + ((ITR) + 0)*64));\ - __asm__("PRFM PLDL1KEEP, [%x[v],%[c]]"::[v]"r"(buffer), [c]"I"((PREF_OFFSET) + ((ITR) + 1)*64));\ - __asm__("PRFM PLDL1KEEP, [%x[v],%[c]]"::[v]"r"(buffer), [c]"I"((PREF_OFFSET) + ((ITR) + 2)*64));\ - __asm__("PRFM PLDL1KEEP, [%x[v],%[c]]"::[v]"r"(buffer), [c]"I"((PREF_OFFSET) + ((ITR) + 3)*64)); + __asm__("PRFM PLDL1KEEP, [%x[v],%[c]]"::[v]"r"(buffer), [c]"I"((PREF_OFFSET) + ((ITR) + 0)*64));\ + __asm__("PRFM PLDL1KEEP, [%x[v],%[c]]"::[v]"r"(buffer), [c]"I"((PREF_OFFSET) + ((ITR) + 1)*64));\ + __asm__("PRFM PLDL1KEEP, [%x[v],%[c]]"::[v]"r"(buffer), [c]"I"((PREF_OFFSET) + ((ITR) + 2)*64));\ + __asm__("PRFM PLDL1KEEP, [%x[v],%[c]]"::[v]"r"(buffer), [c]"I"((PREF_OFFSET) + ((ITR) + 3)*64)); #define PREF1KL1(buffer, PREF_OFFSET) \ - PREF4X64L1(buffer,(PREF_OFFSET), 0) \ - PREF4X64L1(buffer,(PREF_OFFSET), 4) \ - PREF4X64L1(buffer,(PREF_OFFSET), 8) \ - PREF4X64L1(buffer,(PREF_OFFSET), 12) + PREF4X64L1(buffer,(PREF_OFFSET), 0) \ + PREF4X64L1(buffer,(PREF_OFFSET), 4) \ + PREF4X64L1(buffer,(PREF_OFFSET), 8) \ + PREF4X64L1(buffer,(PREF_OFFSET), 12) #define PREF4X64L2(buffer, PREF_OFFSET, ITR) \ - __asm__("PRFM PLDL2KEEP, [%x[v],%[c]]"::[v]"r"(buffer), [c]"I"((PREF_OFFSET) + ((ITR) + 0)*64));\ - __asm__("PRFM PLDL2KEEP, [%x[v],%[c]]"::[v]"r"(buffer), [c]"I"((PREF_OFFSET) + ((ITR) + 1)*64));\ - __asm__("PRFM PLDL2KEEP, [%x[v],%[c]]"::[v]"r"(buffer), [c]"I"((PREF_OFFSET) + ((ITR) + 2)*64));\ - __asm__("PRFM PLDL2KEEP, [%x[v],%[c]]"::[v]"r"(buffer), [c]"I"((PREF_OFFSET) + ((ITR) + 3)*64)); + __asm__("PRFM PLDL2KEEP, [%x[v],%[c]]"::[v]"r"(buffer), [c]"I"((PREF_OFFSET) + ((ITR) + 0)*64));\ + __asm__("PRFM PLDL2KEEP, [%x[v],%[c]]"::[v]"r"(buffer), [c]"I"((PREF_OFFSET) + ((ITR) + 1)*64));\ + __asm__("PRFM PLDL2KEEP, [%x[v],%[c]]"::[v]"r"(buffer), [c]"I"((PREF_OFFSET) + ((ITR) + 2)*64));\ + __asm__("PRFM PLDL2KEEP, [%x[v],%[c]]"::[v]"r"(buffer), [c]"I"((PREF_OFFSET) + ((ITR) + 3)*64)); #define PREF1KL2(buffer, PREF_OFFSET) \ - PREF4X64L2(buffer,(PREF_OFFSET), 0) \ - PREF4X64L2(buffer,(PREF_OFFSET), 4) \ - PREF4X64L2(buffer,(PREF_OFFSET), 8) \ - PREF4X64L2(buffer,(PREF_OFFSET), 12) - + PREF4X64L2(buffer,(PREF_OFFSET), 0) \ + PREF4X64L2(buffer,(PREF_OFFSET), 4) \ + PREF4X64L2(buffer,(PREF_OFFSET), 8) \ + PREF4X64L2(buffer,(PREF_OFFSET), 12) uint32_t crc32c_aarch64(uint32_t crc, const unsigned char *buffer, uint64_t len) { - uint32_t crc0, crc1, crc2; - int64_t length = (int64_t)len; + uint32_t crc0, crc1, crc2; + int64_t length= (int64_t)len; - crc = 0xFFFFFFFFU; + crc= 0xFFFFFFFFU; - if (buffer) { + /* Pmull runtime check here. + * Raspberry Pi 4 supports crc32 but doesn't support pmull (MDEV-23030). + * + * Consider the condition that the target platform does support hardware crc32 + * but not support PMULL. In this condition, it should leverage the aarch64 + * crc32 instruction (__crc32c) and just only skip parallel computation (pmull/vmull) + * rather than skip all hardware crc32 instruction of computation. + */ + if (pmull_supported) + { +/* The following Macro (HAVE_ARMV8_CRYPTO) is used for compiling check */ +#ifdef HAVE_ARMV8_CRYPTO /* Crypto extension Support - * Process 1024 Bytes (per block) + * Parallel computation with 1024 Bytes (per block) + * Intrinsics Support */ -#ifdef HAVE_ARMV8_CRYPTO +# ifdef HAVE_ARMV8_CRC_CRYPTO_INTRINSICS + const poly64_t k1= 0xe417f38a, k2= 0x8f158014; + uint64_t t0, t1; -/* Intrinsics Support */ -#ifdef HAVE_ARMV8_CRC_CRYPTO_INTRINSICS - const poly64_t k1 = 0xe417f38a, k2 = 0x8f158014; - uint64_t t0, t1; + /* Process per block size of 1024 Bytes + * A block size = 8 + 42*3*sizeof(uint64_t) + 8 + */ + while ((length-= 1024) >= 0) + { + /* Prefetch 3*1024 data for avoiding L2 cache miss */ + PREF1KL2(buffer, 1024*3); + /* Do first 8 bytes here for better pipelining */ + crc0= __crc32cd(crc, *(const uint64_t *)buffer); + crc1= 0; + crc2= 0; + buffer+= sizeof(uint64_t); - /* Process per block size of 1024 Bytes - * A block size = 8 + 42*3*sizeof(uint64_t) + 8 - */ - while ((length -= 1024) >= 0) { - /* Prefetch 3*1024 data for avoiding L2 cache miss */ - PREF1KL2(buffer, 1024*3); - /* Do first 8 bytes here for better pipelining */ - crc0 = __crc32cd(crc, *(const uint64_t *)buffer); - crc1 = 0; - crc2 = 0; - buffer += sizeof(uint64_t); + /* Process block inline + * Process crc0 last to avoid dependency with above + */ + CRC32C7X3X8(buffer, 0); + CRC32C7X3X8(buffer, 1); + CRC32C7X3X8(buffer, 2); + CRC32C7X3X8(buffer, 3); + CRC32C7X3X8(buffer, 4); + CRC32C7X3X8(buffer, 5); - /* Process block inline - * Process crc0 last to avoid dependency with above - */ - CRC32C7X3X8(buffer, 0); - CRC32C7X3X8(buffer, 1); - CRC32C7X3X8(buffer, 2); - CRC32C7X3X8(buffer, 3); - CRC32C7X3X8(buffer, 4); - CRC32C7X3X8(buffer, 5); + buffer+= 42*3*sizeof(uint64_t); + /* Prefetch data for following block to avoid L1 cache miss */ + PREF1KL1(buffer, 1024); - buffer += 42*3*sizeof(uint64_t); - /* Prefetch data for following block to avoid L1 cache miss */ - PREF1KL1(buffer, 1024); + /* Last 8 bytes + * Merge crc0 and crc1 into crc2 + * crc1 multiply by K2 + * crc0 multiply by K1 + */ + t1= (uint64_t)vmull_p64(crc1, k2); + t0= (uint64_t)vmull_p64(crc0, k1); + crc= __crc32cd(crc2, *(const uint64_t *)buffer); + crc1= __crc32cd(0, t1); + crc^= crc1; + crc0= __crc32cd(0, t0); + crc^= crc0; - /* Last 8 bytes - * Merge crc0 and crc1 into crc2 - * crc1 multiply by K2 - * crc0 multiply by K1 - */ - t1 = (uint64_t)vmull_p64(crc1, k2); - t0 = (uint64_t)vmull_p64(crc0, k1); - crc = __crc32cd(crc2, *(const uint64_t *)buffer); - crc1 = __crc32cd(0, t1); - crc ^= crc1; - crc0 = __crc32cd(0, t0); - crc ^= crc0; + buffer+= sizeof(uint64_t); + } - buffer += sizeof(uint64_t); - } +# else /* HAVE_ARMV8_CRC_CRYPTO_INTRINSICS */ -#else /* HAVE_ARMV8_CRC_CRYPTO_INTRINSICS */ + /*No intrinsics*/ + __asm__("mov x16, #0xf38a \n\t" + "movk x16, #0xe417, lsl 16 \n\t" + "mov v1.2d[0], x16 \n\t" + "mov x16, #0x8014 \n\t" + "movk x16, #0x8f15, lsl 16 \n\t" + "mov v0.2d[0], x16 \n\t" + :::"x16"); - /*No intrinsics*/ - __asm__("mov x16, #0xf38a \n\t" - "movk x16, #0xe417, lsl 16 \n\t" - "mov v1.2d[0], x16 \n\t" - "mov x16, #0x8014 \n\t" - "movk x16, #0x8f15, lsl 16 \n\t" - "mov v0.2d[0], x16 \n\t" - :::"x16"); + while ((length-= 1024) >= 0) + { + PREF1KL2(buffer, 1024*3); + __asm__("crc32cx %w[c0], %w[c], %x[v]\n\t" + :[c0]"=r"(crc0):[c]"r"(crc), [v]"r"(*(const uint64_t *)buffer):); + crc1= 0; + crc2= 0; + buffer+= sizeof(uint64_t); - while ((length -= 1024) >= 0) { - PREF1KL2(buffer, 1024*3); - __asm__("crc32cx %w[c0], %w[c], %x[v]\n\t" - :[c0]"=r"(crc0):[c]"r"(crc), [v]"r"(*(const uint64_t *)buffer):); - crc1 = 0; - crc2 = 0; - buffer += sizeof(uint64_t); + CRC32C7X3X8(buffer, 0); + CRC32C7X3X8(buffer, 1); + CRC32C7X3X8(buffer, 2); + CRC32C7X3X8(buffer, 3); + CRC32C7X3X8(buffer, 4); + CRC32C7X3X8(buffer, 5); - CRC32C7X3X8(buffer, 0); - CRC32C7X3X8(buffer, 1); - CRC32C7X3X8(buffer, 2); - CRC32C7X3X8(buffer, 3); - CRC32C7X3X8(buffer, 4); - CRC32C7X3X8(buffer, 5); + buffer+= 42*3*sizeof(uint64_t); + PREF1KL1(buffer, 1024); + __asm__("mov v2.2d[0], %x[c1] \n\t" + "pmull v2.1q, v2.1d, v0.1d \n\t" + "mov v3.2d[0], %x[c0] \n\t" + "pmull v3.1q, v3.1d, v1.1d \n\t" + "crc32cx %w[c], %w[c2], %x[v] \n\t" + "mov %x[c1], v2.2d[0] \n\t" + "crc32cx %w[c1], wzr, %x[c1] \n\t" + "eor %w[c], %w[c], %w[c1] \n\t" + "mov %x[c0], v3.2d[0] \n\t" + "crc32cx %w[c0], wzr, %x[c0] \n\t" + "eor %w[c], %w[c], %w[c0] \n\t" + :[c1]"+r"(crc1), [c0]"+r"(crc0), [c2]"+r"(crc2), [c]"+r"(crc) + :[v]"r"(*((const uint64_t *)buffer))); + buffer+= sizeof(uint64_t); + } +# endif /* HAVE_ARMV8_CRC_CRYPTO_INTRINSICS */ - buffer += 42*3*sizeof(uint64_t); - PREF1KL1(buffer, 1024); - __asm__("mov v2.2d[0], %x[c1] \n\t" - "pmull v2.1q, v2.1d, v0.1d \n\t" - "mov v3.2d[0], %x[c0] \n\t" - "pmull v3.1q, v3.1d, v1.1d \n\t" - "crc32cx %w[c], %w[c2], %x[v] \n\t" - "mov %x[c1], v2.2d[0] \n\t" - "crc32cx %w[c1], wzr, %x[c1] \n\t" - "eor %w[c], %w[c], %w[c1] \n\t" - "mov %x[c0], v3.2d[0] \n\t" - "crc32cx %w[c0], wzr, %x[c0] \n\t" - "eor %w[c], %w[c], %w[c0] \n\t" - :[c1]"+r"(crc1), [c0]"+r"(crc0), [c2]"+r"(crc2), [c]"+r"(crc) - :[v]"r"(*((const uint64_t *)buffer))); - buffer += sizeof(uint64_t); - } -#endif /* HAVE_ARMV8_CRC_CRYPTO_INTRINSICS */ - - /* Done if Input data size is aligned with 1024 */ - if(!(length += 1024)) - return (~crc); + /* Done if Input data size is aligned with 1024 */ + if (!(length+= 1024)) + return ~crc; #endif /* HAVE_ARMV8_CRYPTO */ - while ((length -= sizeof(uint64_t)) >= 0) { - CRC32CX(crc, *(uint64_t *)buffer); - buffer += sizeof(uint64_t); - } - /* The following is more efficient than the straight loop */ - if (length & sizeof(uint32_t)) { - CRC32CW(crc, *(uint32_t *)buffer); - buffer += sizeof(uint32_t); - } - if (length & sizeof(uint16_t)) { - CRC32CH(crc, *(uint16_t *)buffer); - buffer += sizeof(uint16_t); - } - if (length & sizeof(uint8_t)) - CRC32CB(crc, *buffer); + } // end if pmull_supported - } else { -#ifdef HAVE_ARMV8_CRYPTO -#ifdef HAVE_ARMV8_CRC_CRYPTO_INTRINSICS - const poly64_t k1 = 0xe417f38a; - uint64_t t0; - while ((length -= 1024) >= 0) { - crc0 = __crc32cd(crc, 0); + while ((length-= sizeof(uint64_t)) >= 0) + { + CRC32CX(crc, *(uint64_t *)buffer); + buffer+= sizeof(uint64_t); + } - CRC32C7X3X8_ZERO; - CRC32C7X3X8_ZERO; - CRC32C7X3X8_ZERO; - CRC32C7X3X8_ZERO; - CRC32C7X3X8_ZERO; - CRC32C7X3X8_ZERO; + /* The following is more efficient than the straight loop */ + if (length & sizeof(uint32_t)) + { + CRC32CW(crc, *(uint32_t *)buffer); + buffer+= sizeof(uint32_t); + } - /* Merge crc0 into crc: crc0 multiply by K1 */ - t0 = (uint64_t)vmull_p64(crc0, k1); - crc = __crc32cd(0, t0); - } -#else /* !HAVE_ARMV8_CRC_CRYPTO_INTRINSICS */ - __asm__("mov x16, #0xf38a \n\t" - "movk x16, #0xe417, lsl 16 \n\t" - "mov v1.2d[0], x16 \n\t" - :::"x16"); + if (length & sizeof(uint16_t)) + { + CRC32CH(crc, *(uint16_t *)buffer); + buffer+= sizeof(uint16_t); + } - while ((length -= 1024) >= 0) { - __asm__("crc32cx %w[c0], %w[c], xzr\n\t" - :[c0]"=r"(crc0):[c]"r"(crc)); + if (length & sizeof(uint8_t)) + CRC32CB(crc, *buffer); - CRC32C7X3X8_ZERO; - CRC32C7X3X8_ZERO; - CRC32C7X3X8_ZERO; - CRC32C7X3X8_ZERO; - CRC32C7X3X8_ZERO; - CRC32C7X3X8_ZERO; - - __asm__("mov v3.2d[0], %x[c0] \n\t" - "pmull v3.1q, v3.1d, v1.1d \n\t" - "mov %x[c0], v3.2d[0] \n\t" - "crc32cx %w[c], wzr, %x[c0] \n\t" - :[c]"=r"(crc) - :[c0]"r"(crc0)); - } -#endif /* HAVE_ARMV8_CRC_CRYPTO_INTRINSICS */ - if(!(length += 1024)) - return (~crc); -#endif /* HAVE_ARMV8_CRYPTO */ - while ((length -= sizeof(uint64_t)) >= 0) - CRC32CX(crc, 0); - - /* The following is more efficient than the straight loop */ - if (length & sizeof(uint32_t)) - CRC32CW(crc, 0); - - if (length & sizeof(uint16_t)) - CRC32CH(crc, 0); - - if (length & sizeof(uint8_t)) - CRC32CB(crc, 0); - } - - return (~crc); + return ~crc; } /* There are multiple approaches to calculate crc. diff --git a/storage/innobase/ut/ut0crc32.cc b/storage/innobase/ut/ut0crc32.cc index 9de0ca81fe3..1ddac168d95 100644 --- a/storage/innobase/ut/ut0crc32.cc +++ b/storage/innobase/ut/ut0crc32.cc @@ -342,11 +342,11 @@ allocations, would not hurt if called twice, but would be pointless. */ void ut_crc32_init() { #ifndef HAVE_CRC32_VPMSUM -# if defined(__GNUC__) && defined(HAVE_ARMV8_CRC) && defined(HAVE_ARMV8_CRYPTO) - if (crc32c_aarch64_available()) +# if defined(__GNUC__) && defined(HAVE_ARMV8_CRC) + if (const char *crc32c_implementation= crc32c_aarch64_available()) { ut_crc32_low= crc32c_aarch64; - ut_crc32_implementation= "Using ARMv8 crc32 + pmull instructions"; + ut_crc32_implementation= crc32c_implementation; return; } # elif defined(TRY_SSE4_2) From ee61c8c0b762840ab5badaa9d6b3a24b1c2ee8c7 Mon Sep 17 00:00:00 2001 From: Ian Gilfillan Date: Tue, 11 Aug 2020 14:30:34 +0200 Subject: [PATCH 67/70] Fix spelling mistake in error message --- mysql-test/suite/maria/maria-connect.result | 2 +- sql/share/errmsg-utf8.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mysql-test/suite/maria/maria-connect.result b/mysql-test/suite/maria/maria-connect.result index 5c8b5524d69..84195780cf8 100644 --- a/mysql-test/suite/maria/maria-connect.result +++ b/mysql-test/suite/maria/maria-connect.result @@ -11,7 +11,7 @@ ERROR 23000: Duplicate entry '2' for key 'PRIMARY' show warnings; Level Code Message Error 1062 Duplicate entry '2' for key 'PRIMARY' -Note 4173 Engine Aria does not support rollback. Changes where committed during rollback call +Note 4173 Engine Aria does not support rollback. Changes were committed during rollback call Warning 1196 Some non-transactional changed tables couldn't be rolled back select * from t1; a diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index 79c27a37e6d..95dcbf157d3 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -7964,4 +7964,4 @@ ER_KEY_CANT_HAVE_WITHOUT_OVERLAPS ER_NOT_ALLOWED_IN_THIS_CONTEXT eng "'%-.128s' is not allowed in this context" ER_DATA_WAS_COMMITED_UNDER_ROLLBACK - eng "Engine %s does not support rollback. Changes where committed during rollback call" + eng "Engine %s does not support rollback. Changes were committed during rollback call" From ae33ebe5b32a82629a40e51c8d6c6611842fbd03 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Fri, 21 Aug 2020 19:41:51 +0400 Subject: [PATCH 68/70] MDEV-23525 Wrong result of MIN(time_expr) and MAX(time_expr) with GROUP BY Problem: When calculatung MIN() and MAX() in a query with GROUP BY, like this: SELECT MIN(time_expr), MAX(time_expr) FROM t1 GROUP BY i; the code in Item_sum_min_max::update_field() erroneosly used string format comparison, therefore '100:20:30' was considered as smaller than '10:20:30'. Fix: 1. Implementing low level "native" related methods in class Time: Time::Time(const Native &native) - convert native to Time Time::to_native(Native *to, uint decimals) - convert Time to native The "native" binary representation for TIME is equal to the binary data format of Field_timef, which is used to store TIME when mysql56_temporal_format is ON (default). 2. Implementing Type_handler_time_common "native" related methods: Type_handler_time_common::cmp_native() Type_handler_time_common::Item_val_native_with_conversion() Type_handler_time_common::Item_val_native_with_conversion_result() Type_handler_time_common::Item_param_val_native() 3. Implementing missing "native representation" related methods in Field_time and Field_timef: Field_time::store_native() Field_time::val_native() Field_timef::store_native() Field_timef::val_native() 4. Implementing missing "native" related methods in all Items that can have the TIME data type: Item_timefunc::val_native() Item_name_const::val_native() Item_time_literal::val_native() Item_cache_time::val_native() Item_handled_func::val_native() 5. Marking Type_handler_time_common as "native ready". So now Item_sum_min_max::update_field() calculates values using min_max_update_native_field(), which uses native binary representation rather than string representation. Before this change, only the TIMESTAMP data type used native representation to calculate MIN() and MAX(). Benchmarks (see more details in MDEV): This change not only fixes the wrong result, but also makes a "SELECT .. MAX.. GROUP BY .." query faster: # TIME(0) CREATE TABLE t1 (id INT, time_col TIME) ENGINE=HEAP; INSERT INTO t1 VALUES (1,'10:10:10'); -- repeat this 1m times SELECT id, MAX(time_col) FROM t1 GROUP BY id; MySQL80: 0.159 sec 10.3: 0.108 sec 10.4: 0.094 sec (fixed) # TIME(6): CREATE TABLE t1 (id INT, time_col TIME(6)) ENGINE=HEAP; INSERT INTO t1 VALUES (1,'10:10:10.999999'); -- repeat this 1m times SELECT id, MAX(time_col) FROM t1 GROUP BY id; My80: 0.154 10.3: 0.135 10.4: 0.093 (fixed) --- mysql-test/main/type_time.result | 122 +++++++++++++++++++++++++++++++ mysql-test/main/type_time.test | 60 +++++++++++++++ sql/field.cc | 34 +++++++++ sql/field.h | 4 + sql/item.cc | 5 ++ sql/item.h | 16 +++- sql/item_func.h | 14 ++++ sql/item_timefunc.h | 4 + sql/sql_type.cc | 100 +++++++++++++++++++++++++ sql/sql_type.h | 9 +++ 10 files changed, 364 insertions(+), 4 deletions(-) diff --git a/mysql-test/main/type_time.result b/mysql-test/main/type_time.result index 7fdeba07ad2..69aa9561ebf 100644 --- a/mysql-test/main/type_time.result +++ b/mysql-test/main/type_time.result @@ -2286,5 +2286,127 @@ SELECT '1972-11-06 16:58:58' < TIME'20:31:05'; '1972-11-06 16:58:58' < TIME'20:31:05' 1 # +# MDEV-23525 Wrong result of MIN(time_expr) and MAX(time_expr) with GROUP BY +# +SET timestamp=UNIX_TIMESTAMP('2020-08-21 18:19:20'); +CREATE PROCEDURE p1() +BEGIN +SELECT MIN(t), MAX(t) FROM t1; +SELECT i, MIN(t), MAX(t) FROM t1 GROUP BY i; +SELECT i, MIN(COALESCE(t)), MAX(COALESCE(t)) FROM t1 GROUP BY i; +SELECT i, MIN(t+INTERVAL 1 SECOND), MAX(t+INTERVAL 1 SECOND) FROM t1 GROUP BY i; +SELECT i, MIN(TIME'10:20:30'+INTERVAL 1 SECOND) FROM t1 GROUP BY i; +SELECT i, MIN(CURRENT_TIME), MAX(CURRENT_TIME) FROM t1 GROUP BY i; +SELECT +i, +MIN((SELECT MAX(CURRENT_TIME) FROM t1)), +MAX((SELECT MAX(CURRENT_TIME) FROM t1)) +FROM t1 GROUP BY i; +SELECT +i, +MIN(NAME_CONST('name',TIME'10:20:30')), +MAX(NAME_CONST('name',TIME'10:20:30')) +FROM t1 GROUP BY i; +EXECUTE IMMEDIATE "SELECT i, MIN(?),MAX(?) FROM t1 GROUP BY i" + USING TIME'10:20:30', TIME'10:20:30'; +END; +$$ +CREATE TABLE t1 (i INT, t TIME); +INSERT INTO t1 VALUES (1,'10:20:30'); +INSERT INTO t1 VALUES (1,'100:20:20'); +CALL p1; +MIN(t) MAX(t) +10:20:30 100:20:20 +i MIN(t) MAX(t) +1 10:20:30 100:20:20 +i MIN(COALESCE(t)) MAX(COALESCE(t)) +1 10:20:30 100:20:20 +i MIN(t+INTERVAL 1 SECOND) MAX(t+INTERVAL 1 SECOND) +1 10:20:31 100:20:21 +i MIN(TIME'10:20:30'+INTERVAL 1 SECOND) +1 10:20:31 +i MIN(CURRENT_TIME) MAX(CURRENT_TIME) +1 18:19:20 18:19:20 +i MIN((SELECT MAX(CURRENT_TIME) FROM t1)) MAX((SELECT MAX(CURRENT_TIME) FROM t1)) +1 18:19:20 18:19:20 +i MIN(NAME_CONST('name',TIME'10:20:30')) MAX(NAME_CONST('name',TIME'10:20:30')) +1 10:20:30 10:20:30 +i MIN(?) MAX(?) +1 10:20:30 10:20:30 +DROP TABLE t1; +CREATE TABLE t1 (i INT, t TIME(3)); +INSERT INTO t1 VALUES (1,'10:20:30.123'); +INSERT INTO t1 VALUES (1,'100:20:20.123'); +CALL p1; +MIN(t) MAX(t) +10:20:30.123 100:20:20.123 +i MIN(t) MAX(t) +1 10:20:30.123 100:20:20.123 +i MIN(COALESCE(t)) MAX(COALESCE(t)) +1 10:20:30.123 100:20:20.123 +i MIN(t+INTERVAL 1 SECOND) MAX(t+INTERVAL 1 SECOND) +1 10:20:31.123 100:20:21.123 +i MIN(TIME'10:20:30'+INTERVAL 1 SECOND) +1 10:20:31 +i MIN(CURRENT_TIME) MAX(CURRENT_TIME) +1 18:19:20 18:19:20 +i MIN((SELECT MAX(CURRENT_TIME) FROM t1)) MAX((SELECT MAX(CURRENT_TIME) FROM t1)) +1 18:19:20 18:19:20 +i MIN(NAME_CONST('name',TIME'10:20:30')) MAX(NAME_CONST('name',TIME'10:20:30')) +1 10:20:30 10:20:30 +i MIN(?) MAX(?) +1 10:20:30 10:20:30 +DROP TABLE t1; +CREATE TABLE t1 (i INT, t TIME(6)); +INSERT INTO t1 VALUES (1,'10:20:30.123456'); +INSERT INTO t1 VALUES (1,'100:20:20.123456'); +CALL p1; +MIN(t) MAX(t) +10:20:30.123456 100:20:20.123456 +i MIN(t) MAX(t) +1 10:20:30.123456 100:20:20.123456 +i MIN(COALESCE(t)) MAX(COALESCE(t)) +1 10:20:30.123456 100:20:20.123456 +i MIN(t+INTERVAL 1 SECOND) MAX(t+INTERVAL 1 SECOND) +1 10:20:31.123456 100:20:21.123456 +i MIN(TIME'10:20:30'+INTERVAL 1 SECOND) +1 10:20:31 +i MIN(CURRENT_TIME) MAX(CURRENT_TIME) +1 18:19:20 18:19:20 +i MIN((SELECT MAX(CURRENT_TIME) FROM t1)) MAX((SELECT MAX(CURRENT_TIME) FROM t1)) +1 18:19:20 18:19:20 +i MIN(NAME_CONST('name',TIME'10:20:30')) MAX(NAME_CONST('name',TIME'10:20:30')) +1 10:20:30 10:20:30 +i MIN(?) MAX(?) +1 10:20:30 10:20:30 +DROP TABLE t1; +SET @@global.mysql56_temporal_format=false; +CREATE TABLE t1 (i INT, t TIME(6)); +INSERT INTO t1 VALUES (1,'10:20:30.123456'); +INSERT INTO t1 VALUES (1,'100:20:20.123456'); +CALL p1; +MIN(t) MAX(t) +10:20:30.123456 100:20:20.123456 +i MIN(t) MAX(t) +1 10:20:30.123456 100:20:20.123456 +i MIN(COALESCE(t)) MAX(COALESCE(t)) +1 10:20:30.123456 100:20:20.123456 +i MIN(t+INTERVAL 1 SECOND) MAX(t+INTERVAL 1 SECOND) +1 10:20:31.123456 100:20:21.123456 +i MIN(TIME'10:20:30'+INTERVAL 1 SECOND) +1 10:20:31 +i MIN(CURRENT_TIME) MAX(CURRENT_TIME) +1 18:19:20 18:19:20 +i MIN((SELECT MAX(CURRENT_TIME) FROM t1)) MAX((SELECT MAX(CURRENT_TIME) FROM t1)) +1 18:19:20 18:19:20 +i MIN(NAME_CONST('name',TIME'10:20:30')) MAX(NAME_CONST('name',TIME'10:20:30')) +1 10:20:30 10:20:30 +i MIN(?) MAX(?) +1 10:20:30 10:20:30 +DROP TABLE t1; +SET @@global.mysql56_temporal_format=default; +DROP PROCEDURE p1; +SET timestamp=DEFAULT; +# # End of 10.4 tests # diff --git a/mysql-test/main/type_time.test b/mysql-test/main/type_time.test index 521953a5078..1d4d157b976 100644 --- a/mysql-test/main/type_time.test +++ b/mysql-test/main/type_time.test @@ -1490,6 +1490,66 @@ DROP TABLE t1; SELECT '1972-11-06 16:58:58' < TIME'20:31:05'; +--echo # +--echo # MDEV-23525 Wrong result of MIN(time_expr) and MAX(time_expr) with GROUP BY +--echo # + +SET timestamp=UNIX_TIMESTAMP('2020-08-21 18:19:20'); + +DELIMITER $$; +CREATE PROCEDURE p1() +BEGIN + SELECT MIN(t), MAX(t) FROM t1; + SELECT i, MIN(t), MAX(t) FROM t1 GROUP BY i; + SELECT i, MIN(COALESCE(t)), MAX(COALESCE(t)) FROM t1 GROUP BY i; + SELECT i, MIN(t+INTERVAL 1 SECOND), MAX(t+INTERVAL 1 SECOND) FROM t1 GROUP BY i; + SELECT i, MIN(TIME'10:20:30'+INTERVAL 1 SECOND) FROM t1 GROUP BY i; + SELECT i, MIN(CURRENT_TIME), MAX(CURRENT_TIME) FROM t1 GROUP BY i; + SELECT + i, + MIN((SELECT MAX(CURRENT_TIME) FROM t1)), + MAX((SELECT MAX(CURRENT_TIME) FROM t1)) + FROM t1 GROUP BY i; + SELECT + i, + MIN(NAME_CONST('name',TIME'10:20:30')), + MAX(NAME_CONST('name',TIME'10:20:30')) + FROM t1 GROUP BY i; + EXECUTE IMMEDIATE "SELECT i, MIN(?),MAX(?) FROM t1 GROUP BY i" + USING TIME'10:20:30', TIME'10:20:30'; +END; +$$ +DELIMITER ;$$ + +CREATE TABLE t1 (i INT, t TIME); +INSERT INTO t1 VALUES (1,'10:20:30'); +INSERT INTO t1 VALUES (1,'100:20:20'); +CALL p1; +DROP TABLE t1; + +CREATE TABLE t1 (i INT, t TIME(3)); +INSERT INTO t1 VALUES (1,'10:20:30.123'); +INSERT INTO t1 VALUES (1,'100:20:20.123'); +CALL p1; +DROP TABLE t1; + +CREATE TABLE t1 (i INT, t TIME(6)); +INSERT INTO t1 VALUES (1,'10:20:30.123456'); +INSERT INTO t1 VALUES (1,'100:20:20.123456'); +CALL p1; +DROP TABLE t1; + +SET @@global.mysql56_temporal_format=false; +CREATE TABLE t1 (i INT, t TIME(6)); +INSERT INTO t1 VALUES (1,'10:20:30.123456'); +INSERT INTO t1 VALUES (1,'100:20:20.123456'); +CALL p1; +DROP TABLE t1; +SET @@global.mysql56_temporal_format=default; + +DROP PROCEDURE p1; +SET timestamp=DEFAULT; + --echo # --echo # End of 10.4 tests --echo # diff --git a/sql/field.cc b/sql/field.cc index 49ee54883e4..65dc7f768a3 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -6011,6 +6011,24 @@ bool Field_time::get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate) } +int Field_time::store_native(const Native &value) +{ + Time t(value); + DBUG_ASSERT(t.is_valid_time()); + store_TIME(t); + return 0; +} + + +bool Field_time::val_native(Native *to) +{ + MYSQL_TIME ltime; + get_date(<ime, date_mode_t(0)); + int warn; + return Time(&warn, <ime, 0).to_native(to, decimals()); +} + + bool Field_time::send_binary(Protocol *protocol) { MYSQL_TIME ltime; @@ -6254,6 +6272,22 @@ bool Field_timef::get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate) return false; } +int Field_timef::store_native(const Native &value) +{ + DBUG_ASSERT(value.length() == my_time_binary_length(dec)); + DBUG_ASSERT(Time(value).is_valid_time()); + memcpy(ptr, value.ptr(), value.length()); + return 0; +} + + +bool Field_timef::val_native(Native *to) +{ + uint32 binlen= my_time_binary_length(dec); + return to->copy((const char*) ptr, binlen); +} + + /**************************************************************************** ** year type ** Save in a byte the year 0, 1901->2155 diff --git a/sql/field.h b/sql/field.h index 58ff9ea2554..0ee4aca5f69 100644 --- a/sql/field.h +++ b/sql/field.h @@ -3213,6 +3213,8 @@ public: decimals() == from->decimals(); } sql_mode_t conversion_depends_on_sql_mode(THD *, Item *) const; + int store_native(const Native &value); + bool val_native(Native *to); int store_time_dec(const MYSQL_TIME *ltime, uint dec); int store(const char *to,size_t length,CHARSET_INFO *charset); int store(double nr); @@ -3334,6 +3336,8 @@ public: } int reset(); bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate); + int store_native(const Native &value); + bool val_native(Native *to); uint size_of() const { return sizeof(*this); } }; diff --git a/sql/item.cc b/sql/item.cc index f8c29c8974c..312effeb6c1 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -2011,6 +2011,11 @@ bool Item_name_const::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydat return rc; } +bool Item_name_const::val_native(THD *thd, Native *to) +{ + return val_native_from_item(thd, value_item, to); +} + bool Item_name_const::is_null() { return value_item->is_null(); diff --git a/sql/item.h b/sql/item.h index 2d5cedbee76..aced2ec5f0d 100644 --- a/sql/item.h +++ b/sql/item.h @@ -1311,16 +1311,13 @@ public: { /* The default implementation for the Items that do not need native format: - - Item_basic_value + - Item_basic_value (default implementation) - Item_copy - Item_exists_subselect - Item_sum_field - Item_sum_or_func (default implementation) - Item_proc - Item_type_holder (as val_xxx() are never called for it); - - TODO: Item_name_const will need val_native() in the future, - when we add this syntax: - TIMESTAMP WITH LOCAL TIMEZONE'2001-01-01 00:00:00' These hybrid Item types override val_native(): - Item_field @@ -1331,6 +1328,8 @@ public: - Item_direct_ref - Item_direct_view_ref - Item_ref_null_helper + - Item_name_const + - Item_time_literal - Item_sum_or_func Note, these hybrid type Item_sum_or_func descendants override the default implementation: @@ -3139,6 +3138,7 @@ public: String *val_str(String *sp); my_decimal *val_decimal(my_decimal *); bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate); + bool val_native(THD *thd, Native *to); bool is_null(); virtual void print(String *str, enum_query_type query_type); @@ -4897,6 +4897,10 @@ public: String *val_str(String *to) { return Time(this).to_string(to, decimals); } my_decimal *val_decimal(my_decimal *to) { return Time(this).to_decimal(to); } bool get_date(THD *thd, MYSQL_TIME *res, date_mode_t fuzzydate); + bool val_native(THD *thd, Native *to) + { + return Time(thd, this).to_native(to, decimals); + } Item *get_copy(THD *thd) { return get_item_copy(thd, this); } }; @@ -6872,6 +6876,10 @@ public: { return has_value() ? Time(this).to_decimal(to) : NULL; } + bool val_native(THD *thd, Native *to) + { + return has_value() ? Time(thd, this).to_native(to, decimals) : true; + } }; diff --git a/sql/item_func.h b/sql/item_func.h index d1292c3e07a..b368e5872fe 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -497,6 +497,12 @@ public: virtual longlong val_int(Item_handled_func *) const= 0; virtual my_decimal *val_decimal(Item_handled_func *, my_decimal *) const= 0; virtual bool get_date(THD *thd, Item_handled_func *, MYSQL_TIME *, date_mode_t fuzzydate) const= 0; + virtual bool val_native(THD *thd, Item_handled_func *, Native *to) const + { + DBUG_ASSERT(0); + to->length(0); + return true; + } virtual const Type_handler *return_type_handler() const= 0; virtual bool fix_length_and_dec(Item_handled_func *) const= 0; }; @@ -600,6 +606,10 @@ public: { return Time(item).to_string(to, item->decimals); } + bool val_native(THD *thd, Item_handled_func *item, Native *to) const + { + return Time(thd, item).to_native(to, item->decimals); + } }; @@ -668,6 +678,10 @@ public: { return m_func_handler->get_date(thd, this, to, fuzzydate); } + bool val_native(THD *thd, Native *to) + { + return m_func_handler->val_native(thd, this, to); + } }; diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index b3ecd1dfd4d..9917811142c 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -598,6 +598,10 @@ public: double val_real() { return Time(this).to_double(); } String *val_str(String *to) { return Time(this).to_string(to, decimals); } my_decimal *val_decimal(my_decimal *to) { return Time(this).to_decimal(to); } + bool val_native(THD *thd, Native *to) + { + return Time(thd, this).to_native(to, decimals); + } }; diff --git a/sql/sql_type.cc b/sql/sql_type.cc index 6763de17085..85052a1c1bc 100644 --- a/sql/sql_type.cc +++ b/sql/sql_type.cc @@ -628,6 +628,23 @@ uint Interval_DDhhmmssff::fsp(THD *thd, Item *item) } +bool Time::to_native(Native *to, uint decimals) const +{ + if (!is_valid_time()) + { + to->length(0); + return true; + } + uint len= my_time_binary_length(decimals); + if (to->reserve(len)) + return true; + longlong tmp= TIME_to_longlong_time_packed(get_mysql_time()); + my_time_packed_to_binary(tmp, (uchar*) to->ptr(), decimals); + to->length(len); + return false; +} + + void Time::make_from_item(THD *thd, int *warn, Item *item, const Options opt) { *warn= 0; @@ -812,6 +829,28 @@ void Time::make_from_time(int *warn, const MYSQL_TIME *from) } +uint Time::binary_length_to_precision(uint length) +{ + switch (length) { + case 3: return 0; + case 4: return 2; + case 5: return 4; + case 6: return 6; + } + DBUG_ASSERT(0); + return 0; +} + + +Time::Time(const Native &native) +{ + uint dec= binary_length_to_precision(native.length()); + longlong tmp= my_time_packed_from_binary((const uchar *) native.ptr(), dec); + TIME_from_longlong_time_packed(this, tmp); + DBUG_ASSERT(is_valid_time()); +} + + Time::Time(int *warn, const MYSQL_TIME *from, long curdays) { switch (from->time_type) { @@ -1456,6 +1495,13 @@ Type_handler_timestamp_common::type_handler_for_native_format() const } +const Type_handler * +Type_handler_time_common::type_handler_for_native_format() const +{ + return &type_handler_time2; +} + + /***************************************************************************/ const Type_handler *Type_handler_typelib::type_handler_for_item_field() const @@ -8391,6 +8437,51 @@ Type_handler_time_common::create_literal_item(THD *thd, } +bool +Type_handler_time_common::Item_val_native_with_conversion(THD *thd, + Item *item, + Native *to) const +{ + if (item->type_handler()->type_handler_for_native_format() == + &type_handler_time2) + return item->val_native(thd, to); + return Time(thd, item).to_native(to, item->time_precision(thd)); +} + + +bool +Type_handler_time_common::Item_val_native_with_conversion_result(THD *thd, + Item *item, + Native *to) + const +{ + if (item->type_handler()->type_handler_for_native_format() == + &type_handler_time2) + return item->val_native_result(thd, to); + MYSQL_TIME ltime; + if (item->get_date_result(thd, <ime, Time::Options(thd))) + return true; + int warn; + return Time(&warn, <ime, 0).to_native(to, item->time_precision(thd)); +} + + +int Type_handler_time_common::cmp_native(const Native &a, + const Native &b) const +{ + // Optimize a simple case: equal fractional precision: + if (a.length() == b.length()) + return memcmp(a.ptr(), b.ptr(), a.length()); + longlong lla= Time(a).to_packed(); + longlong llb= Time(b).to_packed(); + if (lla < llb) + return -1; + if (lla> llb) + return 1; + return 0; +} + + bool Type_handler_timestamp_common::TIME_to_native(THD *thd, const MYSQL_TIME *ltime, Native *to, @@ -8501,6 +8592,15 @@ Type_handler_timestamp_common::Item_param_val_native(THD *thd, } +bool +Type_handler_time_common::Item_param_val_native(THD *thd, + Item_param *item, + Native *to) const +{ + return Time(thd, item).to_native(to, item->decimals); +} + + LEX_CSTRING Charset::collation_specific_name() const { /* diff --git a/sql/sql_type.h b/sql/sql_type.h index b201ca46861..553d204d806 100644 --- a/sql/sql_type.h +++ b/sql/sql_type.h @@ -1308,6 +1308,7 @@ class Schema; */ class Time: public Temporal { + static uint binary_length_to_precision(uint length); public: enum datetime_to_time_mode_t { @@ -1540,6 +1541,7 @@ public: */ Time(int *warn, bool neg, ulonglong hour, uint minute, const Sec6 &second); Time() { time_type= MYSQL_TIMESTAMP_NONE; } + Time(const Native &native); Time(Item *item) :Time(current_thd, item) { } @@ -1695,6 +1697,7 @@ public: return !is_valid_time() ? 0 : Temporal::to_double(neg, TIME_to_ulonglong_time(this), second_part); } + bool to_native(Native *to, uint decimals) const; String *to_string(String *str, uint dec) const { if (!is_valid_time()) @@ -5324,6 +5327,12 @@ public: { return MYSQL_TIMESTAMP_TIME; } + bool is_val_native_ready() const { return true; } + const Type_handler *type_handler_for_native_format() const; + int cmp_native(const Native &a, const Native &b) const; + bool Item_val_native_with_conversion(THD *thd, Item *, Native *to) const; + bool Item_val_native_with_conversion_result(THD *thd, Item *, Native *to) const; + bool Item_param_val_native(THD *thd, Item_param *item, Native *to) const; Item_literal *create_literal_item(THD *thd, const char *str, size_t length, CHARSET_INFO *cs, bool send_error) const; Item *create_typecast_item(THD *thd, Item *item, From 2e5d86f49e7ee538806fba68dc8c960d6acdd483 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Sat, 22 Aug 2020 15:22:20 +0400 Subject: [PATCH 69/70] MDEV-23537 Comparison with temporal columns is slow in MariaDB Implementing methods: - Field::val_time_packed() - Field::val_datetime_packed() - Item_field::val_datetime_packed(THD *thd); - Item_field::val_time_packed(THD *thd); to give a faster access to temporal packed longlong representation of a Field, which is used in temporal Arg_comparator's to DATE, TIME, DATETIME data types. The same idea is used in MySQL-5.6+. This improves performance. --- sql/field.cc | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++ sql/field.h | 5 +++++ sql/item.cc | 18 ++++++++++++++++ sql/item.h | 2 ++ sql/sql_type.h | 7 +++++++ 5 files changed, 88 insertions(+) diff --git a/sql/field.cc b/sql/field.cc index 65dc7f768a3..bac5dd95b5a 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -2328,6 +2328,33 @@ bool Field::get_date(MYSQL_TIME *to, date_mode_t mode) return !t->is_valid_temporal(); } + +longlong Field::val_datetime_packed(THD *thd) +{ + MYSQL_TIME ltime, tmp; + if (get_date(<ime, Datetime::Options_cmp(thd))) + return 0; + if (ltime.time_type != MYSQL_TIMESTAMP_TIME) + return pack_time(<ime); + if (time_to_datetime_with_warn(thd, <ime, &tmp, TIME_CONV_NONE)) + return 0; + return pack_time(&tmp); +} + + +longlong Field::val_time_packed(THD *thd) +{ + MYSQL_TIME ltime; + Time::Options_cmp opt(thd); + if (get_date(<ime, opt)) + return 0; + if (ltime.time_type == MYSQL_TIMESTAMP_TIME) + return pack_time(<ime); + // Conversion from DATETIME or DATE to TIME is needed + return Time(thd, <ime, opt).to_packed(); +} + + /** This is called when storing a date in a string. @@ -6272,6 +6299,17 @@ bool Field_timef::get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate) return false; } + +longlong Field_timef::val_time_packed(THD *thd) +{ + DBUG_ASSERT(marked_for_read()); + longlong tmp= my_time_packed_from_binary(ptr, dec); + MYSQL_TIME ltime; + TIME_from_longlong_time_packed(<ime, tmp); + return pack_time(<ime); +} + + int Field_timef::store_native(const Native &value) { DBUG_ASSERT(value.length() == my_time_binary_length(dec)); @@ -6673,6 +6711,14 @@ bool Field_newdate::get_TIME(MYSQL_TIME *ltime, const uchar *pos, } +longlong Field_newdate::val_datetime_packed(THD *thd) +{ + MYSQL_TIME ltime; + Field_newdate::get_date(<ime, date_mode_t(0)); + return pack_time(<ime); +} + + int Field_newdate::cmp(const uchar *a_ptr, const uchar *b_ptr) { uint32 a,b; @@ -7008,6 +7054,16 @@ bool Field_datetimef::get_TIME(MYSQL_TIME *ltime, const uchar *pos, return validate_MMDD(tmp, ltime->month, ltime->day, fuzzydate); } +longlong Field_datetimef::val_datetime_packed(THD *thd) +{ + DBUG_ASSERT(marked_for_read()); + longlong tmp= my_datetime_packed_from_binary(ptr, dec); + MYSQL_TIME ltime; + TIME_from_longlong_datetime_packed(<ime, tmp); + return pack_time(<ime); +} + + /**************************************************************************** ** string type ** A string may be varchar or binary diff --git a/sql/field.h b/sql/field.h index 0ee4aca5f69..b3bc2d4dbea 100644 --- a/sql/field.h +++ b/sql/field.h @@ -1401,6 +1401,8 @@ public: void copy_from_tmp(int offset); uint fill_cache_field(struct st_cache_field *copy); virtual bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate); + virtual longlong val_datetime_packed(THD *thd); + virtual longlong val_time_packed(THD *thd); virtual TYPELIB *get_typelib() const { return NULL; } virtual CHARSET_INFO *charset(void) const { return &my_charset_bin; } virtual CHARSET_INFO *charset_for_protocol(void) const @@ -3167,6 +3169,7 @@ public: void sql_type(String &str) const; bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate) { return Field_newdate::get_TIME(ltime, ptr, fuzzydate); } + longlong val_datetime_packed(THD *thd); uint size_of() const { return sizeof(*this); } Item *get_equal_const_item(THD *thd, const Context &ctx, Item *const_item); }; @@ -3336,6 +3339,7 @@ public: } int reset(); bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate); + longlong val_time_packed(THD *thd); int store_native(const Native &value); bool val_native(Native *to); uint size_of() const { return sizeof(*this); } @@ -3495,6 +3499,7 @@ public: int reset(); bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate) { return Field_datetimef::get_TIME(ltime, ptr, fuzzydate); } + longlong val_datetime_packed(THD *thd); uint size_of() const { return sizeof(*this); } }; diff --git a/sql/item.cc b/sql/item.cc index 312effeb6c1..22a8cb169b3 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -3246,6 +3246,24 @@ bool Item_field::val_native_result(THD *thd, Native *to) } +longlong Item_field::val_datetime_packed(THD *thd) +{ + DBUG_ASSERT(fixed == 1); + if ((null_value= field->is_null())) + return 0; + return field->val_datetime_packed(thd); +} + + +longlong Item_field::val_time_packed(THD *thd) +{ + DBUG_ASSERT(fixed == 1); + if ((null_value= field->is_null())) + return 0; + return field->val_time_packed(thd); +} + + void Item_field::save_result(Field *to) { save_field_in_field(result_field, &null_value, to, TRUE); diff --git a/sql/item.h b/sql/item.h index aced2ec5f0d..95ca06ac211 100644 --- a/sql/item.h +++ b/sql/item.h @@ -3418,6 +3418,8 @@ public: longlong val_int_endpoint(bool left_endp, bool *incl_endp); bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate); bool get_date_result(THD *thd, MYSQL_TIME *ltime,date_mode_t fuzzydate); + longlong val_datetime_packed(THD *thd); + longlong val_time_packed(THD *thd); bool is_null() { return field->is_null(); } void update_null_value(); void update_table_bitmaps() diff --git a/sql/sql_type.h b/sql/sql_type.h index 553d204d806..8726208b788 100644 --- a/sql/sql_type.h +++ b/sql/sql_type.h @@ -1542,6 +1542,13 @@ public: Time(int *warn, bool neg, ulonglong hour, uint minute, const Sec6 &second); Time() { time_type= MYSQL_TIMESTAMP_NONE; } Time(const Native &native); + Time(THD *thd, const MYSQL_TIME *ltime, const Options opt) + { + *(static_cast(this))= *ltime; + DBUG_ASSERT(is_valid_temporal()); + int warn= 0; + valid_MYSQL_TIME_to_valid_value(thd, &warn, opt); + } Time(Item *item) :Time(current_thd, item) { } From c58e184b14ccdf0b0eaeeeb7947e23b8b5fff7a7 Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Mon, 24 Aug 2020 10:58:13 +1000 Subject: [PATCH 70/70] MDEV-18841: /var/run -> /run for apparmor/systemd service Match 10.5 path changes in: * b2feb030014f5ff7d71cd55326a93cc709386407 * aaaf005ce61a543f1a1470b179ccb535698b36ef * bb8477778b72f047437b2a03a2bd38997e155f10 --- support-files/mariadb@.service.in | 2 +- support-files/policy/apparmor/usr.sbin.mysqld | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/support-files/mariadb@.service.in b/support-files/mariadb@.service.in index 79f347ec271..14749092103 100644 --- a/support-files/mariadb@.service.in +++ b/support-files/mariadb@.service.in @@ -100,7 +100,7 @@ # in configuration between instances. # # [Service] -# Environment=MYSQLD_MULTI_INSTANCE="--socket=/var/run/mysqld/%I.sock \ +# Environment=MYSQLD_MULTI_INSTANCE="--socket=/run/mysqld/%I.sock \ # --datadir=/var/lib/mysqld-multi/%I \ # --skip-networking" # diff --git a/support-files/policy/apparmor/usr.sbin.mysqld b/support-files/policy/apparmor/usr.sbin.mysqld index 18a9c357ff2..c60ecd28531 100644 --- a/support-files/policy/apparmor/usr.sbin.mysqld +++ b/support-files/policy/apparmor/usr.sbin.mysqld @@ -54,8 +54,8 @@ /var/log/mysql.log rw, /var/log/mysql/ r, /var/log/mysql/* rw, - /var/run/mysqld/mysqld.pid w, - /var/run/mysqld/mysqld.sock w, + /run/mysqld/mysqld.pid w, + /run/mysqld/mysqld.sock w, profile /bin/dash flags=(complain) {