Merge 11.1 into 11.2

This commit is contained in:
Marko Mäkelä 2024-01-10 13:19:12 +02:00
commit e4cb1e3295
30 changed files with 358 additions and 408 deletions

View file

@ -610,49 +610,4 @@ c1 c2 c3
2 1 4 2 1 4
2 2 5 2 2 5
drop table t1; 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 End of 11.1 tests

View file

@ -667,31 +667,4 @@ select *from t1;
drop table 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 --echo End of 11.1 tests

View file

@ -24,3 +24,49 @@ SELECT * FROM t1;
c1 c1
SET sort_buffer_size=@save_sort_buffer_size; SET sort_buffer_size=@save_sort_buffer_size;
DROP TABLE t1; 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

View file

@ -1,6 +1,8 @@
--source include/have_innodb.inc --source include/have_innodb.inc
--source include/have_sequence.inc --source include/have_sequence.inc
--source include/innodb_stable_estimates.inc
--echo # Tests for delete with INNODB --echo # Tests for delete with INNODB
--echo # --echo #
@ -20,3 +22,31 @@ SELECT * FROM t1;
SET sort_buffer_size=@save_sort_buffer_size; SET sort_buffer_size=@save_sort_buffer_size;
DROP TABLE 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

View file

@ -895,3 +895,12 @@ REGEXP_INSTR('a_kollision', 'o([lm])\\1')
4 4
SELECT a FROM (SELECT "aa" a) t WHERE a REGEXP '[0-9]'; SELECT a FROM (SELECT "aa" a) t WHERE a REGEXP '[0-9]';
a 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
#

View file

@ -470,3 +470,11 @@ SELECT REGEXP_INSTR('a_kollision', 'o([lm])\\1');
# #
SELECT a FROM (SELECT "aa" a) t WHERE a REGEXP '[0-9]'; SELECT a FROM (SELECT "aa" a) t WHERE a REGEXP '[0-9]';
--enable_service_connection --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 #

View file

@ -61,17 +61,6 @@ set global innodb_fil_make_page_dirty_debug = 0;
set global innodb_buf_flush_list_now = 1; set global innodb_buf_flush_list_now = 1;
--let CLEANUP_IF_CHECKPOINT=drop table t1, unexpected_checkpoint; --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 --source ../include/no_checkpoint_end.inc
--echo # Make the 1st page (page_no=0) and 2nd page (page_no=1) --echo # Make the 1st page (page_no=0) and 2nd page (page_no=1)

View file

@ -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;

View file

@ -52,4 +52,10 @@ select NAME, TYPE, PROCESSLIST_COMMAND, PROCESSLIST_STATE
from performance_schema.threads from performance_schema.threads
where PROCESSLIST_ID = @slave_sql_pid; where PROCESSLIST_ID = @slave_sql_pid;
NAME TYPE PROCESSLIST_COMMAND PROCESSLIST_STATE 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 include/rpl_end.inc

View file

@ -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;

View file

@ -81,5 +81,11 @@ select NAME, TYPE, PROCESSLIST_COMMAND, PROCESSLIST_STATE
from performance_schema.threads from performance_schema.threads
where PROCESSLIST_ID = @slave_sql_pid; 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 --source include/rpl_end.inc

View file

@ -6090,7 +6090,7 @@ void Regexp_processor_pcre::init(CHARSET_INFO *data_charset, int extra_flags)
// Convert text data to utf-8. // Convert text data to utf-8.
m_library_charset= data_charset == &my_charset_bin ? 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) && m_conversion_is_needed= (data_charset != &my_charset_bin) &&
!my_charset_same(data_charset, m_library_charset); !my_charset_same(data_charset, m_library_charset);

View file

@ -3055,7 +3055,7 @@ public:
m_pcre(NULL), m_pcre_match_data(NULL), m_pcre(NULL), m_pcre_match_data(NULL),
m_conversion_is_needed(true), m_is_const(0), m_conversion_is_needed(true), m_is_const(0),
m_library_flags(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(); int default_regex_flags();
void init(CHARSET_INFO *data_charset, int extra_flags); void init(CHARSET_INFO *data_charset, int extra_flags);

View file

@ -11886,14 +11886,21 @@ set_binlog_snapshot_file(const char *src)
void void
TC_LOG_BINLOG::set_status_variables(THD *thd) TC_LOG_BINLOG::set_status_variables(THD *thd)
{ {
binlog_cache_mngr *cache_mngr; bool have_snapshot= false;
if (thd && opt_bin_log) if (thd && opt_bin_log)
cache_mngr= thd->binlog_get_cache_mngr(); {
else mysql_mutex_lock(&thd->LOCK_thd_data);
cache_mngr= 0; 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); mysql_mutex_lock(&LOCK_commit_ordered);
binlog_status_var_num_commits= this->num_commits; binlog_status_var_num_commits= this->num_commits;
binlog_status_var_num_group_commits= this->num_group_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_timeout= this->group_commit_trigger_timeout;
binlog_status_group_commit_trigger_lock_wait= this->group_commit_trigger_lock_wait; binlog_status_group_commit_trigger_lock_wait= this->group_commit_trigger_lock_wait;
mysql_mutex_unlock(&LOCK_prepare_ordered); 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;
}
} }

