From d5a15f04f4ab0738b0a5f993b208bcfaad522fd4 Mon Sep 17 00:00:00 2001 From: sjaakola Date: Wed, 29 Sep 2021 11:24:18 +0300 Subject: [PATCH 01/12] MDEV-24978 crash with transaction on table with no PK and long fulltext column MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If a table has no unique indexes, write set key information will be collected on all columns in the table. The write set key information has space only for max 3500 bytes for individual column, and if a varchar colummn of such non-primary key table is longer than this limit, currently a crash follows. The fix in this commit, is to truncate key values extracted from such long varhar columns to max 3500 bytes. This may potentially lead to false positive certification failures for transactions, which operate on separate cluster nodes, and update/insert/delete table rows, which differ only in the part of such long columns after 3500 bytes border. Reviewed-by: Jan Lindström --- .../suite/galera/r/galera_fulltext.result | 56 ++++++++++++++++ .../suite/galera/t/galera_fulltext.test | 64 +++++++++++++------ storage/innobase/handler/ha_innodb.cc | 10 ++- 3 files changed, 106 insertions(+), 24 deletions(-) diff --git a/mysql-test/suite/galera/r/galera_fulltext.result b/mysql-test/suite/galera/r/galera_fulltext.result index 18e3bff40fc..bb482b7f4f7 100644 --- a/mysql-test/suite/galera/r/galera_fulltext.result +++ b/mysql-test/suite/galera/r/galera_fulltext.result @@ -34,3 +34,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/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; +# +# MDEV-24978 : SIGABRT in __libc_message +# +--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; + # # 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; -# -#--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; +--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/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index a42e8e3699c..fefd0bdde00 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -7218,10 +7218,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( @@ -7234,8 +7238,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; } From 2f5ae0da71d097fa5619ece6aa5dac075282d519 Mon Sep 17 00:00:00 2001 From: mkaruza Date: Fri, 17 Sep 2021 14:20:02 +0200 Subject: [PATCH 02/12] MDEV-25883 Galera Cluster hangs while "DELETE FROM mysql.wsrep_cluster" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Using `innodb_thread_concurrency` will call `wsrep_thd_is_aborting` to check WSREP thread state. This call should be protected by taking `LOCK_thd_data` before entering function. Applier and TOI threads should no be affected with usage of `innodb_thread_concurrency` variable so returning before any checks. Reviewed-by: Jan Lindström --- sql/service_wsrep.cc | 11 +++++------ storage/innobase/handler/ha_innodb.cc | 12 ++++++++++-- storage/innobase/srv/srv0conc.cc | 8 ++++++++ 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/sql/service_wsrep.cc b/sql/service_wsrep.cc index 14f136ca480..4f8e3402610 100644 --- a/sql/service_wsrep.cc +++ b/sql/service_wsrep.cc @@ -269,12 +269,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); @@ -283,8 +282,8 @@ extern "C" my_bool wsrep_thd_is_aborting(const MYSQL_THD thd) return true; default: return false; - } } + return false; } diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 2afe3af9eaf..81952f73058 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -1689,7 +1689,11 @@ static inline void innobase_srv_conc_enter_innodb(row_prebuilt_t *prebuilt) trx_t* trx = prebuilt->trx; #ifdef WITH_WSREP - if (trx->is_wsrep() && wsrep_thd_is_BF(trx->mysql_thd, FALSE)) return; + if (global_system_variables.wsrep_on && + (wsrep_thd_is_applying(trx->mysql_thd) + || wsrep_thd_is_toi(trx->mysql_thd))) { + return; + } #endif /* WITH_WSREP */ if (srv_thread_concurrency) { @@ -1725,7 +1729,11 @@ static inline void innobase_srv_conc_exit_innodb(row_prebuilt_t *prebuilt) trx_t* trx = prebuilt->trx; #ifdef WITH_WSREP - if (trx->is_wsrep() && wsrep_thd_is_BF(trx->mysql_thd, FALSE)) return; + if (global_system_variables.wsrep_on && + (wsrep_thd_is_applying(trx->mysql_thd) + || wsrep_thd_is_toi(trx->mysql_thd))) { + return; + } #endif /* WITH_WSREP */ /* This is to avoid making an unnecessary function call. */ diff --git a/storage/innobase/srv/srv0conc.cc b/storage/innobase/srv/srv0conc.cc index 6167c8daeba..ba264ba7d6b 100644 --- a/storage/innobase/srv/srv0conc.cc +++ b/storage/innobase/srv/srv0conc.cc @@ -118,7 +118,12 @@ srv_conc_enter_innodb_with_atomics( for (;;) { ulint sleep_in_us; #ifdef WITH_WSREP + /* We need to take `thd->LOCK_thd_data` to check WSREP thread state */ + if (trx->is_wsrep()) { + wsrep_thd_LOCK(trx->mysql_thd); + } if (trx->is_wsrep() && wsrep_thd_is_aborting(trx->mysql_thd)) { + wsrep_thd_UNLOCK(trx->mysql_thd); if (UNIV_UNLIKELY(wsrep_debug)) { ib::info() << "srv_conc_enter due to MUST_ABORT"; @@ -126,6 +131,9 @@ srv_conc_enter_innodb_with_atomics( srv_conc_force_enter_innodb(trx); return; } + if (trx->is_wsrep()) { + wsrep_thd_UNLOCK(trx->mysql_thd); + } #endif /* WITH_WSREP */ if (srv_thread_concurrency == 0) { From 86a2e2ba9051888d457b6a5d0b4fb2879e24beb5 Mon Sep 17 00:00:00 2001 From: mkaruza Date: Wed, 22 Sep 2021 14:30:03 +0200 Subject: [PATCH 03/12] MDEV-22708 Assertion `!mysql_bin_log.is_open() || thd.is_current_stmt_binlog_format_row()' failed in Delayed_insert::handle_inserts and in Diagnostics_area::set_eof_status MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Variable wsrep_forced_binlog_format has higher priority than binlog_format. In situation where STATEMENT is used and DELAYED INSERT is executing we should fall back to non-delay INSERT. Reviewed-by: Jan Lindström --- mysql-test/suite/galera/r/MDEV-22708.result | 11 +++++++++++ mysql-test/suite/galera/t/MDEV-22708.cnf | 4 ++++ mysql-test/suite/galera/t/MDEV-22708.test | 14 ++++++++++++++ sql/sql_insert.cc | 2 +- 4 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 mysql-test/suite/galera/r/MDEV-22708.result create mode 100644 mysql-test/suite/galera/t/MDEV-22708.cnf create mode 100644 mysql-test/suite/galera/t/MDEV-22708.test 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/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/sql/sql_insert.cc b/sql/sql_insert.cc index cbd815eb8fd..4dd0ec3375b 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -474,7 +474,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()) { /* From ec619a1def69c175d9fa07201b2567c3478e9408 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Sat, 2 Oct 2021 09:25:40 +0300 Subject: [PATCH 04/12] MDEV-26467 fixup: Prefer fetch_add() to fetch_or() on IA-32 and AMD64 --- storage/innobase/include/srw_lock.h | 10 ++++++++++ 1 file changed, 10 insertions(+) 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() From 98a7fa0ce792408e964ea00cdc571197a513f217 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Sat, 2 Oct 2021 11:14:14 +0300 Subject: [PATCH 05/12] MDEV-26720: optimize rw_lock for IA-32, AMD64 --- storage/innobase/include/rw_lock.h | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/storage/innobase/include/rw_lock.h b/storage/innobase/include/rw_lock.h index b50a76fa779..e9d35c0171f 100644 --- a/storage/innobase/include/rw_lock.h +++ b/storage/innobase/include/rw_lock.h @@ -38,7 +38,17 @@ protected: /** Start waiting for an exclusive lock. */ void write_lock_wait_start() - { lock.fetch_or(WRITER_WAITING, std::memory_order_relaxed); } + { +#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(&lock), 30); +#else + lock.fetch_or(WRITER_WAITING, std::memory_order_relaxed); +#endif + } /** Try to acquire a shared lock. @param l the value of the lock word @return whether the lock was acquired */ From 0144d1d2a67f346f7e393a7689f44372f18ae40d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Sat, 2 Oct 2021 11:29:44 +0300 Subject: [PATCH 06/12] MDEV-26720: rw_lock: Prefer fetch_sub() to fetch_and() rw_lock::write_unlock(): Revert part of commit d46b42489a62124a672e7abea1d393f519979828 (MDEV-24142) to make the IA-32 and AMD64 implementation faster. --- storage/innobase/include/rw_lock.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/storage/innobase/include/rw_lock.h b/storage/innobase/include/rw_lock.h index e2f7b6b9508..ba380b77261 100644 --- a/storage/innobase/include/rw_lock.h +++ b/storage/innobase/include/rw_lock.h @@ -196,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); From 668a5f3d122ef3c935bf365d8084fb9713f44c60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Sun, 3 Oct 2021 13:49:40 +0300 Subject: [PATCH 07/12] MDEV-26720: Optimize single-bit atomic operations on IA-32 and AMD64 This is mostly working around a bad compiler optimization. The Intel 80386 processor introduced some bit operations that would be the perfect translation for atomic single-bit read-modify-and-write operations. Alas, even the latest compilers as of today (GCC 11, clang 13, Microsoft Visual C 19.29) would generate a loop around LOCK CMPXCHG instead of emitting the instructions LOCK BTS (fetch_or()), LOCK BTR (fetch_and()), LOCK BTC (fetch_xor()). fil_space_t::clear_closing(): Clear the CLOSING flag. fil_space_t::set_stopping_check(): Special variant of fil_space_t::set_stopping() that will return the old value of the STOPPING flag after atomically setting it. fil_space_t::clear_stopping(): Use fetch_sub() to toggle the STOPPING flag. The flag is guaranteed to be set upon calling this function, hence we will toggle it to clear it. On IA-32 and AMD64, this will translate into the 80486 LOCK XADD instruction. fil_space_t::check_pending_operations(): Replace a Boolean variable with a goto label, to allow more compact code generation for fil_space_t::set_stopping_check(). trx_rseg_t: Define private accessors ref_set() and ref_reset() for setting and clearing the flags. trx_lock_t::clear_deadlock_victim(), trx_lock_t::set_wsrep_victim(): Accessors for clearing and setting the flags. --- storage/innobase/fil/fil0fil.cc | 49 ++++++++++---------- storage/innobase/handler/ha_innodb.cc | 4 +- storage/innobase/include/fil0fil.h | 66 +++++++++++++++++++++++++-- storage/innobase/include/trx0rseg.h | 50 +++++++++++++++++--- storage/innobase/include/trx0trx.h | 32 +++++++++++++ storage/innobase/lock/lock0lock.cc | 6 +-- 6 files changed, 167 insertions(+), 40 deletions(-) diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc index e64afa8e2b3..adb4bdef1c5 100644 --- a/storage/innobase/fil/fil0fil.cc +++ b/storage/innobase/fil/fil0fil.cc @@ -337,7 +337,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); @@ -700,7 +700,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); @@ -1568,38 +1568,23 @@ fil_name_write( fil_space_t *fil_space_t::check_pending_operations(ulint 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) - return nullptr; - - if (being_deleted) { + mysql_mutex_unlock(&fil_system.mutex); + return nullptr; + } + + 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); @@ -1610,8 +1595,24 @@ fil_space_t *fil_space_t::check_pending_operations(ulint id) sql_print_warning("InnoDB: Waiting for tablespace " ULINTPF " 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 6f7cf984390..afa40f3d73a 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -18512,7 +18512,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 @@ -18567,7 +18567,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 07fb5459106..60f2be95ece 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 + (&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 + (&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: @@ -1508,16 +1536,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 + (&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(&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/trx0rseg.h b/storage/innobase/include/trx0rseg.h index d0dd3e016d7..6ad897ca515 100644 --- a/storage/innobase/include/trx0rseg.h +++ b/storage/innobase/include/trx0rseg.h @@ -105,6 +105,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 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(&ref), + needs_purge); +#else + ref.fetch_or(needs_purge ? NEEDS_PURGE : SKIP, std::memory_order_relaxed); +#endif + } + /** Clear a bit in ref */ + template 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(&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. */ @@ -115,21 +152,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(); } /** Note that undo tablespace truncation was completed. */ void clear_skip_allocation() { ut_ad(is_persistent()); +#if defined DBUG_OFF + ref_reset(); +#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(); } /** 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(); } /** @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 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); From d28b118d7b186391be8d091c00d9cf889c863f1a Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Sun, 3 Oct 2021 16:49:54 +0200 Subject: [PATCH 08/12] Fix MSVC warning with bison 3.8.2 --- sql/sql_yacc.yy | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 0f6773c899d..312ea682975 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -69,7 +69,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: */ From d836f8a50d62865024d5facebeacb9c491d57adb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Mon, 4 Oct 2021 11:28:57 +0300 Subject: [PATCH 09/12] Work around MDEV-26754 main.sp test fails for embedded server --- mysql-test/main/sp.result | 3 --- mysql-test/main/sp.test | 3 ++- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/mysql-test/main/sp.result b/mysql-test/main/sp.result index 694c7bcd20e..3f14c9bec3e 100644 --- a/mysql-test/main/sp.result +++ b/mysql-test/main/sp.result @@ -8911,8 +8911,5 @@ SELECT 1 latin1 latin1_swedish_ci latin1_swedish_ci SELECT VARIABLE_VALUE-@local_mem_used FROM INFORMATION_SCHEMA.SESSION_STATUS WHERE VARIABLE_NAME='MEMORY_USED'; VARIABLE_VALUE-@local_mem_used 0 -SELECT VARIABLE_VALUE-@global_mem_used FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME='MEMORY_USED'; -VARIABLE_VALUE-@global_mem_used -0 DROP PROCEDURE sp1; # End of 10.3 tests diff --git a/mysql-test/main/sp.test b/mysql-test/main/sp.test index 50ae78c8431..b066f0d00ed 100644 --- a/mysql-test/main/sp.test +++ b/mysql-test/main/sp.test @@ -10446,6 +10446,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'; -SELECT VARIABLE_VALUE-@global_mem_used FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME='MEMORY_USED'; +# 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 From 32839c4df237bd64807e4e92a1fabe14eb6df783 Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Mon, 4 Oct 2021 22:31:05 +1100 Subject: [PATCH 10/12] MDEV-19867: postfix - syntax spelling ALTER TABLE Fixes: 5c5ea59bf88bc7cd9774f48e847168b47de7b249 --- client/mysqldump.c | 2 +- mysql-test/suite/s3/mysqldump.result | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/client/mysqldump.c b/client/mysqldump.c index 2aec9265921..c546a44cb70 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -4407,7 +4407,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/suite/s3/mysqldump.result b/mysql-test/suite/s3/mysqldump.result index 995cbf5bc63..947fdc20506 100644 --- a/mysql-test/suite/s3/mysqldump.result +++ b/mysql-test/suite/s3/mysqldump.result @@ -24,7 +24,7 @@ CREATE TABLE `t1` ( ) 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; +ALTER TABLE `t1` ENGINE=S3; ##### # mysqldump with --copy-s3-tables=1 XML ### From f3bd2780632288bec8e8462404df0fea356afd7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Mon, 4 Oct 2021 19:28:43 +0300 Subject: [PATCH 11/12] MDEV-22083/MDEV-26758: Fix uninitialized memory in mysql_client_test The test was passing some uninitialized data to libmariadb. Mostly, the MemorySanitizer wrapper of send() detected that some bytes were uninitialized. The test_mdev19838() is for now disabled under MemorySanitizer, to be fixed in MDEV-26761. --- tests/mysql_client_test.c | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index 87e1304387b..3cc96193e4a 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -1,5 +1,5 @@ /* Copyright (c) 2002, 2014, Oracle and/or its affiliates. - Copyright (c) 2008, 2020, MariaDB + Copyright (c) 2008, 2021, 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 @@ -40,6 +40,8 @@ #include #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; @@ -19457,6 +19471,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; @@ -20132,6 +20147,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); @@ -20140,7 +20156,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; @@ -20753,6 +20768,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; @@ -21178,7 +21194,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() @@ -21670,7 +21689,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 }, From df94aa344b8dd219d6afbec502b53505385e495b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 5 Oct 2021 07:13:14 +0300 Subject: [PATCH 12/12] MDEV-26445 followup: Try to work around GCC 4.8.5 ICE on ARMv8 GCC 4.8.5 would crash when compiling trx_purge_truncate_history(). Let us try to avoid that by disabling optimizations for the function. --- storage/innobase/trx/trx0purge.cc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/storage/innobase/trx/trx0purge.cc b/storage/innobase/trx/trx0purge.cc index 4542e391dca..4d84f295c0b 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) mutex_exit(&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!