From 674842bee0a564a2d94e99c4e1319a716aa10aa9 Mon Sep 17 00:00:00 2001 From: Monty Date: Wed, 15 Jun 2022 23:49:09 +0300 Subject: [PATCH 1/5] MDEV-28858 Wrong result with table elimination combined with not_null_range_scan The bug was that build_notnull_conds_for_range_scans() did not take into account the join_tab is not yet sorted with constant tables first. Fixed the bug by testing explicitely if a table is a const table. --- mysql-test/main/range.result | 19 +++++++++++++++++++ mysql-test/main/range.test | 18 ++++++++++++++++++ mysql-test/main/range_mrr_icp.result | 19 +++++++++++++++++++ sql/sql_select.cc | 14 ++++++++------ 4 files changed, 64 insertions(+), 6 deletions(-) diff --git a/mysql-test/main/range.result b/mysql-test/main/range.result index aca500bf038..81098118abd 100644 --- a/mysql-test/main/range.result +++ b/mysql-test/main/range.result @@ -3635,6 +3635,25 @@ SELECT * FROM t1 LEFT JOIN t2 ON a = pk WHERE b >= 0 AND pk IS NULL; a pk b DROP TABLE t1, t2; SET @@optimizer_switch= @save_optimizer_switch; + +# MDEV-28858 Wrong result with table elimination combined with +# not_null_range_scan +# +CREATE TABLE t1 (a INT, b INT) ENGINE=MyISAM; +INSERT INTO t1 VALUES (10,1),(null,2); +CREATE TABLE t2 (pk INT PRIMARY KEY) ENGINE=MyISAM; +INSERT INTO t2 VALUES (1),(2); +SET @save_optimizer_switch= @@optimizer_switch; +SET optimizer_switch= 'not_null_range_scan=on'; +SELECT t1.b FROM t1 LEFT JOIN t2 ON t1.a = t2.pk WHERE t1.a IS NULL ORDER BY t1.b; +b +2 +SET optimizer_switch= 'not_null_range_scan=off'; +SELECT t1.b FROM t1 LEFT JOIN t2 ON t1.a = t2.pk WHERE t1.a IS NULL ORDER BY t1.b; +b +2 +SET @@optimizer_switch=@save_optimizer_switch; +drop table t1,t2; # # End of 10.5 tests # diff --git a/mysql-test/main/range.test b/mysql-test/main/range.test index 6a2e318e732..a785726cb22 100644 --- a/mysql-test/main/range.test +++ b/mysql-test/main/range.test @@ -2492,6 +2492,24 @@ DROP TABLE t1, t2; SET @@optimizer_switch= @save_optimizer_switch; +--echo +--echo # MDEV-28858 Wrong result with table elimination combined with +--echo # not_null_range_scan +--echo # + +CREATE TABLE t1 (a INT, b INT) ENGINE=MyISAM; +INSERT INTO t1 VALUES (10,1),(null,2); +CREATE TABLE t2 (pk INT PRIMARY KEY) ENGINE=MyISAM; +INSERT INTO t2 VALUES (1),(2); + +SET @save_optimizer_switch= @@optimizer_switch; +SET optimizer_switch= 'not_null_range_scan=on'; +SELECT t1.b FROM t1 LEFT JOIN t2 ON t1.a = t2.pk WHERE t1.a IS NULL ORDER BY t1.b; +SET optimizer_switch= 'not_null_range_scan=off'; +SELECT t1.b FROM t1 LEFT JOIN t2 ON t1.a = t2.pk WHERE t1.a IS NULL ORDER BY t1.b; +SET @@optimizer_switch=@save_optimizer_switch; +drop table t1,t2; + --echo # --echo # End of 10.5 tests --echo # diff --git a/mysql-test/main/range_mrr_icp.result b/mysql-test/main/range_mrr_icp.result index eb4daf7fbc8..e68af8545cf 100644 --- a/mysql-test/main/range_mrr_icp.result +++ b/mysql-test/main/range_mrr_icp.result @@ -3624,6 +3624,25 @@ SELECT * FROM t1 LEFT JOIN t2 ON a = pk WHERE b >= 0 AND pk IS NULL; a pk b DROP TABLE t1, t2; SET @@optimizer_switch= @save_optimizer_switch; + +# MDEV-28858 Wrong result with table elimination combined with +# not_null_range_scan +# +CREATE TABLE t1 (a INT, b INT) ENGINE=MyISAM; +INSERT INTO t1 VALUES (10,1),(null,2); +CREATE TABLE t2 (pk INT PRIMARY KEY) ENGINE=MyISAM; +INSERT INTO t2 VALUES (1),(2); +SET @save_optimizer_switch= @@optimizer_switch; +SET optimizer_switch= 'not_null_range_scan=on'; +SELECT t1.b FROM t1 LEFT JOIN t2 ON t1.a = t2.pk WHERE t1.a IS NULL ORDER BY t1.b; +b +2 +SET optimizer_switch= 'not_null_range_scan=off'; +SELECT t1.b FROM t1 LEFT JOIN t2 ON t1.a = t2.pk WHERE t1.a IS NULL ORDER BY t1.b; +b +2 +SET @@optimizer_switch=@save_optimizer_switch; +drop table t1,t2; # # End of 10.5 tests # diff --git a/sql/sql_select.cc b/sql/sql_select.cc index b4e3a547773..cedf640e4ad 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -29573,11 +29573,12 @@ bool build_notnull_conds_for_range_scans(JOIN *join, Item *cond, DBUG_ENTER("build_notnull_conds_for_range_scans"); - for (JOIN_TAB *s= join->join_tab + join->const_tables ; + for (JOIN_TAB *s= join->join_tab; s < join->join_tab + join->table_count ; s++) { /* Clear all needed bitmaps to mark found fields */ - if (allowed & s->table->map) + if ((allowed & s->table->map) && + !(s->table->map && join->const_table_map)) bitmap_clear_all(&s->table->tmp_set); } @@ -29592,17 +29593,18 @@ bool build_notnull_conds_for_range_scans(JOIN *join, Item *cond, For each table t from 'allowed' build a conjunction of NOT NULL predicates constructed for all found fields if they are included in some indexes. If the construction of the conjunction succeeds attach the formula to - t->table->notnull_cond. The condition will be used to look for complementary - range scans. + t->table->notnull_cond. The condition will be used to look for + complementary range scans. */ - for (JOIN_TAB *s= join->join_tab + join->const_tables ; + for (JOIN_TAB *s= join->join_tab ; s < join->join_tab + join->table_count ; s++) { TABLE *tab= s->table; List notnull_list; Item *notnull_cond= 0; - if (!(allowed & tab->map)) + if (!(allowed & tab->map) || + (s->table->map && join->const_table_map)) continue; for (Field** field_ptr= tab->field; *field_ptr; field_ptr++) From 6f4d0659dd262d2f709e508f42572ef01ecfcfc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 22 Jun 2022 10:04:28 +0300 Subject: [PATCH 2/5] MDEV-22388 Corrupted undo log record leads to server crash trx_undo_rec_copy(): Return nullptr if the undo record is corrupted. trx_undo_rec_get_undo_no(): Define inline with the declaration. trx_purge_dummy_rec: Replaced with a -1 pointer. row_undo_rec_get(), UndorecApplier::apply_undo_rec(): Check if trx_undo_rec_copy() returned nullptr. trx_purge_get_next_rec(): Return nullptr upon encountering any corruption, to signal the end of purge. --- storage/innobase/CMakeLists.txt | 1 - storage/innobase/include/trx0purge.h | 4 -- storage/innobase/include/trx0rec.h | 49 +++++++++---------- storage/innobase/include/trx0rec.inl | 73 ---------------------------- storage/innobase/include/trx0undo.h | 2 +- storage/innobase/row/row0purge.cc | 2 +- storage/innobase/row/row0undo.cc | 11 +++-- storage/innobase/trx/trx0purge.cc | 35 ++++++------- storage/innobase/trx/trx0undo.cc | 4 +- 9 files changed, 51 insertions(+), 130 deletions(-) delete mode 100644 storage/innobase/include/trx0rec.inl diff --git a/storage/innobase/CMakeLists.txt b/storage/innobase/CMakeLists.txt index bb10160370a..cc1ec1e302a 100644 --- a/storage/innobase/CMakeLists.txt +++ b/storage/innobase/CMakeLists.txt @@ -236,7 +236,6 @@ SET(INNOBASE_SOURCES include/trx0i_s.h include/trx0purge.h include/trx0rec.h - include/trx0rec.inl include/trx0roll.h include/trx0rseg.h include/trx0sys.h diff --git a/storage/innobase/include/trx0purge.h b/storage/innobase/include/trx0purge.h index ef9111845a6..0896d9c79a1 100644 --- a/storage/innobase/include/trx0purge.h +++ b/storage/innobase/include/trx0purge.h @@ -33,10 +33,6 @@ Created 3/26/1996 Heikki Tuuri #include -/** A dummy undo record used as a return value when we have a whole undo log -which needs no purge */ -extern trx_undo_rec_t trx_purge_dummy_rec; - /** Prepend the history list with an undo log. Remove the undo log segment from the rseg slot if it is too big for reuse. @param[in] trx transaction diff --git a/storage/innobase/include/trx0rec.h b/storage/innobase/include/trx0rec.h index 8143fd419fa..838226601f8 100644 --- a/storage/innobase/include/trx0rec.h +++ b/storage/innobase/include/trx0rec.h @@ -24,8 +24,7 @@ Transaction undo log record Created 3/26/1996 Heikki Tuuri *******************************************************/ -#ifndef trx0rec_h -#define trx0rec_h +#pragma once #include "trx0types.h" #include "row0types.h" @@ -37,29 +36,31 @@ Created 3/26/1996 Heikki Tuuri /***********************************************************************//** Copies the undo record to the heap. -@return own: copy of undo log record */ -UNIV_INLINE -trx_undo_rec_t* -trx_undo_rec_copy( -/*==============*/ - const trx_undo_rec_t* undo_rec, /*!< in: undo log record */ - mem_heap_t* heap); /*!< in: heap where copied */ -/**********************************************************************//** -Reads the undo log record type. -@return record type */ -UNIV_INLINE -ulint -trx_undo_rec_get_type( -/*==================*/ - const trx_undo_rec_t* undo_rec); /*!< in: undo log record */ +@param undo_rec record in an undo log page +@param heap memory heap +@return copy of undo_rec +@retval nullptr if the undo log record is corrupted */ +inline trx_undo_rec_t* trx_undo_rec_copy(const trx_undo_rec_t *undo_rec, + mem_heap_t *heap) +{ + const size_t offset= ut_align_offset(undo_rec, srv_page_size); + const size_t end= mach_read_from_2(undo_rec); + if (end <= offset || end >= srv_page_size - FIL_PAGE_DATA_END) + return nullptr; + const size_t len= end - offset; + trx_undo_rec_t *rec= static_cast + (mem_heap_dup(heap, undo_rec, len)); + mach_write_to_2(rec, len); + return rec; +} + /**********************************************************************//** Reads the undo log record number. @return undo no */ -UNIV_INLINE -undo_no_t -trx_undo_rec_get_undo_no( -/*=====================*/ - const trx_undo_rec_t* undo_rec); /*!< in: undo log record */ +inline undo_no_t trx_undo_rec_get_undo_no(const trx_undo_rec_t *undo_rec) +{ + return mach_u64_read_much_compressed(undo_rec + 3); +} /**********************************************************************//** Returns the start of the undo record data area. */ @@ -345,7 +346,3 @@ inline table_id_t trx_undo_rec_get_table_id(const trx_undo_rec_t *rec) mach_read_next_much_compressed(&rec); return mach_read_next_much_compressed(&rec); } - -#include "trx0rec.inl" - -#endif /* trx0rec_h */ diff --git a/storage/innobase/include/trx0rec.inl b/storage/innobase/include/trx0rec.inl deleted file mode 100644 index 02244d68b6f..00000000000 --- a/storage/innobase/include/trx0rec.inl +++ /dev/null @@ -1,73 +0,0 @@ -/***************************************************************************** - -Copyright (c) 1996, 2014, Oracle and/or its affiliates. All Rights Reserved. - -This program is free software; you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free Software -Foundation; version 2 of the License. - -This program is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along with -this program; if not, write to the Free Software Foundation, Inc., -51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA - -*****************************************************************************/ - -/**************************************************//** -@file include/trx0rec.ic -Transaction undo log record - -Created 3/26/1996 Heikki Tuuri -*******************************************************/ - -/**********************************************************************//** -Reads from an undo log record the record type. -@return record type */ -UNIV_INLINE -ulint -trx_undo_rec_get_type( -/*==================*/ - const trx_undo_rec_t* undo_rec) /*!< in: undo log record */ -{ - return(mach_read_from_1(undo_rec + 2) & (TRX_UNDO_CMPL_INFO_MULT - 1)); -} - -/**********************************************************************//** -Reads the undo log record number. -@return undo no */ -UNIV_INLINE -undo_no_t -trx_undo_rec_get_undo_no( -/*=====================*/ - const trx_undo_rec_t* undo_rec) /*!< in: undo log record */ -{ - const byte* ptr; - - ptr = undo_rec + 3; - - return(mach_u64_read_much_compressed(ptr)); -} - -/***********************************************************************//** -Copies the undo record to the heap. -@return own: copy of undo log record */ -UNIV_INLINE -trx_undo_rec_t* -trx_undo_rec_copy( -/*==============*/ - const trx_undo_rec_t* undo_rec, /*!< in: undo log record */ - mem_heap_t* heap) /*!< in: heap where copied */ -{ - ulint len; - - len = mach_read_from_2(undo_rec) - - ut_align_offset(undo_rec, srv_page_size); - ut_ad(len < srv_page_size); - trx_undo_rec_t* rec = static_cast( - mem_heap_dup(heap, undo_rec, len)); - mach_write_to_2(rec, len); - return rec; -} diff --git a/storage/innobase/include/trx0undo.h b/storage/innobase/include/trx0undo.h index abfa7c61c1f..a8cddd6575d 100644 --- a/storage/innobase/include/trx0undo.h +++ b/storage/innobase/include/trx0undo.h @@ -360,7 +360,7 @@ public: page_id_t get_page_id() const { return page_id; } /** Handle the DML undo log and apply it on online indexes */ - void apply_undo_rec(); + inline void apply_undo_rec(); ~UndorecApplier() { diff --git a/storage/innobase/row/row0purge.cc b/storage/innobase/row/row0purge.cc index 8a81a45ca12..47625b91f35 100644 --- a/storage/innobase/row/row0purge.cc +++ b/storage/innobase/row/row0purge.cc @@ -1114,7 +1114,7 @@ row_purge( trx_undo_rec_t* undo_rec, /*!< in: record to purge */ que_thr_t* thr) /*!< in: query thread */ { - if (undo_rec != &trx_purge_dummy_rec) { + if (undo_rec != reinterpret_cast(-1)) { bool updated_extern; while (row_purge_parse_undo_rec( diff --git a/storage/innobase/row/row0undo.cc b/storage/innobase/row/row0undo.cc index 9c41862e0b4..4d6d779eee6 100644 --- a/storage/innobase/row/row0undo.cc +++ b/storage/innobase/row/row0undo.cc @@ -342,7 +342,11 @@ static bool row_undo_rec_get(undo_node_t* node) node->heap); mtr.commit(); - switch (trx_undo_rec_get_type(node->undo_rec)) { + if (UNIV_UNLIKELY(!node->undo_rec)) { + return false; + } + + switch (node->undo_rec[2] & (TRX_UNDO_CMPL_INFO_MULT - 1)) { case TRX_UNDO_INSERT_METADATA: /* This record type was introduced in MDEV-11369 instant ADD COLUMN, which was implemented after @@ -356,13 +360,12 @@ static bool row_undo_rec_get(undo_node_t* node) case TRX_UNDO_INSERT_REC: case TRX_UNDO_EMPTY: node->roll_ptr |= 1ULL << ROLL_PTR_INSERT_FLAG_POS; - node->state = undo == temp + node->state = is_temp ? UNDO_INSERT_TEMPORARY : UNDO_INSERT_PERSISTENT; break; default: - node->state = undo == temp + node->state = is_temp ? UNDO_UPDATE_TEMPORARY : UNDO_UPDATE_PERSISTENT; - break; } trx->undo_no = node->undo_no = trx_undo_rec_get_undo_no( diff --git a/storage/innobase/trx/trx0purge.cc b/storage/innobase/trx/trx0purge.cc index e37efa733e2..31153c8e966 100644 --- a/storage/innobase/trx/trx0purge.cc +++ b/storage/innobase/trx/trx0purge.cc @@ -55,10 +55,6 @@ ulong srv_max_purge_lag_delay = 0; /** The global data structure coordinating a purge */ purge_sys_t purge_sys; -/** A dummy undo record used as a return value when we have a whole undo log -which needs no purge */ -trx_undo_rec_t trx_purge_dummy_rec; - #ifdef UNIV_DEBUG my_bool srv_purge_view_update_only_debug; #endif /* UNIV_DEBUG */ @@ -1022,7 +1018,9 @@ TRANSACTIONAL_TARGET static void trx_purge_choose_next_log() /***********************************************************************//** Gets the next record to purge and updates the info in the purge system. -@return copy of an undo log record or pointer to the dummy undo log record */ +@return copy of an undo log record +@retval -1 if there is nothing to purge +@retval nullptr on corruption */ static trx_undo_rec_t* trx_purge_get_next_rec( @@ -1048,11 +1046,10 @@ trx_purge_get_next_rec( /* Look for the next undo log and record to purge */ trx_purge_choose_next_log(); - - return(&trx_purge_dummy_rec); + return reinterpret_cast(-1); } - mtr_start(&mtr); + mtr.start(); const buf_block_t* undo_page = buf_page_get_gen(page_id, 0, RW_S_LATCH, nullptr, @@ -1060,7 +1057,7 @@ trx_purge_get_next_rec( if (UNIV_UNLIKELY(!undo_page)) { corrupted: mtr.commit(); - return &trx_purge_dummy_rec; + return nullptr; } const buf_block_t* rec2_page = undo_page; @@ -1105,16 +1102,16 @@ corrupted: trx_undo_rec_t* rec_copy = trx_undo_rec_copy(undo_page->page.frame + offset, heap); - mtr_commit(&mtr); - - return(rec_copy); + mtr.commit(); + return rec_copy; } /********************************************************************//** Fetches the next undo log record from the history list to purge. It must be released with the corresponding release function. -@return copy of an undo log record or pointer to trx_purge_dummy_rec, -if the whole undo log can skipped in purge; NULL if none left */ +@return copy of an undo log record +@retval -1 if the whole undo log can skipped in purge +@retval nullptr if nothing is left, or on corruption */ static MY_ATTRIBUTE((warn_unused_result)) trx_undo_rec_t* trx_purge_fetch_next_rec( @@ -1130,13 +1127,12 @@ trx_purge_fetch_next_rec( if (!purge_sys.next_stored) { DBUG_PRINT("ib_purge", ("no logs left in the history list")); - return(NULL); + return nullptr; } } if (purge_sys.tail.trx_no >= purge_sys.low_limit_no()) { - - return(NULL); + return nullptr; } /* fprintf(stderr, "Thread %lu purging trx %llu undo record %llu\n", @@ -1152,7 +1148,7 @@ trx_purge_fetch_next_rec( /* The following call will advance the stored values of the purge iterator. */ - return(trx_purge_get_next_rec(n_pages_handled, heap)); + return trx_purge_get_next_rec(n_pages_handled, heap); } /** Run a purge batch. @@ -1229,7 +1225,8 @@ trx_purge_attach_undo_recs(ulint n_purge_threads) if (purge_rec.undo_rec == NULL) { break; - } else if (purge_rec.undo_rec == &trx_purge_dummy_rec) { + } else if (purge_rec.undo_rec + == reinterpret_cast(-1)) { continue; } diff --git a/storage/innobase/trx/trx0undo.cc b/storage/innobase/trx/trx0undo.cc index 353d82c89cf..56bef29cc70 100644 --- a/storage/innobase/trx/trx0undo.cc +++ b/storage/innobase/trx/trx0undo.cc @@ -307,8 +307,10 @@ inline void UndorecApplier::assign_rec(const buf_block_t &block, this->undo_rec= trx_undo_rec_copy(block.page.frame + offset, heap); } -void UndorecApplier::apply_undo_rec() +inline void UndorecApplier::apply_undo_rec() { + if (!undo_rec) + return; bool updated_extern= false; undo_no_t undo_no= 0; table_id_t table_id= 0; From 0f0a45b2dc9fe3c54ca9d146db8068b50fc97138 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 22 Jun 2022 17:27:49 +0300 Subject: [PATCH 3/5] MDEV-18976 fixup: encryption.innodb-redo-badkey When attempting to recover a database with an incorrect encryption key, the unencrypted page contents should be expected to differ from what was written before recovery. Let us suppress some more messages. This caused intermittent failures, depending on when the latest log checkpoint was triggered. --- mysql-test/suite/encryption/r/innodb-redo-badkey.result | 2 ++ mysql-test/suite/encryption/t/innodb-redo-badkey.test | 2 ++ 2 files changed, 4 insertions(+) diff --git a/mysql-test/suite/encryption/r/innodb-redo-badkey.result b/mysql-test/suite/encryption/r/innodb-redo-badkey.result index b1c4ae913fa..aa4fcde7a6c 100644 --- a/mysql-test/suite/encryption/r/innodb-redo-badkey.result +++ b/mysql-test/suite/encryption/r/innodb-redo-badkey.result @@ -6,6 +6,8 @@ call mtr.add_suppression("failed to read or decrypt \\[page id: space=[1-9][0-9] call mtr.add_suppression("InnoDB: Unable to decompress .*.test.t[12]\\.ibd\\[page id: space=[1-9][0-9]*, page number=[0-9]+\\]"); call mtr.add_suppression("InnoDB: Database page corruption on disk or a failed read of file '.*test.t[12]\\.ibd'"); call mtr.add_suppression("InnoDB: Failed to read page .* from file '.*'"); +call mtr.add_suppression("InnoDB: OPT_PAGE_CHECKSUM mismatch"); +call mtr.add_suppression("InnoDB: Set innodb_force_recovery=1 to ignore corruption"); call mtr.add_suppression("InnoDB: Plugin initialization aborted"); call mtr.add_suppression("Plugin 'InnoDB' registration as a STORAGE ENGINE failed"); call mtr.add_suppression("\\[ERROR\\] InnoDB: Cannot decrypt \\[page id: space="); diff --git a/mysql-test/suite/encryption/t/innodb-redo-badkey.test b/mysql-test/suite/encryption/t/innodb-redo-badkey.test index 81febb92c5b..5ba4f86ed5c 100644 --- a/mysql-test/suite/encryption/t/innodb-redo-badkey.test +++ b/mysql-test/suite/encryption/t/innodb-redo-badkey.test @@ -15,6 +15,8 @@ call mtr.add_suppression("failed to read or decrypt \\[page id: space=[1-9][0-9] call mtr.add_suppression("InnoDB: Unable to decompress .*.test.t[12]\\.ibd\\[page id: space=[1-9][0-9]*, page number=[0-9]+\\]"); call mtr.add_suppression("InnoDB: Database page corruption on disk or a failed read of file '.*test.t[12]\\.ibd'"); call mtr.add_suppression("InnoDB: Failed to read page .* from file '.*'"); +call mtr.add_suppression("InnoDB: OPT_PAGE_CHECKSUM mismatch"); +call mtr.add_suppression("InnoDB: Set innodb_force_recovery=1 to ignore corruption"); call mtr.add_suppression("InnoDB: Plugin initialization aborted"); call mtr.add_suppression("Plugin 'InnoDB' registration as a STORAGE ENGINE failed"); # for innodb_checksum_algorithm=full_crc32 only From 35f2cdcb99f4f8b39895070fde3f825329106361 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Thu, 23 Jun 2022 05:53:55 +0200 Subject: [PATCH 4/5] MDEV-28920 Rescheduling of innodb_stats_func() missing Fixed tpool timer implementation on POSIX. Prior to this patch, under some specific rare circumstances (concurrency related), timer callback execution might be skipped. --- tpool/tpool_generic.cc | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/tpool/tpool_generic.cc b/tpool/tpool_generic.cc index fb50b050dea..8dbd7c94d30 100644 --- a/tpool/tpool_generic.cc +++ b/tpool/tpool_generic.cc @@ -345,22 +345,23 @@ public: int m_period; std::mutex m_mtx; bool m_on; - std::atomic m_running; + std::atomic m_running; void run() { /* In rare cases, multiple callbacks can be scheduled, - e.g with set_time(0,0) in a loop. - We do not allow parallel execution, as user is not prepared. + at the same time,. e.g with set_time(0,0) in a loop. + We do not allow parallel execution, since it is against the expectations. */ - bool expected = false; - if (!m_running.compare_exchange_strong(expected, true)) + if (m_running.fetch_add(1, std::memory_order_acquire) > 0) return; - - m_callback(m_data); - dbug_execute_after_task_callback(); - m_running = false; + do + { + m_callback(m_data); + dbug_execute_after_task_callback(); + } + while (m_running.fetch_sub(1, std::memory_order_release) != 1); if (m_pool && m_period) { From f2f18e20ebfff2b744a08ba169bcedd1477b228c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Thu, 23 Jun 2022 13:17:20 +0300 Subject: [PATCH 5/5] MDEV-28923 atomic.rename_table occasionally fails fil_name_process(): If the recovery of a tablespace was deferred, do invoke fil_ibd_load() even though the name in recv_spaces is not changing. This allows us to recover from a situation where there are many FILE_RENAME records, renaming a tablespace back and forth, and a FILE_MODIFY record that had been written by fil_names_clear(). Co-developed with: Thirunarayanan Balathandayuthapani --- storage/innobase/log/log0recv.cc | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/storage/innobase/log/log0recv.cc b/storage/innobase/log/log0recv.cc index 377c08b9290..fa3b268cf2f 100644 --- a/storage/innobase/log/log0recv.cc +++ b/storage/innobase/log/log0recv.cc @@ -1194,17 +1194,14 @@ inline size_t recv_sys_t::files_size() } /** Process a file name from a FILE_* record. -@param[in,out] name file name +@param[in] name file name @param[in] len length of the file name @param[in] space_id the tablespace ID @param[in] deleted whether this is a FILE_DELETE record @param[in] lsn lsn of the redo log -@param[in] store whether the redo log has to - stored */ -static -void -fil_name_process(char* name, ulint len, ulint space_id, - bool deleted, lsn_t lsn, store_t *store) +@param[in] store whether the redo log has to be stored */ +static void fil_name_process(const char *name, ulint len, ulint space_id, + bool deleted, lsn_t lsn, const store_t *store) { if (srv_operation == SRV_OPERATION_BACKUP || srv_operation == SRV_OPERATION_BACKUP_NO_DEFER) { @@ -1226,13 +1223,17 @@ fil_name_process(char* name, ulint len, ulint space_id, file_name_t& f = p.first->second; - if (deleted) { - /* Got FILE_DELETE */ - if (auto d = deferred_spaces.find(static_cast( - space_id))) { + if (auto d = deferred_spaces.find(static_cast(space_id))) { + if (deleted) { d->deleted = true; + goto got_deleted; } + goto reload; + } + if (deleted) { +got_deleted: + /* Got FILE_DELETE */ if (!p.second && f.status != file_name_t::DELETED) { f.status = file_name_t::DELETED; if (f.space != NULL) { @@ -1244,6 +1245,7 @@ fil_name_process(char* name, ulint len, ulint space_id, ut_ad(f.space == NULL); } else if (p.second // the first FILE_MODIFY or FILE_RENAME || f.name != fname.name) { +reload: fil_space_t* space; /* Check if the tablespace file exists and contains