View file

@ -754,16 +754,20 @@ bool buf_page_t::flush(bool evict, fil_space_t *space)
ut_ad(space->referenced()); ut_ad(space->referenced());
const auto s= state(); const auto s= state();
ut_a(s >= FREED);
if (s < UNFIXED)
{
if (UNIV_LIKELY(space->purpose == FIL_TYPE_TABLESPACE))
{
const lsn_t lsn= const lsn_t lsn=
mach_read_from_8(my_assume_aligned<8> mach_read_from_8(my_assume_aligned<8>
(FIL_PAGE_LSN + (zip.data ? zip.data : frame))); (FIL_PAGE_LSN + (zip.data ? zip.data : frame)));
ut_ad(lsn >= oldest_modification()); 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))
{
freed:
if (lsn > log_sys.get_flushed_lsn()) if (lsn > log_sys.get_flushed_lsn())
{ {
mysql_mutex_unlock(&buf_pool.mutex); mysql_mutex_unlock(&buf_pool.mutex);
@ -775,6 +779,12 @@ bool buf_page_t::flush(bool evict, fil_space_t *space)
return false; 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_d(const auto f=) zip.fix.fetch_add(WRITE_FIX - UNFIXED);
ut_ad(f >= UNFIXED); ut_ad(f >= UNFIXED);
ut_ad(f < READ_FIX); 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 ((s & LRU_MASK) == REINIT || !space->use_doublewrite())
{ {
if (UNIV_LIKELY(space->purpose == FIL_TYPE_TABLESPACE)) if (UNIV_LIKELY(space->purpose == FIL_TYPE_TABLESPACE) &&
{ lsn > log_sys.get_flushed_lsn())
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());
log_write_up_to(lsn, true); log_write_up_to(lsn, true);
}
space->io(IORequest{type, this, slot}, physical_offset(), size, space->io(IORequest{type, this, slot}, physical_offset(), size,
write_frame, this); write_frame, this);
} }
@ -1057,11 +1061,25 @@ static ulint buf_flush_try_neighbors(fil_space_t *space,
bool contiguous, bool evict, bool contiguous, bool evict,
ulint n_flushed, ulint n_to_flush) ulint n_flushed, ulint n_to_flush)
{ {
mysql_mutex_unlock(&buf_pool.mutex);
ut_ad(space->id == page_id.space()); ut_ad(space->id == page_id.space());
ut_ad(bpage->id() == page_id); 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; ulint count= 0;
page_id_t id= page_id; page_id_t id= page_id;
page_id_t high= buf_flush_check_neighbors(*space, id, contiguous, evict); page_id_t high= buf_flush_check_neighbors(*space, id, contiguous, evict);
@ -2434,9 +2452,9 @@ static void buf_flush_page_cleaner()
do do
{ {
DBUG_EXECUTE_IF("ib_log_checkpoint_avoid", continue;); IF_DBUG(if (_db_keyword_(nullptr, "ib_log_checkpoint_avoid", 1) ||
DBUG_EXECUTE_IF("ib_log_checkpoint_avoid_hard", continue;); _db_keyword_(nullptr, "ib_log_checkpoint_avoid_hard", 1))
continue,);
if (!recv_recovery_is_on() && if (!recv_recovery_is_on() &&
!srv_startup_is_before_trx_rollback_phase && !srv_startup_is_before_trx_rollback_phase &&
srv_operation <= SRV_OPERATION_EXPORT_RESTORED) srv_operation <= SRV_OPERATION_EXPORT_RESTORED)

View file

@ -564,7 +564,7 @@ fil_space_extend_must_retry(
ut_ad(UT_LIST_GET_LAST(space->chain) == node); ut_ad(UT_LIST_GET_LAST(space->chain) == node);
ut_ad(size >= FIL_IBD_FILE_INITIAL_SIZE); ut_ad(size >= FIL_IBD_FILE_INITIAL_SIZE);
ut_ad(node->space == space); ut_ad(node->space == space);
ut_ad(space->referenced() || space->is_being_truncated); ut_ad(space->referenced());
*success = space->size >= size; *success = space->size >= size;
@ -653,8 +653,7 @@ fil_space_extend_must_retry(
default: default:
ut_ad(space->purpose == FIL_TYPE_TABLESPACE ut_ad(space->purpose == FIL_TYPE_TABLESPACE
|| space->purpose == FIL_TYPE_IMPORT); || space->purpose == FIL_TYPE_IMPORT);
if (space->purpose == FIL_TYPE_TABLESPACE if (space->purpose == FIL_TYPE_TABLESPACE) {
&& !space->is_being_truncated) {
goto do_flush; goto do_flush;
} }
break; break;
@ -754,12 +753,10 @@ bool fil_space_extend(fil_space_t *space, uint32_t size)
bool success= false; bool success= false;
const bool acquired= space->acquire(); const bool acquired= space->acquire();
mysql_mutex_lock(&fil_system.mutex); 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), while (fil_space_extend_must_retry(space, UT_LIST_GET_LAST(space->chain),
size, &success)) size, &success))
mysql_mutex_lock(&fil_system.mutex); mysql_mutex_lock(&fil_system.mutex);
}
mysql_mutex_unlock(&fil_system.mutex); mysql_mutex_unlock(&fil_system.mutex);
if (acquired) if (acquired)
space->release(); space->release();
@ -3135,11 +3132,9 @@ fil_space_validate_for_mtr_commit(
ut_ad(!is_predefined_tablespace(space->id)); ut_ad(!is_predefined_tablespace(space->id));
/* We are serving mtr_commit(). While there is an active /* 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. */ guaranteed by meta-data locks or transactional locks. */
ut_ad(!space->is_stopping() ut_ad(!space->is_stopping() || space->referenced());
|| space->is_being_truncated /* fil_truncate_prepare() */
|| space->referenced());
} }
#endif /* UNIV_DEBUG */ #endif /* UNIV_DEBUG */

View file

@ -41,8 +41,6 @@ Created 11/29/1995 Heikki Tuuri
#include "fsp0types.h" #include "fsp0types.h"
#include "log.h" #include "log.h"
typedef uint32_t page_no_t;
/** Returns the first extent descriptor for a segment. /** Returns the first extent descriptor for a segment.
We think of the extent lists of the segment catenated in the order We think of the extent lists of the segment catenated in the order
FSEG_FULL -> FSEG_NOT_FULL -> FSEG_FREE. FSEG_FULL -> FSEG_NOT_FULL -> FSEG_FREE.
@ -331,7 +329,7 @@ xdes_t*
xdes_get_descriptor_with_space_hdr( xdes_get_descriptor_with_space_hdr(
buf_block_t* header, buf_block_t* header,
const fil_space_t* space, const fil_space_t* space,
page_no_t offset, uint32_t offset,
mtr_t* mtr, mtr_t* mtr,
dberr_t* err = nullptr, dberr_t* err = nullptr,
buf_block_t** desc_block = 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] err error code
@param[out] xdes extent descriptor page @param[out] xdes extent descriptor page
@return the extent descriptor */ @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, mtr_t *mtr, dberr_t *err= nullptr,
buf_block_t **xdes= nullptr) buf_block_t **xdes= nullptr)
{ {
@ -841,8 +839,7 @@ fsp_fill_free_list(
if (i) if (i)
{ {
buf_block_t *f= buf_LRU_get_free_block(have_no_mutex); buf_block_t *f= buf_LRU_get_free_block(have_no_mutex);
buf_block_t *block= buf_page_create(space, static_cast<uint32_t>(i), buf_block_t *block= buf_page_create(space, i, zip_size, mtr, f);
zip_size, mtr, f);
if (UNIV_UNLIKELY(block != f)) if (UNIV_UNLIKELY(block != f))
buf_pool.free_block(f); buf_pool.free_block(f);
fsp_init_file_page(space, block, mtr); 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 *f= buf_LRU_get_free_block(have_no_mutex);
buf_block_t *block= buf_block_t *block=
buf_page_create(space, static_cast<uint32_t>(i + 1), buf_page_create(space, i + 1, zip_size, mtr, f);
zip_size, mtr, f);
if (UNIV_UNLIKELY(block != f)) if (UNIV_UNLIKELY(block != f))
buf_pool.free_block(f); buf_pool.free_block(f);
/* The zero-initialization will reset the change buffer bitmap bits /* 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] offset page number of the allocated page
@param[in,out] mtr mini-transaction @param[in,out] mtr mini-transaction
@return block, initialized */ @return block, initialized */
static static buf_block_t* fsp_page_create(fil_space_t *space, uint32_t offset,
buf_block_t* mtr_t *mtr)
fsp_page_create(fil_space_t *space, page_no_t offset, mtr_t *mtr)
{ {
buf_block_t *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(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_block_t*>
(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<uint32_t>(offset),
space->zip_size(), mtr, free_block);
if (UNIV_UNLIKELY(block != free_block)) if (UNIV_UNLIKELY(block != free_block))
buf_pool.free_block(free_block); buf_pool.free_block(free_block);
}
fsp_init_file_page(space, block, mtr); fsp_init_file_page(space, block, mtr);
return block; return block;
} }
@ -1224,7 +1153,7 @@ MY_ATTRIBUTE((nonnull, warn_unused_result))
@param[in] offset page number in the extent @param[in] offset page number in the extent
@param[in,out] mtr mini-transaction @param[in,out] mtr mini-transaction
@return error code */ @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) mtr_t* mtr)
{ {
ut_ad(space->is_owner()); ut_ad(space->is_owner());
@ -1261,7 +1190,7 @@ The page is marked as free and clean.
@param[in] offset page number @param[in] offset page number
@param[in,out] mtr mini-transaction @param[in,out] mtr mini-transaction
@return error code */ @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; xdes_t* descr;
ulint frag_n_used; ulint frag_n_used;
@ -1801,7 +1730,6 @@ page_alloc:
ut_d(const auto x = block->page.lock.x_lock_count()); ut_d(const auto x = block->page.lock.x_lock_count());
ut_ad(x || block->page.lock.not_recursive()); ut_ad(x || block->page.lock.not_recursive());
ut_ad(x == 1 || space->is_being_truncated);
ut_ad(x <= 2); ut_ad(x <= 2);
ut_ad(!fil_page_get_type(block->page.frame)); ut_ad(!fil_page_get_type(block->page.frame));
mtr->write<1>(*block, FIL_PAGE_TYPE + 1 + 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, fseg_inode_t* seg_inode,
buf_block_t* iblock, buf_block_t* iblock,
fil_space_t* space, fil_space_t* space,
page_no_t offset, uint32_t offset,
mtr_t* mtr mtr_t* mtr
#ifdef BTR_CUR_HASH_ADAPT #ifdef BTR_CUR_HASH_ADAPT
,bool ahi=false ,bool ahi=false
@ -2904,7 +2832,7 @@ fseg_free_step(
return true; 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 if (fseg_free_page_low(inode, iblock, space, page_no, mtr
#ifdef BTR_CUR_HASH_ADAPT #ifdef BTR_CUR_HASH_ADAPT
@ -3699,28 +3627,13 @@ mtr_max:
return; return;
} }
} }
mysql_mutex_lock(&fil_system.mutex);
space->size= last_used_extent;
if (space->free_limit > last_used_extent) if (space->free_limit > last_used_extent)
space->free_limit= space->size; space->free_limit= last_used_extent;
space->free_len= flst_get_len(FSP_HEADER_OFFSET + FSP_FREE +
header->page.frame);
space->free_len= flst_get_len( mtr.commit_shrink(*space, last_used_extent);
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);
sql_print_information("InnoDB: System tablespace truncated successfully"); sql_print_information("InnoDB: System tablespace truncated successfully");
srv_use_doublewrite_buf= old_dblwr_buf; srv_use_doublewrite_buf= old_dblwr_buf;
} }

View file

@ -18184,7 +18184,10 @@ buf_flush_list_now_set(THD*, st_mysql_sys_var*, void*, const void* save)
if (s) if (s)
buf_flush_sync(); buf_flush_sync();
else else
{
while (buf_flush_list_space(fil_system.sys_space, nullptr)); 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); 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, 10 << 20, 10 << 20,
1ULL << (32 + UNIV_PAGE_SIZE_SHIFT_MAX), 0); 1ULL << (32 + UNIV_PAGE_SIZE_SHIFT_MAX), 0);
static ulong innodb_purge_rseg_truncate_frequency;
static MYSQL_SYSVAR_ULONG(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, PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_DEPRECATED,
"Deprecated parameter with no effect", "Deprecated parameter with no effect",
NULL, NULL, 128, 1, 128, 0); NULL, NULL, 128, 1, 128, 0);

