MDEV-27716 mtr_t::commit() acquires log_sys.mutex when writing no log

mtr_t::is_block_dirtied(), mtr_t::memo_push(): Never set m_made_dirty
for pages of the temporary tablespace. Ever since
commit 5eb539555b36a60944eefeb84d5d6d436ba61e63
we never add those pages to buf_pool.flush_list.

mtr_t::commit(): Implement part of mtr_t::prepare_write() here,
and avoid acquiring log_sys.mutex if no log is written.
During IMPORT TABLESPACE fixup, we do not write log, but we must
add pages to buf_pool.flush_list and for that, be prepared
to acquire log_sys.flush_order_mutex.

mtr_t::do_write(): Replaces mtr_t::prepare_write().
This commit is contained in:
Marko Mäkelä 2022-02-09 15:10:10 +02:00
parent 34c5019698
commit fd101daa84
3 changed files with 31 additions and 30 deletions

View File

@ -623,9 +623,9 @@ private:
@param type extended record subtype; @see mrec_ext_t */ @param type extended record subtype; @see mrec_ext_t */
inline void log_write_extended(const buf_block_t &block, byte type); inline void log_write_extended(const buf_block_t &block, byte type);
/** Prepare to write the mini-transaction log to the redo log buffer. /** Append the redo log records to the redo log buffer.
@return number of bytes to write in finish_write() */ @return {start_lsn,flush_ahead} */
inline ulint prepare_write(); std::pair<lsn_t,page_flush_ahead> do_write();
/** Append the redo log records to the redo log buffer. /** Append the redo log records to the redo log buffer.
@param len number of bytes to write @param len number of bytes to write

View File

@ -1,7 +1,7 @@
/***************************************************************************** /*****************************************************************************
Copyright (c) 1995, 2014, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 1995, 2014, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2017, 2021, MariaDB Corporation. Copyright (c) 2017, 2022, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software the terms of the GNU General Public License as published by the Free Software
@ -32,7 +32,8 @@ inline bool mtr_t::is_block_dirtied(const buf_block_t *block)
{ {
ut_ad(block->page.state() == BUF_BLOCK_FILE_PAGE); ut_ad(block->page.state() == BUF_BLOCK_FILE_PAGE);
ut_ad(block->page.buf_fix_count()); ut_ad(block->page.buf_fix_count());
return block->page.oldest_modification() <= 1; return block->page.oldest_modification() <= 1 &&
block->page.id().space() < SRV_TMP_SPACE_ID;
} }
/** /**
@ -51,8 +52,8 @@ mtr_t::memo_push(void* object, mtr_memo_type_t type)
grab log_sys.flush_order_mutex at mtr_t::commit() so that we grab log_sys.flush_order_mutex at mtr_t::commit() so that we
can insert the dirtied page into the flush list. */ can insert the dirtied page into the flush list. */
if ((type == MTR_MEMO_PAGE_X_FIX || type == MTR_MEMO_PAGE_SX_FIX) if (!m_made_dirty
&& !m_made_dirty) { && (type == MTR_MEMO_PAGE_X_FIX || type == MTR_MEMO_PAGE_SX_FIX)) {
m_made_dirty = is_block_dirtied( m_made_dirty = is_block_dirtied(
reinterpret_cast<const buf_block_t*>(object)); reinterpret_cast<const buf_block_t*>(object));

View File

@ -404,18 +404,27 @@ void mtr_t::commit()
std::pair<lsn_t,page_flush_ahead> lsns; std::pair<lsn_t,page_flush_ahead> lsns;
if (const ulint len= prepare_write()) if (UNIV_LIKELY(m_log_mode == MTR_LOG_ALL))
lsns= finish_write(len); {
lsns= do_write();
if (m_made_dirty)
mysql_mutex_lock(&log_sys.flush_order_mutex);
/* It is now safe to release log_sys.mutex because the
buf_pool.flush_order_mutex will ensure that we are the first one
to insert into buf_pool.flush_list. */
mysql_mutex_unlock(&log_sys.mutex);
}
else else
{
ut_ad(m_log_mode == MTR_LOG_NO_REDO);
ut_ad(m_log.size() == 0);
m_commit_lsn= log_sys.get_lsn();
lsns= { m_commit_lsn, PAGE_FLUSH_NO }; lsns= { m_commit_lsn, PAGE_FLUSH_NO };
if (UNIV_UNLIKELY(m_made_dirty)) /* This should be IMPORT TABLESPACE */
if (m_made_dirty) mysql_mutex_lock(&log_sys.flush_order_mutex);
mysql_mutex_lock(&log_sys.flush_order_mutex); }
/* It is now safe to release the log mutex because the
flush_order mutex will ensure that we are the first one
to insert into the flush list. */
mysql_mutex_unlock(&log_sys.mutex);
if (m_freed_pages) if (m_freed_pages)
{ {
@ -517,7 +526,7 @@ void mtr_t::commit_shrink(fil_space_t &space)
log_write_and_flush_prepare(); log_write_and_flush_prepare();
const lsn_t start_lsn= finish_write(prepare_write()).first; const lsn_t start_lsn= do_write().first;
mysql_mutex_lock(&log_sys.flush_order_mutex); mysql_mutex_lock(&log_sys.flush_order_mutex);
/* Durably write the reduced FSP_SIZE before truncating the data file. */ /* Durably write the reduced FSP_SIZE before truncating the data file. */
@ -924,19 +933,10 @@ struct mtr_write_log
} }
}; };
/** Prepare to write the mini-transaction log to the redo log buffer. std::pair<lsn_t,mtr_t::page_flush_ahead> mtr_t::do_write()
@return number of bytes to write in finish_write() */
inline ulint mtr_t::prepare_write()
{ {
ut_ad(!recv_no_log_write); ut_ad(!recv_no_log_write);
ut_ad(m_log_mode == MTR_LOG_ALL);
if (UNIV_UNLIKELY(m_log_mode != MTR_LOG_ALL)) {
ut_ad(m_log_mode == MTR_LOG_NO_REDO);
ut_ad(m_log.size() == 0);
mysql_mutex_lock(&log_sys.mutex);
m_commit_lsn = log_sys.get_lsn();
return 0;
}
ulint len = m_log.size(); ulint len = m_log.size();
ut_ad(len > 0); ut_ad(len > 0);
@ -968,7 +968,7 @@ inline ulint mtr_t::prepare_write()
/* check and attempt a checkpoint if exceeding capacity */ /* check and attempt a checkpoint if exceeding capacity */
log_margin_checkpoint_age(len); log_margin_checkpoint_age(len);
return(len); return finish_write(len);
} }
/** Append the redo log records to the redo log buffer. /** Append the redo log records to the redo log buffer.