diff --git a/mysql-test/main/delete.result b/mysql-test/main/delete.result index 21a3bedcaed62..c4bf335091a10 100644 --- a/mysql-test/main/delete.result +++ b/mysql-test/main/delete.result @@ -610,49 +610,4 @@ c1 c2 c3 2 1 4 2 2 5 drop table t1; -# -# MDEV-32212 DELETE with ORDER BY and semijoin optimization causing crash -# -CREATE TABLE t1 (c1 INT) ENGINE=InnoDB; -CREATE TABLE t2 (c2 INT) ENGINE=InnoDB; -INSERT INTO t1 values (1),(2),(3),(4),(5),(6); -INSERT INTO t2 values (2); -DELETE FROM t1 WHERE c1 IN (select c2 from t2); -select * from t1; -c1 -1 -3 -4 -5 -6 -truncate t1; -truncate t2; -INSERT INTO t1 values (1),(2),(3),(4),(5),(6); -INSERT INTO t2 values (2); -check sj optimization with order-by -analyze DELETE FROM t1 WHERE c1 IN (select c2 from t2) ORDER BY c1; -id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra -1 PRIMARY t1 ALL NULL NULL NULL NULL 6 6.00 100.00 100.00 Using filesort -1 PRIMARY t2 ALL NULL NULL NULL NULL 1 1.00 100.00 16.67 Using where; FirstMatch(t1) -select * from t1; -c1 -1 -3 -4 -5 -6 -truncate t2; -INSERT INTO t2 values (3); -disallows sj optimization -analyze DELETE FROM t1 WHERE c1 IN (select c2 from t2) ORDER BY c1 limit 1; -id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra -1 PRIMARY t1 ALL NULL NULL NULL NULL 5 1.00 100.00 100.00 Using where; Using filesort -2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 1 1.00 100.00 20.00 Using where -select * from t1; -c1 -1 -4 -5 -6 -DROP TABLE t1, t2; End of 11.1 tests diff --git a/mysql-test/main/delete.test b/mysql-test/main/delete.test index 54d0ed7f014a1..583d8223168a8 100644 --- a/mysql-test/main/delete.test +++ b/mysql-test/main/delete.test @@ -667,31 +667,4 @@ select *from t1; drop table t1; ---echo # ---echo # MDEV-32212 DELETE with ORDER BY and semijoin optimization causing crash ---echo # ---source include/have_innodb.inc - -CREATE TABLE t1 (c1 INT) ENGINE=InnoDB; -CREATE TABLE t2 (c2 INT) ENGINE=InnoDB; -INSERT INTO t1 values (1),(2),(3),(4),(5),(6); -INSERT INTO t2 values (2); - -DELETE FROM t1 WHERE c1 IN (select c2 from t2); -select * from t1; -truncate t1; -truncate t2; -INSERT INTO t1 values (1),(2),(3),(4),(5),(6); -INSERT INTO t2 values (2); ---echo check sj optimization with order-by -analyze DELETE FROM t1 WHERE c1 IN (select c2 from t2) ORDER BY c1; -select * from t1; -truncate t2; -INSERT INTO t2 values (3); ---echo disallows sj optimization -analyze DELETE FROM t1 WHERE c1 IN (select c2 from t2) ORDER BY c1 limit 1; -select * from t1; - -DROP TABLE t1, t2; - --echo End of 11.1 tests diff --git a/mysql-test/main/delete_innodb.result b/mysql-test/main/delete_innodb.result index ae9b415152ffb..662c0c558ea8c 100644 --- a/mysql-test/main/delete_innodb.result +++ b/mysql-test/main/delete_innodb.result @@ -24,3 +24,49 @@ SELECT * FROM t1; c1 SET sort_buffer_size=@save_sort_buffer_size; DROP TABLE t1; +# +# MDEV-32212 DELETE with ORDER BY and semijoin optimization causing crash +# +CREATE TABLE t1 (c1 INT) ENGINE=InnoDB; +CREATE TABLE t2 (c2 INT) ENGINE=InnoDB; +INSERT INTO t1 values (1),(2),(3),(4),(5),(6); +INSERT INTO t2 values (2); +DELETE FROM t1 WHERE c1 IN (select c2 from t2); +select * from t1; +c1 +1 +3 +4 +5 +6 +truncate t1; +truncate t2; +INSERT INTO t1 values (1),(2),(3),(4),(5),(6); +INSERT INTO t2 values (2); +check sj optimization with order-by +analyze DELETE FROM t1 WHERE c1 IN (select c2 from t2) ORDER BY c1; +id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 6 6.00 100.00 100.00 Using filesort +1 PRIMARY t2 ALL NULL NULL NULL NULL 1 1.00 100.00 16.67 Using where; FirstMatch(t1) +select * from t1; +c1 +1 +3 +4 +5 +6 +truncate t2; +INSERT INTO t2 values (3); +disallows sj optimization +analyze DELETE FROM t1 WHERE c1 IN (select c2 from t2) ORDER BY c1 limit 1; +id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 5 1.00 100.00 100.00 Using where; Using filesort +2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 1 1.00 100.00 20.00 Using where +select * from t1; +c1 +1 +4 +5 +6 +DROP TABLE t1, t2; +End of 11.1 tests diff --git a/mysql-test/main/delete_innodb.test b/mysql-test/main/delete_innodb.test index c5c5c5d0172fc..e29cf3fa92203 100644 --- a/mysql-test/main/delete_innodb.test +++ b/mysql-test/main/delete_innodb.test @@ -1,6 +1,8 @@ --source include/have_innodb.inc --source include/have_sequence.inc +--source include/innodb_stable_estimates.inc + --echo # Tests for delete with INNODB --echo # @@ -20,3 +22,31 @@ SELECT * FROM t1; SET sort_buffer_size=@save_sort_buffer_size; DROP TABLE t1; + +--echo # +--echo # MDEV-32212 DELETE with ORDER BY and semijoin optimization causing crash +--echo # +--source include/have_innodb.inc + +CREATE TABLE t1 (c1 INT) ENGINE=InnoDB; +CREATE TABLE t2 (c2 INT) ENGINE=InnoDB; +INSERT INTO t1 values (1),(2),(3),(4),(5),(6); +INSERT INTO t2 values (2); + +DELETE FROM t1 WHERE c1 IN (select c2 from t2); +select * from t1; +truncate t1; +truncate t2; +INSERT INTO t1 values (1),(2),(3),(4),(5),(6); +INSERT INTO t2 values (2); +--echo check sj optimization with order-by +analyze DELETE FROM t1 WHERE c1 IN (select c2 from t2) ORDER BY c1; +select * from t1; +truncate t2; +INSERT INTO t2 values (3); +--echo disallows sj optimization +analyze DELETE FROM t1 WHERE c1 IN (select c2 from t2) ORDER BY c1 limit 1; +select * from t1; + +DROP TABLE t1, t2; +--echo End of 11.1 tests diff --git a/mysql-test/main/func_regexp_pcre.result b/mysql-test/main/func_regexp_pcre.result index 9e51ced961ccf..36f2fced1dbe1 100644 --- a/mysql-test/main/func_regexp_pcre.result +++ b/mysql-test/main/func_regexp_pcre.result @@ -895,3 +895,12 @@ REGEXP_INSTR('a_kollision', 'o([lm])\\1') 4 SELECT a FROM (SELECT "aa" a) t WHERE a REGEXP '[0-9]'; a +# +# MDEV-11777 REGEXP_REPLACE converts utf8mb4 supplementary characters to '?' +# +select hex(regexp_replace(cast(x'F09F9881' as char character set 'utf8mb4'), _utf8mb4'a', _utf8mb4'b')) as Text; +Text +F09F9881 +# +# End of 10.6 tests +# diff --git a/mysql-test/main/func_regexp_pcre.test b/mysql-test/main/func_regexp_pcre.test index e6e356f4a8c76..8c2408f576389 100644 --- a/mysql-test/main/func_regexp_pcre.test +++ b/mysql-test/main/func_regexp_pcre.test @@ -470,3 +470,11 @@ SELECT REGEXP_INSTR('a_kollision', 'o([lm])\\1'); # SELECT a FROM (SELECT "aa" a) t WHERE a REGEXP '[0-9]'; --enable_service_connection + +--echo # +--echo # MDEV-11777 REGEXP_REPLACE converts utf8mb4 supplementary characters to '?' +--echo # +select hex(regexp_replace(cast(x'F09F9881' as char character set 'utf8mb4'), _utf8mb4'a', _utf8mb4'b')) as Text; +--echo # +--echo # End of 10.6 tests +--echo # diff --git a/mysql-test/suite/innodb/t/doublewrite_debug.test b/mysql-test/suite/innodb/t/doublewrite_debug.test index aa460cc9d661d..ebae84e2211b1 100644 --- a/mysql-test/suite/innodb/t/doublewrite_debug.test +++ b/mysql-test/suite/innodb/t/doublewrite_debug.test @@ -61,17 +61,6 @@ set global innodb_fil_make_page_dirty_debug = 0; set global innodb_buf_flush_list_now = 1; --let CLEANUP_IF_CHECKPOINT=drop table t1, unexpected_checkpoint; -# Occasionally, a checkpoint would occur on the MSAN builder. -# We do not know the reason, because the failure can only be reproduced if there is -# enough load in that environment. -# Therefore, we allow the test to be skipped when run on MSAN. -# In other environments, we want the test to fail if a checkpoint occurs, -# so that we would catch it if it starts to happen regularly. -if (`select count(*) from information_schema.system_variables where variable_name='have_sanitizer' and global_value like "MSAN%"`) -{ ---let CLEANUP_IF_CHECKPOINT=drop table t1; -} - --source ../include/no_checkpoint_end.inc --echo # Make the 1st page (page_no=0) and 2nd page (page_no=1) diff --git a/mysql-test/suite/perfschema/r/misc_session_status.result b/mysql-test/suite/perfschema/r/misc_session_status.result new file mode 100644 index 0000000000000..3ce472fc61768 --- /dev/null +++ b/mysql-test/suite/perfschema/r/misc_session_status.result @@ -0,0 +1,20 @@ +# +# MDEV-33150 double-locking of LOCK_thd_kill in performance_schema.session_status +# +set @old_innodb_io_capacity=@@global.innodb_io_capacity; +set @old_innodb_io_capacity_max=@@global.innodb_io_capacity_max; +select * from performance_schema.session_status limit 0; +VARIABLE_NAME VARIABLE_VALUE +set max_session_mem_used=32768; +select * from performance_schema.session_status; +ERROR HY000: The MariaDB server is running with the --max-session-mem-used=32768 option so it cannot execute this statement +set global innodb_io_capacity_max=100; +Warnings: +Warning 1210 Setting innodb_io_capacity_max 100 lower than innodb_io_capacity 200. +Warning 1210 Setting innodb_io_capacity to 100 +set max_session_mem_used=default; +set global innodb_io_capacity=@old_innodb_io_capacity; +Warnings: +Warning 1210 Setting innodb_io_capacity to 200 higher than innodb_io_capacity_max 100 +Warning 1210 Setting innodb_max_io_capacity to 400 +set global innodb_io_capacity_max=@old_innodb_io_capacity_max; diff --git a/mysql-test/suite/perfschema/r/rpl_threads.result b/mysql-test/suite/perfschema/r/rpl_threads.result index e9ad54386ab2c..51b49cc88b154 100644 --- a/mysql-test/suite/perfschema/r/rpl_threads.result +++ b/mysql-test/suite/perfschema/r/rpl_threads.result @@ -52,4 +52,10 @@ select NAME, TYPE, PROCESSLIST_COMMAND, PROCESSLIST_STATE from performance_schema.threads where PROCESSLIST_ID = @slave_sql_pid; NAME TYPE PROCESSLIST_COMMAND PROCESSLIST_STATE +# +# MDEV-33031 Assertion failure upon reading from performance schema with binlog enabled +# +select variable_name, variable_value from performance_schema.status_by_thread +where variable_name like '%impossible%'; +variable_name variable_value include/rpl_end.inc diff --git a/mysql-test/suite/perfschema/t/misc_session_status.test b/mysql-test/suite/perfschema/t/misc_session_status.test new file mode 100644 index 0000000000000..ea662ce673855 --- /dev/null +++ b/mysql-test/suite/perfschema/t/misc_session_status.test @@ -0,0 +1,18 @@ +--source include/not_embedded.inc +--source include/have_perfschema.inc +--echo # +--echo # MDEV-33150 double-locking of LOCK_thd_kill in performance_schema.session_status +--echo # +source include/have_innodb.inc; +set @old_innodb_io_capacity=@@global.innodb_io_capacity; +set @old_innodb_io_capacity_max=@@global.innodb_io_capacity_max; +select * from performance_schema.session_status limit 0; # discover the table +set max_session_mem_used=32768; +--error ER_OPTION_PREVENTS_STATEMENT +# this used to crash, when OOM happened under LOCK_thd_kill +select * from performance_schema.session_status; +# this used to cause mutex lock order violation when OOM happened under LOCK_global_system_variables +set global innodb_io_capacity_max=100; +set max_session_mem_used=default; +set global innodb_io_capacity=@old_innodb_io_capacity; +set global innodb_io_capacity_max=@old_innodb_io_capacity_max; diff --git a/mysql-test/suite/perfschema/t/rpl_threads.test b/mysql-test/suite/perfschema/t/rpl_threads.test index a5ca51a94a482..fcecf77572258 100644 --- a/mysql-test/suite/perfschema/t/rpl_threads.test +++ b/mysql-test/suite/perfschema/t/rpl_threads.test @@ -81,5 +81,11 @@ select NAME, TYPE, PROCESSLIST_COMMAND, PROCESSLIST_STATE from performance_schema.threads where PROCESSLIST_ID = @slave_sql_pid; +--echo # +--echo # MDEV-33031 Assertion failure upon reading from performance schema with binlog enabled +--echo # +select variable_name, variable_value from performance_schema.status_by_thread +where variable_name like '%impossible%'; # should not crash + --source include/rpl_end.inc diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 3db3a5ccbcf22..b324a8f5e6a38 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -6090,7 +6090,7 @@ void Regexp_processor_pcre::init(CHARSET_INFO *data_charset, int extra_flags) // Convert text data to utf-8. m_library_charset= data_charset == &my_charset_bin ? - &my_charset_bin : &my_charset_utf8mb3_general_ci; + &my_charset_bin : &my_charset_utf8mb4_general_ci; m_conversion_is_needed= (data_charset != &my_charset_bin) && !my_charset_same(data_charset, m_library_charset); diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 8037b908b10c9..13922b9ef77ba 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -3055,7 +3055,7 @@ class Regexp_processor_pcre m_pcre(NULL), m_pcre_match_data(NULL), m_conversion_is_needed(true), m_is_const(0), m_library_flags(0), - m_library_charset(&my_charset_utf8mb3_general_ci) + m_library_charset(&my_charset_utf8mb4_general_ci) {} int default_regex_flags(); void init(CHARSET_INFO *data_charset, int extra_flags); diff --git a/sql/log.cc b/sql/log.cc index 381bd378da282..7e0fa078d71fb 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -11886,14 +11886,21 @@ set_binlog_snapshot_file(const char *src) void TC_LOG_BINLOG::set_status_variables(THD *thd) { - binlog_cache_mngr *cache_mngr; + bool have_snapshot= false; if (thd && opt_bin_log) - cache_mngr= thd->binlog_get_cache_mngr(); - else - cache_mngr= 0; + { + mysql_mutex_lock(&thd->LOCK_thd_data); + auto cache_mngr= thd->binlog_get_cache_mngr(); + have_snapshot= cache_mngr && cache_mngr->last_commit_pos_file[0]; + if (have_snapshot) + { + set_binlog_snapshot_file(cache_mngr->last_commit_pos_file); + binlog_snapshot_position= cache_mngr->last_commit_pos_offset; + } + mysql_mutex_unlock(&thd->LOCK_thd_data); + } - bool have_snapshot= (cache_mngr && cache_mngr->last_commit_pos_file[0] != 0); mysql_mutex_lock(&LOCK_commit_ordered); binlog_status_var_num_commits= this->num_commits; binlog_status_var_num_group_commits= this->num_group_commits; @@ -11908,12 +11915,6 @@ TC_LOG_BINLOG::set_status_variables(THD *thd) binlog_status_group_commit_trigger_timeout= this->group_commit_trigger_timeout; binlog_status_group_commit_trigger_lock_wait= this->group_commit_trigger_lock_wait; mysql_mutex_unlock(&LOCK_prepare_ordered); - - if (have_snapshot) - { - set_binlog_snapshot_file(cache_mngr->last_commit_pos_file); - binlog_snapshot_position= cache_mngr->last_commit_pos_offset; - } } diff --git a/storage/innobase/buf/buf0flu.cc b/storage/innobase/buf/buf0flu.cc index e7f44b2e596ab..ebcf430d532a7 100644 --- a/storage/innobase/buf/buf0flu.cc +++ b/storage/innobase/buf/buf0flu.cc @@ -754,16 +754,20 @@ bool buf_page_t::flush(bool evict, fil_space_t *space) ut_ad(space->referenced()); const auto s= state(); - ut_a(s >= FREED); + + const lsn_t lsn= + mach_read_from_8(my_assume_aligned<8> + (FIL_PAGE_LSN + (zip.data ? zip.data : frame))); + ut_ad(lsn + ? lsn >= oldest_modification() || oldest_modification() == 2 + : space->purpose != FIL_TYPE_TABLESPACE); if (s < UNFIXED) { + ut_a(s >= FREED); if (UNIV_LIKELY(space->purpose == FIL_TYPE_TABLESPACE)) { - const lsn_t lsn= - mach_read_from_8(my_assume_aligned<8> - (FIL_PAGE_LSN + (zip.data ? zip.data : frame))); - ut_ad(lsn >= oldest_modification()); + freed: if (lsn > log_sys.get_flushed_lsn()) { mysql_mutex_unlock(&buf_pool.mutex); @@ -775,6 +779,12 @@ bool buf_page_t::flush(bool evict, fil_space_t *space) return false; } + if (UNIV_UNLIKELY(lsn < space->get_create_lsn())) + { + ut_ad(space->purpose == FIL_TYPE_TABLESPACE); + goto freed; + } + ut_d(const auto f=) zip.fix.fetch_add(WRITE_FIX - UNFIXED); ut_ad(f >= UNFIXED); ut_ad(f < READ_FIX); @@ -869,15 +879,9 @@ bool buf_page_t::flush(bool evict, fil_space_t *space) if ((s & LRU_MASK) == REINIT || !space->use_doublewrite()) { - if (UNIV_LIKELY(space->purpose == FIL_TYPE_TABLESPACE)) - { - const lsn_t lsn= - mach_read_from_8(my_assume_aligned<8>(FIL_PAGE_LSN + - (write_frame ? write_frame - : frame))); - ut_ad(lsn >= oldest_modification()); + if (UNIV_LIKELY(space->purpose == FIL_TYPE_TABLESPACE) && + lsn > log_sys.get_flushed_lsn()) log_write_up_to(lsn, true); - } space->io(IORequest{type, this, slot}, physical_offset(), size, write_frame, this); } @@ -1057,11 +1061,25 @@ static ulint buf_flush_try_neighbors(fil_space_t *space, bool contiguous, bool evict, ulint n_flushed, ulint n_to_flush) { - mysql_mutex_unlock(&buf_pool.mutex); - ut_ad(space->id == page_id.space()); ut_ad(bpage->id() == page_id); + { + const lsn_t lsn= + mach_read_from_8(my_assume_aligned<8> + (FIL_PAGE_LSN + + (bpage->zip.data ? bpage->zip.data : bpage->frame))); + ut_ad(lsn >= bpage->oldest_modification()); + if (UNIV_UNLIKELY(lsn < space->get_create_lsn())) + { + ut_a(!bpage->flush(evict, space)); + mysql_mutex_unlock(&buf_pool.mutex); + return 0; + } + } + + mysql_mutex_unlock(&buf_pool.mutex); + ulint count= 0; page_id_t id= page_id; page_id_t high= buf_flush_check_neighbors(*space, id, contiguous, evict); @@ -2434,9 +2452,9 @@ static void buf_flush_page_cleaner() do { - DBUG_EXECUTE_IF("ib_log_checkpoint_avoid", continue;); - DBUG_EXECUTE_IF("ib_log_checkpoint_avoid_hard", continue;); - + IF_DBUG(if (_db_keyword_(nullptr, "ib_log_checkpoint_avoid", 1) || + _db_keyword_(nullptr, "ib_log_checkpoint_avoid_hard", 1)) + continue,); if (!recv_recovery_is_on() && !srv_startup_is_before_trx_rollback_phase && srv_operation <= SRV_OPERATION_EXPORT_RESTORED) diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc index 0f4bf115d043f..842651360fe80 100644 --- a/storage/innobase/fil/fil0fil.cc +++ b/storage/innobase/fil/fil0fil.cc @@ -564,7 +564,7 @@ fil_space_extend_must_retry( ut_ad(UT_LIST_GET_LAST(space->chain) == node); ut_ad(size >= FIL_IBD_FILE_INITIAL_SIZE); ut_ad(node->space == space); - ut_ad(space->referenced() || space->is_being_truncated); + ut_ad(space->referenced()); *success = space->size >= size; @@ -653,8 +653,7 @@ fil_space_extend_must_retry( default: ut_ad(space->purpose == FIL_TYPE_TABLESPACE || space->purpose == FIL_TYPE_IMPORT); - if (space->purpose == FIL_TYPE_TABLESPACE - && !space->is_being_truncated) { + if (space->purpose == FIL_TYPE_TABLESPACE) { goto do_flush; } break; @@ -754,12 +753,10 @@ bool fil_space_extend(fil_space_t *space, uint32_t size) bool success= false; const bool acquired= space->acquire(); mysql_mutex_lock(&fil_system.mutex); - if (acquired || space->is_being_truncated) - { + if (acquired) while (fil_space_extend_must_retry(space, UT_LIST_GET_LAST(space->chain), size, &success)) mysql_mutex_lock(&fil_system.mutex); - } mysql_mutex_unlock(&fil_system.mutex); if (acquired) space->release(); @@ -3135,11 +3132,9 @@ fil_space_validate_for_mtr_commit( ut_ad(!is_predefined_tablespace(space->id)); /* We are serving mtr_commit(). While there is an active - mini-transaction, we should have !space->stop_new_ops. This is + mini-transaction, we should have !space->is_stopping(). This is guaranteed by meta-data locks or transactional locks. */ - ut_ad(!space->is_stopping() - || space->is_being_truncated /* fil_truncate_prepare() */ - || space->referenced()); + ut_ad(!space->is_stopping() || space->referenced()); } #endif /* UNIV_DEBUG */ diff --git a/storage/innobase/fsp/fsp0fsp.cc b/storage/innobase/fsp/fsp0fsp.cc index 3865390f49ab2..f1eef838739c2 100644 --- a/storage/innobase/fsp/fsp0fsp.cc +++ b/storage/innobase/fsp/fsp0fsp.cc @@ -41,8 +41,6 @@ Created 11/29/1995 Heikki Tuuri #include "fsp0types.h" #include "log.h" -typedef uint32_t page_no_t; - /** Returns the first extent descriptor for a segment. We think of the extent lists of the segment catenated in the order FSEG_FULL -> FSEG_NOT_FULL -> FSEG_FREE. @@ -331,7 +329,7 @@ xdes_t* xdes_get_descriptor_with_space_hdr( buf_block_t* header, const fil_space_t* space, - page_no_t offset, + uint32_t offset, mtr_t* mtr, dberr_t* err = nullptr, buf_block_t** desc_block = nullptr, @@ -395,7 +393,7 @@ try to add new extents to the space free list @param[out] err error code @param[out] xdes extent descriptor page @return the extent descriptor */ -static xdes_t *xdes_get_descriptor(const fil_space_t *space, page_no_t offset, +static xdes_t *xdes_get_descriptor(const fil_space_t *space, uint32_t offset, mtr_t *mtr, dberr_t *err= nullptr, buf_block_t **xdes= nullptr) { @@ -841,8 +839,7 @@ fsp_fill_free_list( if (i) { buf_block_t *f= buf_LRU_get_free_block(have_no_mutex); - buf_block_t *block= buf_page_create(space, static_cast(i), - zip_size, mtr, f); + buf_block_t *block= buf_page_create(space, i, zip_size, mtr, f); if (UNIV_UNLIKELY(block != f)) buf_pool.free_block(f); fsp_init_file_page(space, block, mtr); @@ -854,8 +851,7 @@ fsp_fill_free_list( { buf_block_t *f= buf_LRU_get_free_block(have_no_mutex); buf_block_t *block= - buf_page_create(space, static_cast(i + 1), - zip_size, mtr, f); + buf_page_create(space, i + 1, zip_size, mtr, f); if (UNIV_UNLIKELY(block != f)) buf_pool.free_block(f); /* The zero-initialization will reset the change buffer bitmap bits @@ -1033,80 +1029,13 @@ fsp_alloc_from_free_frag(buf_block_t *header, buf_block_t *xdes, xdes_t *descr, @param[in] offset page number of the allocated page @param[in,out] mtr mini-transaction @return block, initialized */ -static -buf_block_t* -fsp_page_create(fil_space_t *space, page_no_t offset, mtr_t *mtr) +static buf_block_t* fsp_page_create(fil_space_t *space, uint32_t offset, + mtr_t *mtr) { - buf_block_t *block; - - if (UNIV_UNLIKELY(space->is_being_truncated)) - { - const page_id_t page_id{space->id, offset}; - uint32_t state; - block= mtr->get_already_latched(page_id, MTR_MEMO_PAGE_X_FIX); - if (block) - goto have_latch; - else - { - buf_pool_t::hash_chain &chain= - buf_pool.page_hash.cell_get(page_id.fold()); - mysql_mutex_lock(&buf_pool.mutex); - block= reinterpret_cast - (buf_pool.page_hash.get(page_id, chain)); - if (!block) - { - mysql_mutex_unlock(&buf_pool.mutex); - goto create; - } - } - - if (!mtr->have_x_latch(*block)) - { - const bool got{block->page.lock.x_lock_try()}; - mysql_mutex_unlock(&buf_pool.mutex); - if (!got) - { - block->page.lock.x_lock(); - const page_id_t id{block->page.id()}; - if (UNIV_UNLIKELY(id != page_id)) - { - ut_ad(id.is_corrupted()); - block->page.lock.x_unlock(); - goto create; - } - } - state= block->page.fix() + 1; - mtr->memo_push(block, MTR_MEMO_PAGE_X_FIX); - } - else - { - mysql_mutex_unlock(&buf_pool.mutex); - have_latch: - state= block->page.state(); - } - - ut_ad(state > buf_page_t::FREED); - ut_ad(state < buf_page_t::READ_FIX); - ut_ad(block->page.lock.x_lock_count() == 1); - ut_ad(block->page.frame); -#ifdef BTR_CUR_HASH_ADAPT - ut_ad(!block->index); -#endif - - block->page.set_reinit(state < buf_page_t::UNFIXED - ? buf_page_t::FREED - : (state & buf_page_t::LRU_MASK)); - } - else - { - create: - buf_block_t *free_block= buf_LRU_get_free_block(have_no_mutex); - block= buf_page_create(space, static_cast(offset), - space->zip_size(), mtr, free_block); - if (UNIV_UNLIKELY(block != free_block)) - buf_pool.free_block(free_block); - } - + buf_block_t *free_block= buf_LRU_get_free_block(have_no_mutex), + *block= buf_page_create(space, offset, space->zip_size(), mtr, free_block); + if (UNIV_UNLIKELY(block != free_block)) + buf_pool.free_block(free_block); fsp_init_file_page(space, block, mtr); return block; } @@ -1224,7 +1153,7 @@ MY_ATTRIBUTE((nonnull, warn_unused_result)) @param[in] offset page number in the extent @param[in,out] mtr mini-transaction @return error code */ -static dberr_t fsp_free_extent(fil_space_t* space, page_no_t offset, +static dberr_t fsp_free_extent(fil_space_t* space, uint32_t offset, mtr_t* mtr) { ut_ad(space->is_owner()); @@ -1261,7 +1190,7 @@ The page is marked as free and clean. @param[in] offset page number @param[in,out] mtr mini-transaction @return error code */ -static dberr_t fsp_free_page(fil_space_t *space, page_no_t offset, mtr_t *mtr) +static dberr_t fsp_free_page(fil_space_t *space, uint32_t offset, mtr_t *mtr) { xdes_t* descr; ulint frag_n_used; @@ -1801,7 +1730,6 @@ fseg_create(fil_space_t *space, ulint byte_offset, mtr_t *mtr, dberr_t *err, ut_d(const auto x = block->page.lock.x_lock_count()); ut_ad(x || block->page.lock.not_recursive()); - ut_ad(x == 1 || space->is_being_truncated); ut_ad(x <= 2); ut_ad(!fil_page_get_type(block->page.frame)); mtr->write<1>(*block, FIL_PAGE_TYPE + 1 + block->page.frame, @@ -2538,7 +2466,7 @@ fseg_free_page_low( fseg_inode_t* seg_inode, buf_block_t* iblock, fil_space_t* space, - page_no_t offset, + uint32_t offset, mtr_t* mtr #ifdef BTR_CUR_HASH_ADAPT ,bool ahi=false @@ -2904,7 +2832,7 @@ fseg_free_step( return true; } - page_no_t page_no = fseg_get_nth_frag_page_no(inode, n); + uint32_t page_no = fseg_get_nth_frag_page_no(inode, n); if (fseg_free_page_low(inode, iblock, space, page_no, mtr #ifdef BTR_CUR_HASH_ADAPT @@ -3699,28 +3627,13 @@ void fsp_system_tablespace_truncate() return; } } - mysql_mutex_lock(&fil_system.mutex); - space->size= last_used_extent; if (space->free_limit > last_used_extent) - space->free_limit= space->size; - - space->free_len= flst_get_len( - FSP_HEADER_OFFSET + FSP_FREE+ header->page.frame); - - /* Last file new size after truncation */ - uint32_t new_last_file_size= - last_used_extent - - (fixed_size - srv_sys_space.m_files.at( - srv_sys_space.m_files.size() - 1).param_size()); - - space->size_in_header= space->size; - space->is_being_truncated= true; - space->set_stopping(); - space->chain.end->size= new_last_file_size; - srv_sys_space.set_last_file_size(new_last_file_size); - mysql_mutex_unlock(&fil_system.mutex); - mtr.commit_shrink(*space); + space->free_limit= last_used_extent; + space->free_len= flst_get_len(FSP_HEADER_OFFSET + FSP_FREE + + header->page.frame); + + mtr.commit_shrink(*space, last_used_extent); sql_print_information("InnoDB: System tablespace truncated successfully"); srv_use_doublewrite_buf= old_dblwr_buf; } diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 44fe62a4874a0..4468a7e096c59 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -18184,7 +18184,10 @@ buf_flush_list_now_set(THD*, st_mysql_sys_var*, void*, const void* save) if (s) buf_flush_sync(); else + { while (buf_flush_list_space(fil_system.sys_space, nullptr)); + os_aio_wait_until_no_pending_writes(true); + } mysql_mutex_lock(&LOCK_global_system_variables); } @@ -19263,8 +19266,10 @@ static MYSQL_SYSVAR_ULONGLONG(max_undo_log_size, srv_max_undo_log_size, 10 << 20, 10 << 20, 1ULL << (32 + UNIV_PAGE_SIZE_SHIFT_MAX), 0); +static ulong innodb_purge_rseg_truncate_frequency; + static MYSQL_SYSVAR_ULONG(purge_rseg_truncate_frequency, - srv_purge_rseg_truncate_frequency, + innodb_purge_rseg_truncate_frequency, PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_DEPRECATED, "Deprecated parameter with no effect", NULL, NULL, 128, 1, 128, 0); diff --git a/storage/innobase/include/fil0fil.h b/storage/innobase/include/fil0fil.h index 5328b8359f9f6..128be0057b02b 100644 --- a/storage/innobase/include/fil0fil.h +++ b/storage/innobase/include/fil0fil.h @@ -330,8 +330,6 @@ struct fil_space_t final lsn_t max_lsn; /** tablespace identifier */ uint32_t id; - /** whether undo tablespace truncation is in progress */ - bool is_being_truncated; fil_type_t purpose;/*!< purpose */ UT_LIST_BASE_NODE_T(fil_node_t) chain; /*!< base node for the file chain */ @@ -411,6 +409,8 @@ struct fil_space_t final /** LSN of freeing last page; protected by freed_range_mutex */ lsn_t last_freed_lsn; + /** LSN of undo tablespace creation or 0; protected by latch */ + lsn_t create_lsn; public: /** @return whether doublewrite buffering is needed */ inline bool use_doublewrite() const; @@ -418,6 +418,12 @@ struct fil_space_t final /** @return whether a page has been freed */ inline bool is_freed(uint32_t page); + /** Set create_lsn. */ + inline void set_create_lsn(lsn_t lsn); + + /** @return the latest tablespace rebuild LSN, or 0 */ + lsn_t get_create_lsn() const { return create_lsn; } + /** Apply freed_ranges to the file. @param writable whether the file is writable @return number of pages written or hole-punched */ @@ -495,9 +501,6 @@ struct fil_space_t final /** 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(); - /** Drop the tablespace and wait for any pending operations to cease @param id tablespace identifier @param detached_handle pointer to file to be closed later, or nullptr @@ -1542,14 +1545,6 @@ inline void fil_space_t::set_stopping() #endif } -inline void fil_space_t::clear_stopping() -{ - mysql_mutex_assert_owner(&fil_system.mutex); - static_assert(STOPPING_WRITES == 1U << 30, "compatibility"); - ut_d(auto n=) n_pending.fetch_sub(STOPPING_WRITES, std::memory_order_relaxed); - ut_ad((n & STOPPING) == STOPPING_WRITES); -} - /** Flush pending writes from the file system cache to the file. */ template inline void fil_space_t::flush() { diff --git a/storage/innobase/include/mtr0mtr.h b/storage/innobase/include/mtr0mtr.h index dc53abc3eb603..fe0ad3a7128f1 100644 --- a/storage/innobase/include/mtr0mtr.h +++ b/storage/innobase/include/mtr0mtr.h @@ -89,8 +89,9 @@ struct mtr_t { { auto s= m_memo.size(); rollback_to_savepoint(s - 1, s); } /** Commit a mini-transaction that is shrinking a tablespace. - @param space tablespace that is being shrunk */ - ATTRIBUTE_COLD void commit_shrink(fil_space_t &space); + @param space tablespace that is being shrunk + @param size new size in pages */ + ATTRIBUTE_COLD void commit_shrink(fil_space_t &space, uint32_t size); /** Commit a mini-transaction that is deleting or renaming a file. @param space tablespace that is being renamed or deleted diff --git a/storage/innobase/include/srv0srv.h b/storage/innobase/include/srv0srv.h index 9734778bff63e..4443ac3354435 100644 --- a/storage/innobase/include/srv0srv.h +++ b/storage/innobase/include/srv0srv.h @@ -210,14 +210,11 @@ extern unsigned long long srv_max_undo_log_size; extern uint srv_n_fil_crypt_threads; extern uint srv_n_fil_crypt_threads_started; -/** Rate at which UNDO records should be purged. */ -extern ulong srv_purge_rseg_truncate_frequency; - /** Enable or Disable Truncate of UNDO tablespace. */ extern my_bool srv_undo_log_truncate; /** Default size of UNDO tablespace (10MiB for innodb_page_size=16k) */ -constexpr ulint SRV_UNDO_TABLESPACE_SIZE_IN_PAGES= (10U << 20) / +constexpr uint32_t SRV_UNDO_TABLESPACE_SIZE_IN_PAGES= (10U << 20) / UNIV_PAGE_SIZE_DEF; extern char* srv_log_group_home_dir; diff --git a/storage/innobase/mtr/mtr0mtr.cc b/storage/innobase/mtr/mtr0mtr.cc index b3a1adb76b07d..0f0a28a54c13e 100644 --- a/storage/innobase/mtr/mtr0mtr.cc +++ b/storage/innobase/mtr/mtr0mtr.cc @@ -508,9 +508,20 @@ void mtr_t::rollback_to_savepoint(ulint begin, ulint end) m_memo.erase(m_memo.begin() + begin, m_memo.begin() + end); } +/** Set create_lsn. */ +inline void fil_space_t::set_create_lsn(lsn_t lsn) +{ +#ifndef SUX_LOCK_GENERIC + /* Concurrent log_checkpoint_low() must be impossible. */ + ut_ad(latch.is_write_locked()); +#endif + create_lsn= lsn; +} + /** Commit a mini-transaction that is shrinking a tablespace. -@param space tablespace that is being shrunk */ -void mtr_t::commit_shrink(fil_space_t &space) +@param space tablespace that is being shrunk +@param size new size in pages */ +void mtr_t::commit_shrink(fil_space_t &space, uint32_t size) { ut_ad(is_active()); ut_ad(!high_level_read_only); @@ -528,19 +539,34 @@ void mtr_t::commit_shrink(fil_space_t &space) const lsn_t start_lsn= do_write().first; ut_d(m_log.erase()); + fil_node_t *file= UT_LIST_GET_LAST(space.chain); + mysql_mutex_lock(&fil_system.mutex); + ut_ad(file->is_open()); + ut_ad(space.size >= size); + ut_ad(file->size >= space.size - size); + file->size-= space.size - size; + space.size= space.size_in_header= size; + + if (space.id == TRX_SYS_SPACE) + srv_sys_space.set_last_file_size(file->size); + + space.set_create_lsn(m_commit_lsn); + mysql_mutex_unlock(&fil_system.mutex); + + space.clear_freed_ranges(); + /* Durably write the reduced FSP_SIZE before truncating the data file. */ log_write_and_flush(); #ifndef SUX_LOCK_GENERIC ut_ad(log_sys.latch.is_write_locked()); #endif - os_file_truncate( - space.chain.end->name, space.chain.end->handle, - os_offset_t{space.chain.end->size} << srv_page_size_shift, true); + os_file_truncate(file->name, file->handle, + os_offset_t{file->size} << srv_page_size_shift, true); space.clear_freed_ranges(); - const page_id_t high{space.id, space.size}; + const page_id_t high{space.id, size}; size_t modified= 0; auto it= m_memo.rbegin(); mysql_mutex_lock(&buf_pool.flush_list_mutex); @@ -601,13 +627,6 @@ void mtr_t::commit_shrink(fil_space_t &space) log_sys.latch.wr_unlock(); m_latch_ex= false; - mysql_mutex_lock(&fil_system.mutex); - ut_ad(space.is_being_truncated); - ut_ad(space.is_stopping_writes()); - space.clear_stopping(); - space.is_being_truncated= false; - mysql_mutex_unlock(&fil_system.mutex); - release(); release_resources(); } @@ -998,10 +1017,9 @@ std::pair mtr_t::do_write() #ifndef DBUG_OFF do { - if (m_log_mode != MTR_LOG_ALL) + if (m_log_mode != MTR_LOG_ALL || + _db_keyword_(nullptr, "skip_page_checksum", 1)) continue; - DBUG_EXECUTE_IF("skip_page_checksum", continue;); - for (const mtr_memo_slot_t& slot : m_memo) if (slot.type & MTR_MEMO_MODIFY) { diff --git a/storage/innobase/srv/srv0srv.cc b/storage/innobase/srv/srv0srv.cc index 32e9f9e923ffe..d1ea843e521cf 100644 --- a/storage/innobase/srv/srv0srv.cc +++ b/storage/innobase/srv/srv0srv.cc @@ -104,9 +104,6 @@ segment). It is quite possible that some of the tablespaces doesn't host any of the rollback-segment based on configuration used. */ uint32_t srv_undo_tablespaces_active; -/** Rate at which UNDO records should be purged. */ -ulong srv_purge_rseg_truncate_frequency; - /** Enable or Disable Truncate of UNDO tablespace. Note: If enabled then UNDO tablespace will be selected for truncate. While Server waits for undo-tablespace to truncate if user disables diff --git a/storage/innobase/trx/trx0purge.cc b/storage/innobase/trx/trx0purge.cc index ddc4d400a18c2..add4db962d54b 100644 --- a/storage/innobase/trx/trx0purge.cc +++ b/storage/innobase/trx/trx0purge.cc @@ -41,6 +41,7 @@ Created 3/26/1996 Heikki Tuuri #include "dict0load.h" #include #include +#include "log.h" /** Maximum allowable purge history length. <=0 means 'infinite'. */ ulong srv_max_purge_lag = 0; @@ -376,8 +377,8 @@ static void trx_purge_free_segment(buf_block_t *rseg_hdr, buf_block_t *block, ut_ad(rseg_hdr->page.id() == rseg_hdr_id); block->page.lock.x_lock(); ut_ad(block->page.id() == id); - mtr.memo_push(rseg_hdr, MTR_MEMO_PAGE_X_MODIFY); - mtr.memo_push(block, MTR_MEMO_PAGE_X_MODIFY); + mtr.memo_push(rseg_hdr, MTR_MEMO_PAGE_X_FIX); + mtr.memo_push(block, MTR_MEMO_PAGE_X_FIX); } while (!fseg_free_step(TRX_UNDO_SEG_HDR + TRX_UNDO_FSEG_HEADER + @@ -500,7 +501,7 @@ trx_purge_truncate_rseg_history(trx_rseg_t &rseg, mtr.start(); rseg_hdr->page.lock.x_lock(); ut_ad(rseg_hdr->page.id() == rseg.page_id()); - mtr.memo_push(rseg_hdr, MTR_MEMO_PAGE_X_MODIFY); + mtr.memo_push(rseg_hdr, MTR_MEMO_PAGE_X_FIX); goto loop; } @@ -667,16 +668,9 @@ TRANSACTIONAL_TARGET void trx_purge_truncate_history() rseg.latch.rd_unlock(); } - ib::info() << "Truncating " << file->name; + sql_print_information("InnoDB: Truncating %s", file->name); trx_purge_cleanse_purge_queue(space); - log_free_check(); - - mtr_t mtr; - mtr.start(); - mtr.x_lock_space(&space); - const auto space_id= space.id; - /* Lock all modified pages of the tablespace. During truncation, we do not want any writes to the file. @@ -686,86 +680,12 @@ TRANSACTIONAL_TARGET void trx_purge_truncate_history() discarding the to-be-trimmed pages without flushing would break crash recovery. */ - rescan: if (UNIV_UNLIKELY(srv_shutdown_state != SRV_SHUTDOWN_NONE) && srv_fast_shutdown) - { - fast_shutdown: - mtr.commit(); return; - } - - mysql_mutex_lock(&buf_pool.flush_list_mutex); - for (buf_page_t *bpage= UT_LIST_GET_LAST(buf_pool.flush_list); bpage; ) - { - ut_ad(bpage->oldest_modification()); - ut_ad(bpage->in_file()); - - buf_page_t *prev= UT_LIST_GET_PREV(list, bpage); - - if (bpage->oldest_modification() > 2 && bpage->id().space() == space_id) - { - ut_ad(bpage->frame); - bpage->fix(); - { - /* Try to acquire an exclusive latch while the cache line is - fresh after fix(). */ - const bool got_lock{bpage->lock.x_lock_try()}; - buf_pool.flush_hp.set(prev); - mysql_mutex_unlock(&buf_pool.flush_list_mutex); - if (!got_lock) - bpage->lock.x_lock(); - } - -#ifdef BTR_CUR_HASH_ADAPT - /* There is no AHI on undo tablespaces. */ - ut_ad(!reinterpret_cast(bpage)->index); -#endif - ut_ad(!bpage->is_io_fixed()); - ut_ad(bpage->id().space() == space_id); - - if (bpage->oldest_modification() > 2 && - !mtr.have_x_latch(*reinterpret_cast(bpage))) - mtr.memo_push(reinterpret_cast(bpage), - MTR_MEMO_PAGE_X_FIX); - else - { - bpage->unfix(); - bpage->lock.x_unlock(); - } - - mysql_mutex_lock(&buf_pool.flush_list_mutex); - - if (prev != buf_pool.flush_hp.get()) - { - /* The functions buf_pool_t::release_freed_page() or - buf_do_flush_list_batch() may be right now holding - buf_pool.mutex and waiting to acquire - buf_pool.flush_list_mutex. Ensure that they can proceed, - to avoid extreme waits. */ - mysql_mutex_unlock(&buf_pool.flush_list_mutex); - mysql_mutex_lock(&buf_pool.mutex); - mysql_mutex_unlock(&buf_pool.mutex); - goto rescan; - } - } - - bpage= prev; - } - - mysql_mutex_unlock(&buf_pool.flush_list_mutex); - - if (UNIV_UNLIKELY(srv_shutdown_state != SRV_SHUTDOWN_NONE) && - srv_fast_shutdown) - goto fast_shutdown; - - /* Re-initialize tablespace, in a single mini-transaction. */ - const ulint size= SRV_UNDO_TABLESPACE_SIZE_IN_PAGES; /* Adjust the tablespace metadata. */ mysql_mutex_lock(&fil_system.mutex); - space.set_stopping(); - space.is_being_truncated= true; if (space.crypt_data) { space.reacquire(); @@ -776,26 +696,20 @@ TRANSACTIONAL_TARGET void trx_purge_truncate_history() else mysql_mutex_unlock(&fil_system.mutex); - for (auto i= 6000; space.referenced(); - std::this_thread::sleep_for(std::chrono::milliseconds(10))) - { - if (!--i) - { - mtr.commit(); - ib::error() << "Failed to freeze UNDO tablespace " << file->name; - return; - } - } + /* Re-initialize tablespace, in a single mini-transaction. */ + const uint32_t size= SRV_UNDO_TABLESPACE_SIZE_IN_PAGES; + log_free_check(); + + mtr_t mtr; + mtr.start(); + mtr.x_lock_space(&space); /* Associate the undo tablespace with mtr. During mtr::commit_shrink(), InnoDB can use the undo tablespace object to clear all freed ranges */ mtr.set_named_space(&space); mtr.trim_pages(page_id_t(space.id, size)); ut_a(fsp_header_init(&space, size, &mtr) == DB_SUCCESS); - mysql_mutex_lock(&fil_system.mutex); - space.size= file->size= size; - mysql_mutex_unlock(&fil_system.mutex); for (auto &rseg : trx_sys.rseg_array) { @@ -821,7 +735,7 @@ TRANSACTIONAL_TARGET void trx_purge_truncate_history() rseg.reinit(rblock->page.id().page_no()); } - mtr.commit_shrink(space); + mtr.commit_shrink(space, size); /* No mutex; this is only updated by the purge coordinator. */ export_vars.innodb_undo_truncations++; @@ -838,11 +752,12 @@ TRANSACTIONAL_TARGET void trx_purge_truncate_history() purge_sys.next_stored= false; } - DBUG_EXECUTE_IF("ib_undo_trunc", ib::info() << "ib_undo_trunc"; + DBUG_EXECUTE_IF("ib_undo_trunc", + sql_print_information("InnoDB: ib_undo_trunc"); log_buffer_flush_to_disk(); DBUG_SUICIDE();); - ib::info() << "Truncated " << file->name; + sql_print_information("InnoDB: Truncated %s", file->name); purge_sys.truncate.last= purge_sys.truncate.current; ut_ad(&space == purge_sys.truncate.current); purge_sys.truncate.current= nullptr; diff --git a/storage/perfschema/pfs_variable.cc b/storage/perfschema/pfs_variable.cc index 3f7fd73683a87..a33fe2edd06e7 100644 --- a/storage/perfschema/pfs_variable.cc +++ b/storage/perfschema/pfs_variable.cc @@ -254,7 +254,8 @@ int PFS_system_variable_cache::do_materialize_all(THD *unsafe_thd) } /* Release lock taken in get_THD(). */ - mysql_mutex_unlock(&m_safe_thd->LOCK_thd_kill); + if (m_safe_thd != current_thd) + mysql_mutex_unlock(&m_safe_thd->LOCK_thd_kill); m_materialized= true; ret= 0; @@ -354,7 +355,8 @@ int PFS_system_variable_cache::do_materialize_session(PFS_thread *pfs_thread) } /* Release lock taken in get_THD(). */ - mysql_mutex_unlock(&m_safe_thd->LOCK_thd_kill); + if (m_safe_thd != current_thd) + mysql_mutex_unlock(&m_safe_thd->LOCK_thd_kill); m_materialized= true; ret= 0; @@ -407,7 +409,8 @@ int PFS_system_variable_cache::do_materialize_session(PFS_thread *pfs_thread, ui } /* Release lock taken in get_THD(). */ - mysql_mutex_unlock(&m_safe_thd->LOCK_thd_kill); + if (m_safe_thd != current_thd) + mysql_mutex_unlock(&m_safe_thd->LOCK_thd_kill); m_materialized= true; ret= 0; @@ -458,7 +461,8 @@ int PFS_system_variable_cache::do_materialize_session(THD *unsafe_thd) } /* Release lock taken in get_THD(). */ - mysql_mutex_unlock(&m_safe_thd->LOCK_thd_kill); + if (m_safe_thd != current_thd) + mysql_mutex_unlock(&m_safe_thd->LOCK_thd_kill); m_materialized= true; ret= 0; @@ -984,7 +988,8 @@ int PFS_status_variable_cache::do_materialize_all(THD* unsafe_thd) manifest(m_safe_thd, m_show_var_array.front(), status_vars, "", false, false); /* Release lock taken in get_THD(). */ - mysql_mutex_unlock(&m_safe_thd->LOCK_thd_kill); + if (m_safe_thd != current_thd) + mysql_mutex_unlock(&m_safe_thd->LOCK_thd_kill); m_materialized= true; ret= 0; @@ -1027,7 +1032,8 @@ int PFS_status_variable_cache::do_materialize_session(THD* unsafe_thd) manifest(m_safe_thd, m_show_var_array.front(), status_vars, "", false, true); /* Release lock taken in get_THD(). */ - mysql_mutex_unlock(&m_safe_thd->LOCK_thd_kill); + if (m_safe_thd != current_thd) + mysql_mutex_unlock(&m_safe_thd->LOCK_thd_kill); m_materialized= true; ret= 0; @@ -1067,7 +1073,8 @@ int PFS_status_variable_cache::do_materialize_session(PFS_thread *pfs_thread) manifest(m_safe_thd, m_show_var_array.front(), status_vars, "", false, true); /* Release lock taken in get_THD(). */ - mysql_mutex_unlock(&m_safe_thd->LOCK_thd_kill); + if (m_safe_thd != current_thd) + mysql_mutex_unlock(&m_safe_thd->LOCK_thd_kill); m_materialized= true; ret= 0; diff --git a/storage/perfschema/pfs_variable.h b/storage/perfschema/pfs_variable.h index fda8dc692d9d1..7dc248269b358 100644 --- a/storage/perfschema/pfs_variable.h +++ b/storage/perfschema/pfs_variable.h @@ -211,8 +211,12 @@ class Find_THD_variable : public Find_THD_Impl if (thd != m_unsafe_thd) return false; - /* Hold this lock to keep THD during materialization. */ - mysql_mutex_lock(&thd->LOCK_thd_kill); + /* + Hold this lock to keep THD during materialization. + But don't lock current_thd (to be able to use set_killed() later + */ + if (thd != current_thd) + mysql_mutex_lock(&thd->LOCK_thd_kill); return true; } void set_unsafe_thd(THD *unsafe_thd) { m_unsafe_thd= unsafe_thd; } diff --git a/storage/spider/mysql-test/spider/bugfix/r/perfschema.result b/storage/spider/mysql-test/spider/bugfix/r/perfschema.result new file mode 100644 index 0000000000000..9ce2e38f40be8 --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/r/perfschema.result @@ -0,0 +1,11 @@ +# +# MDEV-33031 Assertion failure upon reading from performance schema with binlog enabled +# +connect foo,localhost,root; +select variable_name, variable_value from performance_schema.status_by_thread +where variable_name like '%spider_direct_aggregate%'; +variable_name variable_value +Spider_direct_aggregate 0 +Spider_direct_aggregate 0 +disconnect foo; +connection default; diff --git a/storage/spider/mysql-test/spider/bugfix/t/perfschema.opt b/storage/spider/mysql-test/spider/bugfix/t/perfschema.opt new file mode 100644 index 0000000000000..611d08f0c7849 --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/t/perfschema.opt @@ -0,0 +1 @@ +--performance-schema diff --git a/storage/spider/mysql-test/spider/bugfix/t/perfschema.test b/storage/spider/mysql-test/spider/bugfix/t/perfschema.test new file mode 100644 index 0000000000000..2f1a961a51339 --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/t/perfschema.test @@ -0,0 +1,15 @@ +disable_query_log; +source ../../include/init_spider.inc; +enable_query_log; + +--echo # +--echo # MDEV-33031 Assertion failure upon reading from performance schema with binlog enabled +--echo # +connect foo,localhost,root; +select variable_name, variable_value from performance_schema.status_by_thread +where variable_name like '%spider_direct_aggregate%'; +disconnect foo; +connection default; + +disable_query_log; +source ../../include/deinit_spider.inc; diff --git a/storage/spider/spd_param.cc b/storage/spider/spd_param.cc index 21e457a814d54..62414dd1aa75f 100644 --- a/storage/spider/spd_param.cc +++ b/storage/spider/spd_param.cc @@ -109,59 +109,56 @@ extern volatile ulonglong spider_mon_table_cache_version_req; MYSQL_SYSVAR_NAME(param_name).def_val; \ } -static int spider_direct_update(THD *thd, SHOW_VAR *var, char *buff) +extern handlerton *spider_hton_ptr; +static void spider_trx_status_var(THD *thd, SHOW_VAR *var, char *buff, + ulonglong SPIDER_TRX::*counter) { - int error_num = 0; - SPIDER_TRX *trx; DBUG_ENTER("spider_direct_update"); var->type = SHOW_LONGLONG; - if ((trx = spider_get_trx(thd, TRUE, &error_num))) - var->value = (char *) &trx->direct_update_count; - DBUG_RETURN(error_num); + var->value= buff; + if (thd != current_thd) + mysql_mutex_lock(&thd->LOCK_thd_data); + SPIDER_TRX *trx = (SPIDER_TRX*)thd_get_ha_data(thd, spider_hton_ptr); + *(ulonglong*)buff= trx ? trx->*counter : 0; + if (thd != current_thd) + mysql_mutex_unlock(&thd->LOCK_thd_data); + DBUG_VOID_RETURN; +} + + +static int spider_direct_update(THD *thd, SHOW_VAR *var, char *buff) +{ + DBUG_ENTER("spider_direct_update"); + spider_trx_status_var(thd, var, buff, &SPIDER_TRX::direct_update_count); + DBUG_RETURN(0); } static int spider_direct_delete(THD *thd, SHOW_VAR *var, char *buff) { - int error_num = 0; - SPIDER_TRX *trx; DBUG_ENTER("spider_direct_delete"); - var->type = SHOW_LONGLONG; - if ((trx = spider_get_trx(thd, TRUE, &error_num))) - var->value = (char *) &trx->direct_delete_count; - DBUG_RETURN(error_num); + spider_trx_status_var(thd, var, buff, &SPIDER_TRX::direct_delete_count); + DBUG_RETURN(0); } static int spider_direct_order_limit(THD *thd, SHOW_VAR *var, char *buff) { - int error_num = 0; - SPIDER_TRX *trx; DBUG_ENTER("spider_direct_order_limit"); - var->type = SHOW_LONGLONG; - if ((trx = spider_get_trx(thd, TRUE, &error_num))) - var->value = (char *) &trx->direct_order_limit_count; - DBUG_RETURN(error_num); + spider_trx_status_var(thd, var, buff, &SPIDER_TRX::direct_order_limit_count); + DBUG_RETURN(0); } static int spider_direct_aggregate(THD *thd, SHOW_VAR *var, char *buff) { - int error_num = 0; - SPIDER_TRX *trx; DBUG_ENTER("spider_direct_aggregate"); - var->type = SHOW_LONGLONG; - if ((trx = spider_get_trx(thd, TRUE, &error_num))) - var->value = (char *) &trx->direct_aggregate_count; - DBUG_RETURN(error_num); + spider_trx_status_var(thd, var, buff, &SPIDER_TRX::direct_aggregate_count); + DBUG_RETURN(0); } static int spider_parallel_search(THD *thd, SHOW_VAR *var, char *buff) { - int error_num = 0; - SPIDER_TRX *trx; DBUG_ENTER("spider_parallel_search"); - var->type = SHOW_LONGLONG; - if ((trx = spider_get_trx(thd, TRUE, &error_num))) - var->value = (char *) &trx->parallel_search_count; - DBUG_RETURN(error_num); + spider_trx_status_var(thd, var, buff, &SPIDER_TRX::parallel_search_count); + DBUG_RETURN(0); } struct st_mysql_show_var spider_status_variables[] =