diff options
author | Marko Mäkelä <marko.makela@mariadb.com> | 2021-10-05 13:38:53 +0300 |
---|---|---|
committer | Marko Mäkelä <marko.makela@mariadb.com> | 2021-10-05 13:38:53 +0300 |
commit | 822066acfcd5bbbb0c4dfbcec4f5fa3bd2bc1fe4 (patch) | |
tree | 211cf281a206d9614ae87dc2fb4cc805c1234e1e | |
parent | d5e606c60545eae8ab86d68e9d432c92450c3122 (diff) | |
parent | 4ca56e8348c7bd20cb7544a607b730d6038746b6 (diff) | |
download | mariadb-git-822066acfcd5bbbb0c4dfbcec4f5fa3bd2bc1fe4.tar.gz |
Merge 10.6 into 10.7
-rw-r--r-- | client/mysqldump.c | 2 | ||||
-rw-r--r-- | mysql-test/main/sp.test | 2 | ||||
-rw-r--r-- | mysql-test/suite/galera/r/MDEV-22708.result | 11 | ||||
-rw-r--r-- | mysql-test/suite/galera/r/galera_fulltext.result | 56 | ||||
-rw-r--r-- | mysql-test/suite/galera/t/MDEV-22708.cnf | 4 | ||||
-rw-r--r-- | mysql-test/suite/galera/t/MDEV-22708.test | 14 | ||||
-rw-r--r-- | mysql-test/suite/galera/t/galera_fulltext.test | 64 | ||||
-rw-r--r-- | mysql-test/suite/s3/mysqldump.result | 8 | ||||
-rw-r--r-- | sql/service_wsrep.cc | 11 | ||||
-rw-r--r-- | sql/sql_insert.cc | 2 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 3 | ||||
-rw-r--r-- | storage/innobase/fil/fil0fil.cc | 45 | ||||
-rw-r--r-- | storage/innobase/handler/ha_innodb.cc | 14 | ||||
-rw-r--r-- | storage/innobase/include/fil0fil.h | 66 | ||||
-rw-r--r-- | storage/innobase/include/rw_lock.h | 23 | ||||
-rw-r--r-- | storage/innobase/include/srw_lock.h | 10 | ||||
-rw-r--r-- | storage/innobase/include/trx0rseg.h | 50 | ||||
-rw-r--r-- | storage/innobase/include/trx0trx.h | 32 | ||||
-rw-r--r-- | storage/innobase/lock/lock0lock.cc | 6 | ||||
-rw-r--r-- | storage/innobase/sync/srw_lock.cc | 6 | ||||
-rw-r--r-- | storage/innobase/trx/trx0purge.cc | 6 | ||||
-rw-r--r-- | tests/mysql_client_test.c | 30 |
22 files changed, 377 insertions, 88 deletions
diff --git a/client/mysqldump.c b/client/mysqldump.c index ba47ba266ae..a73f06d592a 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -4518,7 +4518,7 @@ static void dump_table(const char *table, const char *db, const uchar *hash_key, if (!opt_xml && opt_copy_s3_tables && (ignore_flag & IGNORE_S3_TABLE)) { DYNAMIC_STRING alter_string; - init_dynamic_string_checked(&alter_string, "ATER TABLE ", 1024, 1024); + init_dynamic_string_checked(&alter_string, "ALTER TABLE ", 1024, 1024); dynstr_append_checked(&alter_string, opt_quoted_table); dynstr_append_checked(&alter_string, " ENGINE=S3;\n"); fputs(alter_string.str, md_result_file); diff --git a/mysql-test/main/sp.test b/mysql-test/main/sp.test index b1c69faa83a..9e4166b42c1 100644 --- a/mysql-test/main/sp.test +++ b/mysql-test/main/sp.test @@ -10432,7 +10432,7 @@ SELECT VARIABLE_VALUE into @local_mem_used FROM INFORMATION_SCHEMA.SESSION_STATU CREATE PROCEDURE sp1() SELECT 1; SHOW CREATE PROCEDURE sp1; SELECT VARIABLE_VALUE-@local_mem_used FROM INFORMATION_SCHEMA.SESSION_STATUS WHERE VARIABLE_NAME='MEMORY_USED'; -# 10.5 FIXME: This occasionally shows 56 or 64 bytes of difference! +# FIXME: MDEV-26754 main.sp test fails for embedded server #SELECT VARIABLE_VALUE-@global_mem_used FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME='MEMORY_USED'; DROP PROCEDURE sp1; --echo # End of 10.3 tests diff --git a/mysql-test/suite/galera/r/MDEV-22708.result b/mysql-test/suite/galera/r/MDEV-22708.result new file mode 100644 index 00000000000..a672ed7be0d --- /dev/null +++ b/mysql-test/suite/galera/r/MDEV-22708.result @@ -0,0 +1,11 @@ +connection node_2; +connection node_1; +SET @wsrep_forced_binlog_format_saved = @@GLOBAL.wsrep_forced_binlog_format; +SET @@GLOBAL.wsrep_forced_binlog_format = STATEMENT; +CREATE TABLE t1(c INT PRIMARY KEY) ENGINE = MyISAM; +INSERT DELAYED INTO t1 VALUES (1),(2),(3); +SELECT SLEEP(1); +SLEEP(1) +0 +DROP TABLE t1; +SET @@GLOBAL.wsrep_forced_binlog_format = @wsrep_forced_binlog_format_saved; diff --git a/mysql-test/suite/galera/r/galera_fulltext.result b/mysql-test/suite/galera/r/galera_fulltext.result index a22296278fa..94780f235ad 100644 --- a/mysql-test/suite/galera/r/galera_fulltext.result +++ b/mysql-test/suite/galera/r/galera_fulltext.result @@ -36,3 +36,59 @@ COUNT(f1) = 1000 1 DROP TABLE t1; DROP TABLE ten; +connection node_1; +SET @value=REPEAT (1,5001); +CREATE TABLE t (a VARCHAR(5000),FULLTEXT (a)) engine=innodb; +INSERT IGNORE INTO t VALUES(@value); +Warnings: +Warning 1265 Data truncated for column 'a' at row 1 +SELECT COUNT(*) FROM t; +COUNT(*) +1 +connection node_2; +SELECT COUNT(*) FROM t; +COUNT(*) +1 +connection node_1; +DROP TABLE t; +CREATE TABLE t (a VARCHAR(5000)) engine=innodb; +INSERT IGNORE INTO t VALUES(@value); +Warnings: +Warning 1265 Data truncated for column 'a' at row 1 +SELECT COUNT(*) FROM t; +COUNT(*) +1 +connection node_2; +SELECT COUNT(*) FROM t; +COUNT(*) +1 +connection node_1; +DROP TABLE t; +connection node_1; +SET @value=REPEAT (1,5001); +CREATE TABLE t (a VARCHAR(5000),FULLTEXT (a)) engine=innodb DEFAULT CHARSET=utf8; +INSERT IGNORE INTO t VALUES(@value); +Warnings: +Warning 1265 Data truncated for column 'a' at row 1 +SELECT COUNT(*) FROM t; +COUNT(*) +1 +connection node_2; +SELECT COUNT(*) FROM t; +COUNT(*) +1 +connection node_1; +DROP TABLE t; +CREATE TABLE t (a VARCHAR(5000)) engine=innodb DEFAULT CHARSET=utf8; +INSERT IGNORE INTO t VALUES(@value); +Warnings: +Warning 1265 Data truncated for column 'a' at row 1 +SELECT COUNT(*) FROM t; +COUNT(*) +1 +connection node_2; +SELECT COUNT(*) FROM t; +COUNT(*) +1 +connection node_1; +DROP TABLE t; diff --git a/mysql-test/suite/galera/t/MDEV-22708.cnf b/mysql-test/suite/galera/t/MDEV-22708.cnf new file mode 100644 index 00000000000..f7ac4f43082 --- /dev/null +++ b/mysql-test/suite/galera/t/MDEV-22708.cnf @@ -0,0 +1,4 @@ +!include ../galera_2nodes.cnf + +[mysqld] +log-bin
\ No newline at end of file diff --git a/mysql-test/suite/galera/t/MDEV-22708.test b/mysql-test/suite/galera/t/MDEV-22708.test new file mode 100644 index 00000000000..5f75715febf --- /dev/null +++ b/mysql-test/suite/galera/t/MDEV-22708.test @@ -0,0 +1,14 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +SET @wsrep_forced_binlog_format_saved = @@GLOBAL.wsrep_forced_binlog_format; +SET @@GLOBAL.wsrep_forced_binlog_format = STATEMENT; + +CREATE TABLE t1(c INT PRIMARY KEY) ENGINE = MyISAM; + +INSERT DELAYED INTO t1 VALUES (1),(2),(3); +SELECT SLEEP(1); + +DROP TABLE t1; + +SET @@GLOBAL.wsrep_forced_binlog_format = @wsrep_forced_binlog_format_saved; diff --git a/mysql-test/suite/galera/t/galera_fulltext.test b/mysql-test/suite/galera/t/galera_fulltext.test index 7e2fc5e581d..beb6a1b8f6f 100644 --- a/mysql-test/suite/galera/t/galera_fulltext.test +++ b/mysql-test/suite/galera/t/galera_fulltext.test @@ -58,28 +58,50 @@ SELECT COUNT(f1) = 1000 FROM t1 WHERE MATCH(f1) AGAINST ('abcdefjhk'); DROP TABLE t1; DROP TABLE ten; - -# -# Case 2: UTF-8 -# TODO: MDEV-24978 # -#--connection node_1 -#SET @value=REPEAT (1,5001); -#CREATE TABLE t (a VARCHAR(5000),FULLTEXT (a)) engine=innodb DEFAULT CHARSET=utf8; -#INSERT IGNORE INTO t VALUES(@value); -#SELECT COUNT(*) FROM t; +# MDEV-24978 : SIGABRT in __libc_message # -#--connection node_2 -#SELECT COUNT(*) FROM t; -# -#--connection node_1 -#DROP TABLE t; -#CREATE TABLE t (a VARCHAR(5000)) engine=innodb DEFAULT CHARSET=utf8; -#INSERT IGNORE INTO t VALUES(@value); -#SELECT COUNT(*) FROM t; +--connection node_1 +SET @value=REPEAT (1,5001); +CREATE TABLE t (a VARCHAR(5000),FULLTEXT (a)) engine=innodb; +INSERT IGNORE INTO t VALUES(@value); +SELECT COUNT(*) FROM t; + +--connection node_2 +SELECT COUNT(*) FROM t; + +--connection node_1 +DROP TABLE t; +CREATE TABLE t (a VARCHAR(5000)) engine=innodb; +INSERT IGNORE INTO t VALUES(@value); +SELECT COUNT(*) FROM t; + +--connection node_2 +SELECT COUNT(*) FROM t; + +--connection node_1 +DROP TABLE t; + # -#--connection node_2 -#SELECT COUNT(*) FROM t; +# Case 2: UTF-8 # -#--connection node_1 -#DROP TABLE t; +--connection node_1 +SET @value=REPEAT (1,5001); +CREATE TABLE t (a VARCHAR(5000),FULLTEXT (a)) engine=innodb DEFAULT CHARSET=utf8; +INSERT IGNORE INTO t VALUES(@value); +SELECT COUNT(*) FROM t; + +--connection node_2 +SELECT COUNT(*) FROM t; + +--connection node_1 +DROP TABLE t; +CREATE TABLE t (a VARCHAR(5000)) engine=innodb DEFAULT CHARSET=utf8; +INSERT IGNORE INTO t VALUES(@value); +SELECT COUNT(*) FROM t; + +--connection node_2 +SELECT COUNT(*) FROM t; + +--connection node_1 +DROP TABLE t; diff --git a/mysql-test/suite/s3/mysqldump.result b/mysql-test/suite/s3/mysqldump.result index 8d71a022b5c..af9882615c3 100644 --- a/mysql-test/suite/s3/mysqldump.result +++ b/mysql-test/suite/s3/mysqldump.result @@ -23,12 +23,8 @@ CREATE TABLE `t1` ( PRIMARY KEY (`pk`) ) ENGINE=Aria DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1; /*!40101 SET character_set_client = @saved_cs_client */; -INSERT INTO `t1` VALUES -(1,1), -(2,2), -(3,3), -(4,4); -ATER TABLE `t1` ENGINE=S3; +INSERT INTO `t1` VALUES (1,1),(2,2),(3,3),(4,4); +ALTER TABLE `t1` ENGINE=S3; ##### # mysqldump with --copy-s3-tables=1 XML ### diff --git a/sql/service_wsrep.cc b/sql/service_wsrep.cc index 91b1a48cad7..67735972400 100644 --- a/sql/service_wsrep.cc +++ b/sql/service_wsrep.cc @@ -268,12 +268,11 @@ extern "C" my_bool wsrep_thd_order_before(const THD *left, const THD *right) extern "C" my_bool wsrep_thd_is_aborting(const MYSQL_THD thd) { mysql_mutex_assert_owner(&thd->LOCK_thd_data); - if (thd != 0) + + const wsrep::client_state& cs(thd->wsrep_cs()); + const enum wsrep::transaction::state tx_state(cs.transaction().state()); + switch (tx_state) { - const wsrep::client_state& cs(thd->wsrep_cs()); - const enum wsrep::transaction::state tx_state(cs.transaction().state()); - switch (tx_state) - { case wsrep::transaction::s_must_abort: return (cs.state() == wsrep::client_state::s_exec || cs.state() == wsrep::client_state::s_result); @@ -282,8 +281,8 @@ extern "C" my_bool wsrep_thd_is_aborting(const MYSQL_THD thd) return true; default: return false; - } } + return false; } diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index bd4ca508a9e..a3f4e67405a 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -475,7 +475,7 @@ void upgrade_lock_type(THD *thd, thr_lock_type *lock_type, } bool log_on= (thd->variables.option_bits & OPTION_BIN_LOG); - if (global_system_variables.binlog_format == BINLOG_FORMAT_STMT && + if (thd->wsrep_binlog_format() == BINLOG_FORMAT_STMT && log_on && mysql_bin_log.is_open()) { /* diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index dad897265e0..9281563969f 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -73,7 +73,8 @@ /* this is to get the bison compilation windows warnings out */ #ifdef _MSC_VER /* warning C4065: switch statement contains 'default' but no 'case' labels */ -#pragma warning (disable : 4065) +/* warning C4102: 'yyexhaustedlab': unreferenced label */ +#pragma warning (disable : 4065 4102) #endif #ifdef __GNUC__ #pragma GCC diagnostic ignored "-Wunused-label" /* yyexhaustedlab: */ diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc index 360a10f29a6..3fb384b9ff8 100644 --- a/storage/innobase/fil/fil0fil.cc +++ b/storage/innobase/fil/fil0fil.cc @@ -320,7 +320,7 @@ fil_node_t* fil_space_t::add(const char* name, pfs_os_file_t handle, this->size += size; UT_LIST_ADD_LAST(chain, node); if (node->is_open()) { - n_pending.fetch_and(~CLOSING, std::memory_order_relaxed); + clear_closing(); if (++fil_system.n_open >= srv_max_n_open_files) { reacquire(); try_to_close(true); @@ -683,7 +683,7 @@ ATTRIBUTE_COLD bool fil_space_t::prepare(bool have_mutex) } else clear: - n_pending.fetch_and(~CLOSING, std::memory_order_relaxed); + clear_closing(); if (!have_mutex) mysql_mutex_unlock(&fil_system.mutex); @@ -1527,38 +1527,23 @@ static void fil_name_write(uint32_t space_id, const char *name, fil_space_t *fil_space_t::check_pending_operations(uint32_t id) { ut_a(!is_system_tablespace(id)); - bool being_deleted= false; mysql_mutex_lock(&fil_system.mutex); fil_space_t *space= fil_space_get_by_id(id); - if (!space); - else if (space->pending() & STOPPING) - being_deleted= true; - else - { - if (space->crypt_data) - { - space->reacquire(); - mysql_mutex_unlock(&fil_system.mutex); - fil_space_crypt_close_tablespace(space); - mysql_mutex_lock(&fil_system.mutex); - space->release(); - } - being_deleted= space->set_stopping(); - } - mysql_mutex_unlock(&fil_system.mutex); - if (!space) + { + mysql_mutex_unlock(&fil_system.mutex); return nullptr; + } - if (being_deleted) + if (space->pending() & STOPPING) { +being_deleted: /* A thread executing DDL and another thread executing purge may be executing fil_delete_tablespace() concurrently for the same tablespace. Wait for the other thread to complete the operation. */ for (ulint count= 0;; count++) { - mysql_mutex_lock(&fil_system.mutex); space= fil_space_get_by_id(id); ut_ad(!space || space->is_stopping()); mysql_mutex_unlock(&fil_system.mutex); @@ -1569,8 +1554,24 @@ fil_space_t *fil_space_t::check_pending_operations(uint32_t id) sql_print_warning("InnoDB: Waiting for tablespace " UINT32PF " to be deleted", id); std::this_thread::sleep_for(std::chrono::milliseconds(20)); + mysql_mutex_lock(&fil_system.mutex); } } + else + { + if (space->crypt_data) + { + space->reacquire(); + mysql_mutex_unlock(&fil_system.mutex); + fil_space_crypt_close_tablespace(space); + mysql_mutex_lock(&fil_system.mutex); + space->release(); + } + if (space->set_stopping_check()) + goto being_deleted; + } + + mysql_mutex_unlock(&fil_system.mutex); for (ulint count= 0;; count++) { diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index e38110edb60..e992b435b2d 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -6789,10 +6789,14 @@ wsrep_store_key_val_for_row( /* In a column prefix index, we may need to truncate the stored value: */ - if (true_len > key_len) { true_len = key_len; } + /* cannot exceed max column lenght either, we may need to truncate + the stored value: */ + if (true_len > sizeof(sorted)) { + true_len = sizeof(sorted); + } memcpy(sorted, data, true_len); true_len = wsrep_innobase_mysql_sort( @@ -6805,8 +6809,8 @@ wsrep_store_key_val_for_row( actual data. The rest of the space was reset to zero in the bzero() call above. */ if (true_len > buff_space) { - fprintf (stderr, - "WSREP: key truncated: %s\n", + WSREP_DEBUG ( + "write set key truncated for: %s\n", wsrep_thd_query(thd)); true_len = buff_space; } @@ -18507,7 +18511,7 @@ void lock_wait_wsrep_kill(trx_t *bf_trx, ulong thd_id, trx_id_t trx_id) wsrep_thd_transaction_state_str(vthd), wsrep_thd_query(vthd)); /* Mark transaction as a victim for Galera abort */ - vtrx->lock.was_chosen_as_deadlock_victim.fetch_or(2); + vtrx->lock.set_wsrep_victim(); if (!wsrep_thd_set_wsrep_aborter(bf_thd, vthd)) aborting= true; else @@ -18562,7 +18566,7 @@ wsrep_abort_transaction( wsrep_thd_transaction_state_str(victim_thd)); if (victim_trx) { - victim_trx->lock.was_chosen_as_deadlock_victim.fetch_or(2); + victim_trx->lock.set_wsrep_victim(); wsrep_thd_kill_LOCK(victim_thd); wsrep_thd_LOCK(victim_thd); diff --git a/storage/innobase/include/fil0fil.h b/storage/innobase/include/fil0fil.h index 365f8367292..1c306670354 100644 --- a/storage/innobase/include/fil0fil.h +++ b/storage/innobase/include/fil0fil.h @@ -511,7 +511,9 @@ public: /** Note that operations on the tablespace must stop. @return whether the operations were already stopped */ - inline bool set_stopping(); + inline bool set_stopping_check(); + /** Note that operations on the tablespace must stop. */ + inline void set_stopping(); /** Note that operations on the tablespace can resume after truncation */ inline void clear_stopping(); @@ -566,9 +568,35 @@ public: /** Clear the NEEDS_FSYNC flag */ void clear_flush() - { n_pending.fetch_and(~NEEDS_FSYNC, std::memory_order_release); } + { +#if defined __GNUC__ && (defined __i386__ || defined __x86_64__) + static_assert(NEEDS_FSYNC == 1U << 29, "compatibility"); + __asm__ __volatile__("lock btrl $29, %0" : "+m" (n_pending)); +#elif defined _MSC_VER && (defined _M_IX86 || defined _M_IX64) + static_assert(NEEDS_FSYNC == 1U << 29, "compatibility"); + _interlockedbittestandreset(reinterpret_cast<volatile long*> + (&n_pending), 29); +#else + n_pending.fetch_and(~NEEDS_FSYNC, std::memory_order_release); +#endif + } private: + /** Clear the CLOSING flag */ + void clear_closing() + { +#if defined __GNUC__ && (defined __i386__ || defined __x86_64__) + static_assert(CLOSING == 1U << 30, "compatibility"); + __asm__ __volatile__("lock btrl $30, %0" : "+m" (n_pending)); +#elif defined _MSC_VER && (defined _M_IX86 || defined _M_IX64) + static_assert(CLOSING == 1U << 30, "compatibility"); + _interlockedbittestandreset(reinterpret_cast<volatile long*> + (&n_pending), 30); +#else + n_pending.fetch_and(~CLOSING, std::memory_order_relaxed); +#endif + } + /** @return pending operations (and flags) */ uint32_t pending()const { return n_pending.load(std::memory_order_acquire); } public: @@ -1452,16 +1480,46 @@ inline void fil_space_t::reacquire() /** Note that operations on the tablespace must stop. @return whether the operations were already stopped */ -inline bool fil_space_t::set_stopping() +inline bool fil_space_t::set_stopping_check() { mysql_mutex_assert_owner(&fil_system.mutex); +#if defined __GNUC__ && (defined __i386__ || defined __x86_64__) + static_assert(STOPPING == 1U << 31, "compatibility"); + __asm__ goto("lock btsl $31, %0\t\njnc %l1" : : "m" (n_pending) + : "cc", "memory" : not_stopped); + return true; +not_stopped: + return false; +#elif defined _MSC_VER && (defined _M_IX86 || defined _M_IX64) + static_assert(STOPPING == 1U << 31, "compatibility"); + return _interlockedbittestandset(reinterpret_cast<volatile long*> + (&n_pending), 31); +#else return n_pending.fetch_or(STOPPING, std::memory_order_relaxed) & STOPPING; +#endif +} + +/** Note that operations on the tablespace must stop. +@return whether the operations were already stopped */ +inline void fil_space_t::set_stopping() +{ + mysql_mutex_assert_owner(&fil_system.mutex); +#if defined __GNUC__ && (defined __i386__ || defined __x86_64__) + static_assert(STOPPING == 1U << 31, "compatibility"); + __asm__ __volatile__("lock btsl $31, %0" : "+m" (n_pending)); +#elif defined _MSC_VER && (defined _M_IX86 || defined _M_IX64) + static_assert(STOPPING == 1U << 31, "compatibility"); + _interlockedbittestandset(reinterpret_cast<volatile long*>(&n_pending), 31); +#else + n_pending.fetch_or(STOPPING, std::memory_order_relaxed); +#endif } inline void fil_space_t::clear_stopping() { mysql_mutex_assert_owner(&fil_system.mutex); - ut_d(auto n=) n_pending.fetch_and(~STOPPING, std::memory_order_relaxed); + static_assert(STOPPING == 1U << 31, "compatibility"); + ut_d(auto n=) n_pending.fetch_sub(STOPPING, std::memory_order_relaxed); ut_ad(n & STOPPING); } diff --git a/storage/innobase/include/rw_lock.h b/storage/innobase/include/rw_lock.h index cd176f0b35b..ba380b77261 100644 --- a/storage/innobase/include/rw_lock.h +++ b/storage/innobase/include/rw_lock.h @@ -50,9 +50,22 @@ protected: static constexpr uint32_t UPDATER= 1U << 29; #endif /* SUX_LOCK_GENERIC */ + /** Start waiting for an exclusive lock. */ + void write_lock_wait_start() + { +#if defined __GNUC__ && (defined __i386__ || defined __x86_64__) + static_assert(WRITER_WAITING == 1U << 30, "compatibility"); + __asm__ __volatile__("lock btsl $30, %0" : "+m" (lock)); +#elif defined _MSC_VER && (defined _M_IX86 || defined _M_IX64) + static_assert(WRITER_WAITING == 1U << 30, "compatibility"); + _interlockedbittestandset(reinterpret_cast<volatile long*>(&lock), 30); +#else + lock.fetch_or(WRITER_WAITING, std::memory_order_relaxed); +#endif + } /** Start waiting for an exclusive lock. @return current value of the lock word */ - uint32_t write_lock_wait_start() + uint32_t write_lock_wait_start_read() { return lock.fetch_or(WRITER_WAITING, std::memory_order_relaxed); } /** Wait for an exclusive lock. @param l the value of the lock word @@ -183,8 +196,12 @@ public: /** Release an exclusive lock */ void write_unlock() { - IF_DBUG_ASSERT(auto l=,) - lock.fetch_and(~WRITER, std::memory_order_release); + /* Below, we use fetch_sub(WRITER) instead of fetch_and(~WRITER). + The reason is that on IA-32 and AMD64 it translates into the 80486 + instruction LOCK XADD, while fetch_and() translates into a loop + around LOCK CMPXCHG. For other ISA either form should be fine. */ + static_assert(WRITER == 1U << 31, "compatibility"); + IF_DBUG_ASSERT(auto l=,) lock.fetch_sub(WRITER, std::memory_order_release); /* the write lock must have existed */ #ifdef SUX_LOCK_GENERIC DBUG_ASSERT((l & (WRITER | UPDATER)) == WRITER); diff --git a/storage/innobase/include/srw_lock.h b/storage/innobase/include/srw_lock.h index 3d0d82b81df..9e2eac15df0 100644 --- a/storage/innobase/include/srw_lock.h +++ b/storage/innobase/include/srw_lock.h @@ -226,8 +226,18 @@ public: void wr_lock() { writer.wr_lock(); +#if defined __i386__||defined __x86_64__||defined _M_IX86||defined _M_IX64 + /* On IA-32 and AMD64, this type of fetch_or() can only be implemented + as a loop around LOCK CMPXCHG. In this particular case, setting the + most significant bit using fetch_add() is equivalent, and is + translated into a simple LOCK XADD. */ + static_assert(WRITER == 1U << 31, "compatibility"); + if (uint32_t lk= readers.fetch_add(WRITER, std::memory_order_acquire)) + wr_wait(lk); +#else if (uint32_t lk= readers.fetch_or(WRITER, std::memory_order_acquire)) wr_wait(lk); +#endif } void u_wr_upgrade() diff --git a/storage/innobase/include/trx0rseg.h b/storage/innobase/include/trx0rseg.h index 0cfa5d734be..ba2537715c4 100644 --- a/storage/innobase/include/trx0rseg.h +++ b/storage/innobase/include/trx0rseg.h @@ -93,6 +93,43 @@ private: static constexpr uint32_t REF= 4; uint32_t ref_load() const { return ref.load(std::memory_order_relaxed); } + + /** Set a bit in ref */ + template<bool needs_purge> void ref_set() + { + static_assert(SKIP == 1U << 0, "compatibility"); + static_assert(NEEDS_PURGE == 1U << 1, "compatibility"); +#if defined __GNUC__ && (defined __i386__ || defined __x86_64__) + if (needs_purge) + __asm__ __volatile__("lock btsl $1, %0" : "+m" (ref)); + else + __asm__ __volatile__("lock btsl $0, %0" : "+m" (ref)); +#elif defined _MSC_VER && (defined _M_IX86 || defined _M_IX64) + _interlockedbittestandset(reinterpret_cast<volatile long*>(&ref), + needs_purge); +#else + ref.fetch_or(needs_purge ? NEEDS_PURGE : SKIP, std::memory_order_relaxed); +#endif + } + /** Clear a bit in ref */ + template<bool needs_purge> void ref_reset() + { + static_assert(SKIP == 1U << 0, "compatibility"); + static_assert(NEEDS_PURGE == 1U << 1, "compatibility"); +#if defined __GNUC__ && (defined __i386__ || defined __x86_64__) + if (needs_purge) + __asm__ __volatile__("lock btrl $1, %0" : "+m" (ref)); + else + __asm__ __volatile__("lock btrl $0, %0" : "+m" (ref)); +#elif defined _MSC_VER && (defined _M_IX86 || defined _M_IX64) + _interlockedbittestandreset(reinterpret_cast<volatile long*>(&ref), + needs_purge); +#else + ref.fetch_and(needs_purge ? ~NEEDS_PURGE : ~SKIP, + std::memory_order_relaxed); +#endif + } + public: /** Initialize the fields that are not zero-initialized. */ @@ -103,21 +140,22 @@ public: void destroy(); /** Note that undo tablespace truncation was started. */ - void set_skip_allocation() - { ut_ad(is_persistent()); ref.fetch_or(SKIP, std::memory_order_relaxed); } + void set_skip_allocation() { ut_ad(is_persistent()); ref_set<false>(); } /** Note that undo tablespace truncation was completed. */ void clear_skip_allocation() { ut_ad(is_persistent()); +#if defined DBUG_OFF + ref_reset<false>(); +#else ut_d(auto r=) ref.fetch_and(~SKIP, std::memory_order_relaxed); ut_ad(r == SKIP); +#endif } /** Note that the rollback segment requires purge. */ - void set_needs_purge() - { ref.fetch_or(NEEDS_PURGE, std::memory_order_relaxed); } + void set_needs_purge() { ref_set<true>(); } /** Note that the rollback segment will not require purge. */ - void clear_needs_purge() - { ref.fetch_and(~NEEDS_PURGE, std::memory_order_relaxed); } + void clear_needs_purge() { ref_reset<true>(); } /** @return whether the segment is marked for undo truncation */ bool skip_allocation() const { return ref_load() & SKIP; } /** @return whether the segment needs purge */ diff --git a/storage/innobase/include/trx0trx.h b/storage/innobase/include/trx0trx.h index 343e7d42dc4..86e8b534f54 100644 --- a/storage/innobase/include/trx0trx.h +++ b/storage/innobase/include/trx0trx.h @@ -342,6 +342,38 @@ struct trx_lock_t 1=another transaction chose this as a victim in deadlock resolution. */ Atomic_relaxed<byte> was_chosen_as_deadlock_victim; + /** Clear the deadlock victim status. */ + void clear_deadlock_victim() + { +#ifndef WITH_WSREP + was_chosen_as_deadlock_victim= false; +#elif defined __GNUC__ && (defined __i386__ || defined __x86_64__) + /* There is no 8-bit version of the 80386 BTR instruction. + Technically, this is the wrong addressing mode (16-bit), but + there are other data members stored after the byte. */ + __asm__ __volatile__("lock btrw $0, %0" + : "+m" (was_chosen_as_deadlock_victim)); +#else + was_chosen_as_deadlock_victim.fetch_and(byte(~1)); +#endif + } + +#ifdef WITH_WSREP + /** Flag the lock owner as a victim in Galera conflict resolution. */ + void set_wsrep_victim() + { +# if defined __GNUC__ && (defined __i386__ || defined __x86_64__) + /* There is no 8-bit version of the 80386 BTS instruction. + Technically, this is the wrong addressing mode (16-bit), but + there are other data members stored after the byte. */ + __asm__ __volatile__("lock btsw $1, %0" + : "+m" (was_chosen_as_deadlock_victim)); +# else + was_chosen_as_deadlock_victim.fetch_or(2); +# endif + } +#endif + /** Next available rec_pool[] entry */ byte rec_cached; /** Next available table_pool[] entry */ diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc index 41da85dcc98..47e30e075a0 100644 --- a/storage/innobase/lock/lock0lock.cc +++ b/storage/innobase/lock/lock0lock.cc @@ -1282,8 +1282,7 @@ lock_rec_enqueue_waiting( } trx->lock.wait_thr = thr; - trx->lock.was_chosen_as_deadlock_victim - IF_WSREP(.fetch_and(byte(~1)), = false); + trx->lock.clear_deadlock_victim(); DBUG_LOG("ib_lock", "trx " << ib::hex(trx->id) << " waits for lock in index " << index->name @@ -3333,8 +3332,7 @@ lock_table_enqueue_waiting( lock_table_create(table, mode | LOCK_WAIT, trx, c_lock); trx->lock.wait_thr = thr; - trx->lock.was_chosen_as_deadlock_victim - IF_WSREP(.fetch_and(byte(~1)), = false); + trx->lock.clear_deadlock_victim(); MONITOR_INC(MONITOR_TABLELOCK_WAIT); return(DB_LOCK_WAIT); diff --git a/storage/innobase/sync/srw_lock.cc b/storage/innobase/sync/srw_lock.cc index 7d26dd2b590..2e22a01eb8f 100644 --- a/storage/innobase/sync/srw_lock.cc +++ b/storage/innobase/sync/srw_lock.cc @@ -193,10 +193,10 @@ void ssux_lock_impl<spinloop>::write_lock(bool holding_u) { for (;;) { - uint32_t l= write_lock_wait_start(); + write_lock_wait_start(); const uint32_t e= holding_u ? WRITER_WAITING | UPDATER : WRITER_WAITING; - l= e; + uint32_t l= e; if (write_lock_wait_try(l)) return; @@ -213,7 +213,7 @@ void ssux_lock_impl<spinloop>::write_lock(bool holding_u) return; } - for (l= write_lock_wait_start() | WRITER_WAITING; + for (l= write_lock_wait_start_read() | WRITER_WAITING; (l | WRITER_WAITING) == e; ) if (write_lock_wait_try(l)) return; diff --git a/storage/innobase/trx/trx0purge.cc b/storage/innobase/trx/trx0purge.cc index b2d602ad5b5..77354a8da91 100644 --- a/storage/innobase/trx/trx0purge.cc +++ b/storage/innobase/trx/trx0purge.cc @@ -540,6 +540,12 @@ static void trx_purge_cleanse_purge_queue(const fil_space_t& space) mysql_mutex_unlock(&purge_sys.pq_mutex); } +#if defined __GNUC__ && __GNUC__ == 4 && !defined __clang__ +# if defined __arm__ || defined __aarch64__ +/* Work around an internal compiler error in GCC 4.8.5 */ +__attribute__((optimize(0))) +# endif +#endif /** Removes unnecessary history data from rollback segments. NOTE that when this function is called, the caller must not have any latches on undo log pages! diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index dfcbcf344de..86485f502ef 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -40,6 +40,8 @@ #include <arpa/inet.h> #endif +#include "my_valgrind.h" + static const my_bool my_true= 1; @@ -672,6 +674,11 @@ static void test_wl4435() /* Init PS-parameters. */ + memset(str_data, 0, sizeof str_data); + memset(dbl_data, 0, sizeof dbl_data); + memset(dec_data, 0, sizeof dec_data); + memset(int_data, 0, sizeof int_data); + bzero((char *) ps_params, sizeof (ps_params)); /* - v0 -- INT */ @@ -1072,7 +1079,7 @@ static void test_wl4435_2() MYSQL_RES *rs_metadata; \ MYSQL_FIELD *fields; \ c_type pspv c_type_ext; \ - my_bool psp_null; \ + my_bool psp_null= FALSE; \ \ bzero(&pspv, sizeof (pspv)); \ \ @@ -1133,6 +1140,7 @@ static void test_wl4435_3() { char tmp[255]; + memset(tmp, 0, sizeof tmp); puts(""); /* @@ -1631,6 +1639,7 @@ static void test_double_compare() my_bind[2].buffer= (void *)&double_data; tiny_data= 1; + memset(real_data, 0, sizeof real_data); strmov(real_data, "10.2"); double_data= 34.5; rc= mysql_stmt_bind_param(stmt, my_bind); @@ -7419,6 +7428,7 @@ static void test_decimal_bug() rc= mysql_stmt_bind_param(stmt, my_bind); check_execute(stmt, rc); + memset(data, 0, sizeof data); strmov(data, "8.0"); rc= mysql_stmt_execute(stmt); check_execute(stmt, rc); @@ -11571,6 +11581,7 @@ static void test_view_insert_fields() my_bind[i].is_null= 0; my_bind[i].buffer= (char *)&parm[i]; + memset(parm[i], 0, sizeof parm[i]); strmov(parm[i], "1"); my_bind[i].buffer_length= 2; my_bind[i].length= &l[i]; @@ -13168,6 +13179,7 @@ static void test_bug8330() check_execute(stmt[i], rc); my_bind[i].buffer_type= MYSQL_TYPE_LONG; + lval[i]= 0; my_bind[i].buffer= (void*) &lval[i]; my_bind[i].is_null= 0; mysql_stmt_bind_param(stmt[i], &my_bind[i]); @@ -15904,6 +15916,7 @@ static void test_bug20152() my_bind[0].buffer_type= MYSQL_TYPE_DATE; my_bind[0].buffer= (void*)&tm; + memset(&tm, 0, sizeof tm); tm.year = 2006; tm.month = 6; tm.day = 18; @@ -18939,6 +18952,7 @@ static void test_bug49972() in_param_bind.buffer_type= MYSQL_TYPE_LONG; in_param_bind.buffer= (char *) &int_data; + int_data= 0; in_param_bind.length= 0; in_param_bind.is_null= 0; @@ -19460,6 +19474,7 @@ static void test_ps_sp_out_params() DIE_UNLESS(mysql_stmt_param_count(stmt) == 1); memset(bind, 0, sizeof(MYSQL_BIND)); + memset(buffer, 0, sizeof buffer); bind[0].buffer= buffer; bind[0].buffer_length= sizeof(buffer); bind[0].buffer_type= MYSQL_TYPE_STRING; @@ -20135,6 +20150,7 @@ static void test_mdev14454_internal(const char *init, DIE_UNLESS(rc == 0); DIE_UNLESS(mysql_stmt_param_count(stmt) == 1); + memset(&bind, 0, sizeof bind); bind.buffer_type= MYSQL_TYPE_NULL; rc= mysql_stmt_bind_param(stmt, &bind); DIE_UNLESS(rc == 0); @@ -20143,7 +20159,6 @@ static void test_mdev14454_internal(const char *init, DIE_UNLESS(rc == 0); memset(res, 0, sizeof(res)); - memset(&bind, 0, sizeof(bind)); bind.buffer_type= MYSQL_TYPE_STRING; bind.buffer_length= sizeof(res); bind.buffer= res; @@ -20756,6 +20771,7 @@ static void test_ps_params_in_ctes() int_data[0]=2; + memset(ps_params, 0, sizeof ps_params); ps_params[0].buffer_type= MYSQL_TYPE_LONG; ps_params[0].buffer= (char *) &int_data[0]; ps_params[0].length= 0; @@ -21181,7 +21197,10 @@ static void test_explain_meta() } -#ifndef EMBEDDED_LIBRARY +#if __has_feature(memory_sanitizer) +/* FIXME: MDEV-26761: main.mysql_client_test fails with MemorySanitizer */ +#elif defined EMBEDDED_LIBRARY +#else #define MDEV19838_MAX_PARAM_COUNT 32 #define MDEV19838_FIELDS_COUNT 17 static void test_mdev19838() @@ -21891,7 +21910,10 @@ static struct my_tests_st my_tests[]= { #endif { "test_ps_params_in_ctes", test_ps_params_in_ctes }, { "test_explain_meta", test_explain_meta }, -#ifndef EMBEDDED_LIBRARY +#if __has_feature(memory_sanitizer) +/* FIXME: MDEV-26761: main.mysql_client_test fails with MemorySanitizer */ +#elif defined EMBEDDED_LIBRARY +#else { "test_mdev19838", test_mdev19838 }, #endif { "test_mdev18408", test_mdev18408 }, |