View file

@ -330,8 +330,6 @@ struct fil_space_t final
lsn_t max_lsn; lsn_t max_lsn;
/** tablespace identifier */ /** tablespace identifier */
uint32_t id; uint32_t id;
/** whether undo tablespace truncation is in progress */
bool is_being_truncated;
fil_type_t purpose;/*!< purpose */ fil_type_t purpose;/*!< purpose */
UT_LIST_BASE_NODE_T(fil_node_t) chain; UT_LIST_BASE_NODE_T(fil_node_t) chain;
/*!< base node for the file chain */ /*!< base node for the file chain */
@ -411,6 +409,8 @@ private:
/** LSN of freeing last page; protected by freed_range_mutex */ /** LSN of freeing last page; protected by freed_range_mutex */
lsn_t last_freed_lsn; lsn_t last_freed_lsn;
/** LSN of undo tablespace creation or 0; protected by latch */
lsn_t create_lsn;
public: public:
/** @return whether doublewrite buffering is needed */ /** @return whether doublewrite buffering is needed */
inline bool use_doublewrite() const; inline bool use_doublewrite() const;
@ -418,6 +418,12 @@ public:
/** @return whether a page has been freed */ /** @return whether a page has been freed */
inline bool is_freed(uint32_t page); 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. /** Apply freed_ranges to the file.
@param writable whether the file is writable @param writable whether the file is writable
@return number of pages written or hole-punched */ @return number of pages written or hole-punched */
@ -495,9 +501,6 @@ public:
/** Note that operations on the tablespace must stop. */ /** Note that operations on the tablespace must stop. */
inline void set_stopping(); 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 /** Drop the tablespace and wait for any pending operations to cease
@param id tablespace identifier @param id tablespace identifier
@param detached_handle pointer to file to be closed later, or nullptr @param detached_handle pointer to file to be closed later, or nullptr
@ -1542,14 +1545,6 @@ inline void fil_space_t::set_stopping()
#endif #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. */ /** Flush pending writes from the file system cache to the file. */
template<bool have_reference> inline void fil_space_t::flush() template<bool have_reference> inline void fil_space_t::flush()
{ {

View file

@ -89,8 +89,9 @@ struct mtr_t {
{ auto s= m_memo.size(); rollback_to_savepoint(s - 1, s); } { auto s= m_memo.size(); rollback_to_savepoint(s - 1, s); }
/** Commit a mini-transaction that is shrinking a tablespace. /** Commit a mini-transaction that is shrinking a tablespace.
@param space tablespace that is being shrunk */ @param space tablespace that is being shrunk
ATTRIBUTE_COLD void commit_shrink(fil_space_t &space); @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. /** Commit a mini-transaction that is deleting or renaming a file.
@param space tablespace that is being renamed or deleted @param space tablespace that is being renamed or deleted

View file

@ -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;
extern uint srv_n_fil_crypt_threads_started; 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. */ /** Enable or Disable Truncate of UNDO tablespace. */
extern my_bool srv_undo_log_truncate; extern my_bool srv_undo_log_truncate;
/** Default size of UNDO tablespace (10MiB for innodb_page_size=16k) */ /** 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; UNIV_PAGE_SIZE_DEF;
extern char* srv_log_group_home_dir; extern char* srv_log_group_home_dir;

View file

@ -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); 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. /** Commit a mini-transaction that is shrinking a tablespace.
@param space tablespace that is being shrunk */ @param space tablespace that is being shrunk
void mtr_t::commit_shrink(fil_space_t &space) @param size new size in pages */
void mtr_t::commit_shrink(fil_space_t &space, uint32_t size)
{ {
ut_ad(is_active()); ut_ad(is_active());
ut_ad(!high_level_read_only); 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; const lsn_t start_lsn= do_write().first;
ut_d(m_log.erase()); 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. */ /* Durably write the reduced FSP_SIZE before truncating the data file. */
log_write_and_flush(); log_write_and_flush();
#ifndef SUX_LOCK_GENERIC #ifndef SUX_LOCK_GENERIC
ut_ad(log_sys.latch.is_write_locked()); ut_ad(log_sys.latch.is_write_locked());
#endif #endif
os_file_truncate( os_file_truncate(file->name, file->handle,
space.chain.end->name, space.chain.end->handle, os_offset_t{file->size} << srv_page_size_shift, true);
os_offset_t{space.chain.end->size} << srv_page_size_shift, true);
space.clear_freed_ranges(); 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; size_t modified= 0;
auto it= m_memo.rbegin(); auto it= m_memo.rbegin();
mysql_mutex_lock(&buf_pool.flush_list_mutex); 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(); log_sys.latch.wr_unlock();
m_latch_ex= false; 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();
release_resources(); release_resources();
} }
@ -998,10 +1017,9 @@ std::pair<lsn_t,mtr_t::page_flush_ahead> mtr_t::do_write()
#ifndef DBUG_OFF #ifndef DBUG_OFF
do do
{ {
if (m_log_mode != MTR_LOG_ALL) if (m_log_mode != MTR_LOG_ALL ||
_db_keyword_(nullptr, "skip_page_checksum", 1))
continue; continue;
DBUG_EXECUTE_IF("skip_page_checksum", continue;);
for (const mtr_memo_slot_t& slot : m_memo) for (const mtr_memo_slot_t& slot : m_memo)
if (slot.type & MTR_MEMO_MODIFY) if (slot.type & MTR_MEMO_MODIFY)
{ {

View file

@ -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. */ any of the rollback-segment based on configuration used. */
uint32_t srv_undo_tablespaces_active; 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. /** Enable or Disable Truncate of UNDO tablespace.
Note: If enabled then UNDO tablespace will be selected for truncate. Note: If enabled then UNDO tablespace will be selected for truncate.
While Server waits for undo-tablespace to truncate if user disables While Server waits for undo-tablespace to truncate if user disables

View file

@ -41,6 +41,7 @@ Created 3/26/1996 Heikki Tuuri
#include "dict0load.h" #include "dict0load.h"
#include <mysql/service_thd_mdl.h> #include <mysql/service_thd_mdl.h>
#include <mysql/service_wsrep.h> #include <mysql/service_wsrep.h>
#include "log.h"
/** Maximum allowable purge history length. <=0 means 'infinite'. */ /** Maximum allowable purge history length. <=0 means 'infinite'. */
ulong srv_max_purge_lag = 0; 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); ut_ad(rseg_hdr->page.id() == rseg_hdr_id);
block->page.lock.x_lock(); block->page.lock.x_lock();
ut_ad(block->page.id() == id); ut_ad(block->page.id() == id);
mtr.memo_push(rseg_hdr, MTR_MEMO_PAGE_X_MODIFY); mtr.memo_push(rseg_hdr, MTR_MEMO_PAGE_X_FIX);
mtr.memo_push(block, MTR_MEMO_PAGE_X_MODIFY); mtr.memo_push(block, MTR_MEMO_PAGE_X_FIX);
} }
while (!fseg_free_step(TRX_UNDO_SEG_HDR + TRX_UNDO_FSEG_HEADER + while (!fseg_free_step(TRX_UNDO_SEG_HDR + TRX_UNDO_FSEG_HEADER +
@ -500,7 +501,7 @@ loop:
mtr.start(); mtr.start();
rseg_hdr->page.lock.x_lock(); rseg_hdr->page.lock.x_lock();
ut_ad(rseg_hdr->page.id() == rseg.page_id()); 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; goto loop;
} }
@ -667,16 +668,9 @@ not_free:
rseg.latch.rd_unlock(); rseg.latch.rd_unlock();
} }
ib::info() << "Truncating " << file->name; sql_print_information("InnoDB: Truncating %s", file->name);
trx_purge_cleanse_purge_queue(space); 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. /* Lock all modified pages of the tablespace.
During truncation, we do not want any writes to the file. During truncation, we do not want any writes to the file.
@ -686,86 +680,12 @@ not_free:
discarding the to-be-trimmed pages without flushing would discarding the to-be-trimmed pages without flushing would
break crash recovery. */ break crash recovery. */
rescan:
if (UNIV_UNLIKELY(srv_shutdown_state != SRV_SHUTDOWN_NONE) && if (UNIV_UNLIKELY(srv_shutdown_state != SRV_SHUTDOWN_NONE) &&
srv_fast_shutdown) srv_fast_shutdown)
{
fast_shutdown:
mtr.commit();
return; 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<buf_block_t*>(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<buf_block_t*>(bpage)))
mtr.memo_push(reinterpret_cast<buf_block_t*>(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. */ /* Adjust the tablespace metadata. */
mysql_mutex_lock(&fil_system.mutex); mysql_mutex_lock(&fil_system.mutex);
space.set_stopping();
space.is_being_truncated= true;
if (space.crypt_data) if (space.crypt_data)
{ {
space.reacquire(); space.reacquire();
@ -776,26 +696,20 @@ not_free:
else else
mysql_mutex_unlock(&fil_system.mutex); mysql_mutex_unlock(&fil_system.mutex);
for (auto i= 6000; space.referenced(); /* Re-initialize tablespace, in a single mini-transaction. */
std::this_thread::sleep_for(std::chrono::milliseconds(10))) const uint32_t size= SRV_UNDO_TABLESPACE_SIZE_IN_PAGES;
{
if (!--i)
{
mtr.commit();
ib::error() << "Failed to freeze UNDO tablespace " << file->name;
return;
}
}
log_free_check();
mtr_t mtr;
mtr.start();
mtr.x_lock_space(&space);
/* Associate the undo tablespace with mtr. /* Associate the undo tablespace with mtr.
During mtr::commit_shrink(), InnoDB can use the undo During mtr::commit_shrink(), InnoDB can use the undo
tablespace object to clear all freed ranges */ tablespace object to clear all freed ranges */
mtr.set_named_space(&space); mtr.set_named_space(&space);
mtr.trim_pages(page_id_t(space.id, size)); mtr.trim_pages(page_id_t(space.id, size));
ut_a(fsp_header_init(&space, size, &mtr) == DB_SUCCESS); 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) for (auto &rseg : trx_sys.rseg_array)
{ {
@ -821,7 +735,7 @@ not_free:
rseg.reinit(rblock->page.id().page_no()); 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. */ /* No mutex; this is only updated by the purge coordinator. */
export_vars.innodb_undo_truncations++; export_vars.innodb_undo_truncations++;
@ -838,11 +752,12 @@ not_free:
purge_sys.next_stored= false; 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(); log_buffer_flush_to_disk();
DBUG_SUICIDE();); DBUG_SUICIDE(););
ib::info() << "Truncated " << file->name; sql_print_information("InnoDB: Truncated %s", file->name);
purge_sys.truncate.last= purge_sys.truncate.current; purge_sys.truncate.last= purge_sys.truncate.current;
ut_ad(&space == purge_sys.truncate.current); ut_ad(&space == purge_sys.truncate.current);
purge_sys.truncate.current= nullptr; purge_sys.truncate.current= nullptr;

View file

@ -254,6 +254,7 @@ int PFS_system_variable_cache::do_materialize_all(THD *unsafe_thd)
} }
/* Release lock taken in get_THD(). */ /* Release lock taken in get_THD(). */
if (m_safe_thd != current_thd)
mysql_mutex_unlock(&m_safe_thd->LOCK_thd_kill); mysql_mutex_unlock(&m_safe_thd->LOCK_thd_kill);
m_materialized= true; m_materialized= true;
@ -354,6 +355,7 @@ int PFS_system_variable_cache::do_materialize_session(PFS_thread *pfs_thread)
} }
/* Release lock taken in get_THD(). */ /* Release lock taken in get_THD(). */
if (m_safe_thd != current_thd)
mysql_mutex_unlock(&m_safe_thd->LOCK_thd_kill); mysql_mutex_unlock(&m_safe_thd->LOCK_thd_kill);
m_materialized= true; m_materialized= true;
@ -407,6 +409,7 @@ int PFS_system_variable_cache::do_materialize_session(PFS_thread *pfs_thread, ui
} }
/* Release lock taken in get_THD(). */ /* Release lock taken in get_THD(). */
if (m_safe_thd != current_thd)
mysql_mutex_unlock(&m_safe_thd->LOCK_thd_kill); mysql_mutex_unlock(&m_safe_thd->LOCK_thd_kill);
m_materialized= true; m_materialized= true;
@ -458,6 +461,7 @@ int PFS_system_variable_cache::do_materialize_session(THD *unsafe_thd)
} }
/* Release lock taken in get_THD(). */ /* Release lock taken in get_THD(). */
if (m_safe_thd != current_thd)
mysql_mutex_unlock(&m_safe_thd->LOCK_thd_kill); mysql_mutex_unlock(&m_safe_thd->LOCK_thd_kill);
m_materialized= true; m_materialized= true;
@ -984,6 +988,7 @@ int PFS_status_variable_cache::do_materialize_all(THD* unsafe_thd)
manifest(m_safe_thd, m_show_var_array.front(), status_vars, "", false, false); manifest(m_safe_thd, m_show_var_array.front(), status_vars, "", false, false);
/* Release lock taken in get_THD(). */ /* Release lock taken in get_THD(). */
if (m_safe_thd != current_thd)
mysql_mutex_unlock(&m_safe_thd->LOCK_thd_kill); mysql_mutex_unlock(&m_safe_thd->LOCK_thd_kill);
m_materialized= true; m_materialized= true;
@ -1027,6 +1032,7 @@ int PFS_status_variable_cache::do_materialize_session(THD* unsafe_thd)
manifest(m_safe_thd, m_show_var_array.front(), status_vars, "", false, true); manifest(m_safe_thd, m_show_var_array.front(), status_vars, "", false, true);
/* Release lock taken in get_THD(). */ /* Release lock taken in get_THD(). */
if (m_safe_thd != current_thd)
mysql_mutex_unlock(&m_safe_thd->LOCK_thd_kill); mysql_mutex_unlock(&m_safe_thd->LOCK_thd_kill);
m_materialized= true; m_materialized= true;
@ -1067,6 +1073,7 @@ 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); manifest(m_safe_thd, m_show_var_array.front(), status_vars, "", false, true);
/* Release lock taken in get_THD(). */ /* Release lock taken in get_THD(). */
if (m_safe_thd != current_thd)
mysql_mutex_unlock(&m_safe_thd->LOCK_thd_kill); mysql_mutex_unlock(&m_safe_thd->LOCK_thd_kill);
m_materialized= true; m_materialized= true;

