Skip to content

Commit 01095c8

Browse files
committed
MDEV-40063 Corruption due to race in SET GLOBAL innodb_log_archive=ON
There was a race condition between log_t::write_checkpoint() and the execution of SET GLOBAL innodb_log_archive=ON (enabling log archiving). We had wrongly allowed the concurrent execution of log_t::set_archive() and log_t::write_checkpoint(). The result was that log_sys.next_checkpoint_no was corrupted. This could have broken crash recovery. log_t::write_checkpoint(): When we are releasing log_sys.latch while durably writing the checkpoint header block, assign log_sys.resize_log to log_sys.log to inform other threads that a checkpoint is in progress. Previously, we only did this when innodb_log_archive=ON holds. log_t::resize_start(): Relax a debug assertion for the logic change. Tested by: Matthias Leich
1 parent 72e0f9c commit 01095c8

2 files changed

Lines changed: 16 additions & 11 deletions

File tree

storage/innobase/buf/buf0flu.cc

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1993,8 +1993,6 @@ inline lsn_t log_t::write_checkpoint(lsn_t checkpoint, lsn_t end_lsn) noexcept
19931993
(C[-1] && my_betoh64(C[-1]) < d));
19941994
ut_ad(!*C || offset + o == START_OFFSET - 8);
19951995
*C= my_htobe64(d);
1996-
if (resize_log.m_file == OS_FILE_CLOSED)
1997-
resize_log= log; /* Block concurrent set_archive() */
19981996
goto write_checkpoint;
19991997
}
20001998

@@ -2029,6 +2027,8 @@ inline lsn_t log_t::write_checkpoint(lsn_t checkpoint, lsn_t end_lsn) noexcept
20292027
{
20302028
write_checkpoint:
20312029
ut_ad(!is_mmap());
2030+
if (resize_log.m_file == OS_FILE_CLOSED)
2031+
resize_log= log; /* Block concurrent set_archive() */
20322032
latch.wr_unlock();
20332033
log_write_and_flush_prepare();
20342034
resizing= resize_lsn.load(std::memory_order_relaxed);
@@ -2059,7 +2059,18 @@ inline lsn_t log_t::write_checkpoint(lsn_t checkpoint, lsn_t end_lsn) noexcept
20592059
last_checkpoint_lsn= checkpoint;
20602060
this->end_lsn= end_lsn;
20612061
if (!archive)
2062+
{
20622063
archived_lsn= end_lsn;
2064+
checkpoint_completed:
2065+
if (resize_log.m_file == log.m_file)
2066+
{
2067+
/* We may have assigned resize_log= log to keep set_archived() out. */
2068+
#ifdef HAVE_PMEM
2069+
ut_ad(!is_mmap());
2070+
#endif
2071+
resize_log.m_file= OS_FILE_CLOSED;
2072+
}
2073+
}
20632074
else if (archive_header_was_reset)
20642075
{
20652076
ut_ad(resize_log.m_file != log.m_file);
@@ -2080,14 +2091,8 @@ inline lsn_t log_t::write_checkpoint(lsn_t checkpoint, lsn_t end_lsn) noexcept
20802091
resize_log.close();
20812092
#endif
20822093
}
2083-
else if (resize_log.m_file == log.m_file)
2084-
{
2085-
/* We may have assigned resize_log= log to keep set_archived() out. */
2086-
#ifdef HAVE_PMEM
2087-
ut_ad(!is_mmap());
2088-
#endif
2089-
resize_log.m_file= OS_FILE_CLOSED;
2090-
}
2094+
else
2095+
goto checkpoint_completed;
20912096

20922097
DBUG_PRINT("ib_log", ("checkpoint ended at " LSN_PF ", flushed to " LSN_PF,
20932098
checkpoint, get_flushed_lsn()));

storage/innobase/log/log0log.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -993,7 +993,7 @@ log_t::resize_start_status log_t::resize_start(os_offset_t size, void *thd)
993993
{
994994
lsn_t start_lsn;
995995
ut_ad(!resize_in_progress());
996-
ut_ad(!resize_log.is_opened());
996+
ut_ad(!resize_log.is_opened() || resize_log.m_file == log.m_file);
997997
ut_ad(!resize_buf);
998998
ut_ad(!resize_flush_buf);
999999
ut_ad(!resize_initiator);

0 commit comments

Comments
 (0)