summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarko Mäkelä <marko.makela@mariadb.com>2021-10-05 13:38:53 +0300
committerMarko Mäkelä <marko.makela@mariadb.com>2021-10-05 13:38:53 +0300
commit822066acfcd5bbbb0c4dfbcec4f5fa3bd2bc1fe4 (patch)
tree211cf281a206d9614ae87dc2fb4cc805c1234e1e
parentd5e606c60545eae8ab86d68e9d432c92450c3122 (diff)
parent4ca56e8348c7bd20cb7544a607b730d6038746b6 (diff)
downloadmariadb-git-822066acfcd5bbbb0c4dfbcec4f5fa3bd2bc1fe4.tar.gz
Merge 10.6 into 10.7
-rw-r--r--client/mysqldump.c2
-rw-r--r--mysql-test/main/sp.test2
-rw-r--r--mysql-test/suite/galera/r/MDEV-22708.result11
-rw-r--r--mysql-test/suite/galera/r/galera_fulltext.result56
-rw-r--r--mysql-test/suite/galera/t/MDEV-22708.cnf4
-rw-r--r--mysql-test/suite/galera/t/MDEV-22708.test14
-rw-r--r--mysql-test/suite/galera/t/galera_fulltext.test64
-rw-r--r--mysql-test/suite/s3/mysqldump.result8
-rw-r--r--sql/service_wsrep.cc11
-rw-r--r--sql/sql_insert.cc2
-rw-r--r--sql/sql_yacc.yy3
-rw-r--r--storage/innobase/fil/fil0fil.cc45
-rw-r--r--storage/innobase/handler/ha_innodb.cc14
-rw-r--r--storage/innobase/include/fil0fil.h66
-rw-r--r--storage/innobase/include/rw_lock.h23
-rw-r--r--storage/innobase/include/srw_lock.h10
-rw-r--r--storage/innobase/include/trx0rseg.h50
-rw-r--r--storage/innobase/include/trx0trx.h32
-rw-r--r--storage/innobase/lock/lock0lock.cc6
-rw-r--r--storage/innobase/sync/srw_lock.cc6
-rw-r--r--storage/innobase/trx/trx0purge.cc6
-rw-r--r--tests/mysql_client_test.c30
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 },