View file

@ -211,7 +211,11 @@ public:
if (thd != m_unsafe_thd) if (thd != m_unsafe_thd)
return false; return false;
/* Hold this lock to keep THD during materialization. */ /*
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); mysql_mutex_lock(&thd->LOCK_thd_kill);
return true; return true;
} }

View file

@ -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;

View file

@ -0,0 +1 @@
--performance-schema

View file

@ -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;

View file

@ -109,59 +109,56 @@ extern volatile ulonglong spider_mon_table_cache_version_req;
MYSQL_SYSVAR_NAME(param_name).def_val; \ 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"); DBUG_ENTER("spider_direct_update");
var->type = SHOW_LONGLONG; var->type = SHOW_LONGLONG;
if ((trx = spider_get_trx(thd, TRUE, &error_num))) var->value= buff;
var->value = (char *) &trx->direct_update_count; if (thd != current_thd)
DBUG_RETURN(error_num); 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) static int spider_direct_delete(THD *thd, SHOW_VAR *var, char *buff)
{ {
int error_num = 0;
SPIDER_TRX *trx;
DBUG_ENTER("spider_direct_delete"); DBUG_ENTER("spider_direct_delete");
var->type = SHOW_LONGLONG; spider_trx_status_var(thd, var, buff, &SPIDER_TRX::direct_delete_count);
if ((trx = spider_get_trx(thd, TRUE, &error_num))) DBUG_RETURN(0);
var->value = (char *) &trx->direct_delete_count;
DBUG_RETURN(error_num);
} }
static int spider_direct_order_limit(THD *thd, SHOW_VAR *var, char *buff) 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"); DBUG_ENTER("spider_direct_order_limit");
var->type = SHOW_LONGLONG; spider_trx_status_var(thd, var, buff, &SPIDER_TRX::direct_order_limit_count);
if ((trx = spider_get_trx(thd, TRUE, &error_num))) DBUG_RETURN(0);
var->value = (char *) &trx->direct_order_limit_count;
DBUG_RETURN(error_num);
} }
static int spider_direct_aggregate(THD *thd, SHOW_VAR *var, char *buff) static int spider_direct_aggregate(THD *thd, SHOW_VAR *var, char *buff)
{ {
int error_num = 0;
SPIDER_TRX *trx;
DBUG_ENTER("spider_direct_aggregate"); DBUG_ENTER("spider_direct_aggregate");
var->type = SHOW_LONGLONG; spider_trx_status_var(thd, var, buff, &SPIDER_TRX::direct_aggregate_count);
if ((trx = spider_get_trx(thd, TRUE, &error_num))) DBUG_RETURN(0);
var->value = (char *) &trx->direct_aggregate_count;
DBUG_RETURN(error_num);
} }
static int spider_parallel_search(THD *thd, SHOW_VAR *var, char *buff) static int spider_parallel_search(THD *thd, SHOW_VAR *var, char *buff)
{ {
int error_num = 0;
SPIDER_TRX *trx;
DBUG_ENTER("spider_parallel_search"); DBUG_ENTER("spider_parallel_search");
var->type = SHOW_LONGLONG; spider_trx_status_var(thd, var, buff, &SPIDER_TRX::parallel_search_count);
if ((trx = spider_get_trx(thd, TRUE, &error_num))) DBUG_RETURN(0);
var->value = (char *) &trx->parallel_search_count;
DBUG_RETURN(error_num);
} }
struct st_mysql_show_var spider_status_variables[] = struct st_mysql_show_var spider_status_variables[] =