From 42f657cd2fab9acb00b15e00c7cc630f64ecc6ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Fri, 7 Jul 2017 18:29:31 +0300 Subject: [PATCH] MDEV-13267 At startup with crash recovery: mtr_t::commit_checkpoint(lsn_t, bool): Assertion `!recv_no_log_write' failed This is a bogus debug assertion failure that should be possible starting with MariaDB 10.2.2 (which merged WL#7142 via MySQL 5.7.9). While generating page-change redo log records is strictly out of the question during tat certain parts of crash recovery, the fil_names_clear() is only emitting informational MLOG_FILE_NAME and MLOG_CHECKPOINT records to guarantee that if the server is killed during or soon after the crash recovery, subsequent crash recovery will be possible. The metadata buffer that fil_names_clear() is flushing to the redo log is being filled by recv_init_crash_recovery_spaces(), right before starting to apply redo log, by invoking fil_names_dirty() on every discovered tablespace for which there are changes to apply. When it comes to Mariabackup (xtrabackup --prepare), it is strictly out of the question to generate any redo log whatsoever, because that could break the restore of incremental backups by causing LSN deviation. So, the fil_names_dirty() call must be skipped when restoring backups. recv_recovery_from_checkpoint_start(): Do not invoke fil_names_clear() when restoring a backup. mtr_t::commit_checkpoint(): Remove the failing assertion. The only caller is fil_names_clear(), and it must be called by recv_recovery_from_checkpoint_start() for normal server startup to be crash-safe. The debug assertion in mtr_t::commit() will still catch rogue redo log writes. --- storage/innobase/log/log0recv.cc | 9 +++++++-- storage/innobase/mtr/mtr0mtr.cc | 3 --- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/storage/innobase/log/log0recv.cc b/storage/innobase/log/log0recv.cc index ff7523a295447..dc8977e49c82c 100644 --- a/storage/innobase/log/log0recv.cc +++ b/storage/innobase/log/log0recv.cc @@ -3126,6 +3126,9 @@ recv_recovery_from_checkpoint_start(lsn_t flush_lsn) byte* buf; dberr_t err = DB_SUCCESS; + ut_ad(srv_operation == SRV_OPERATION_NORMAL + || srv_operation == SRV_OPERATION_RESTORE); + /* Initialize red-black tree for fast insertions into the flush_list during recovery process. */ buf_flush_init_flush_rbt(); @@ -3342,9 +3345,11 @@ recv_recovery_from_checkpoint_start(lsn_t flush_lsn) log_sys->last_checkpoint_lsn = checkpoint_lsn; - if (!srv_read_only_mode) { + if (!srv_read_only_mode && srv_operation == SRV_OPERATION_NORMAL) { /* Write a MLOG_CHECKPOINT marker as the first thing, - before generating any other redo log. */ + before generating any other redo log. This ensures + that subsequent crash recovery will be possible even + if the server were killed soon after this. */ fil_names_clear(log_sys->last_checkpoint_lsn, true); } diff --git a/storage/innobase/mtr/mtr0mtr.cc b/storage/innobase/mtr/mtr0mtr.cc index e050694bb861c..0b9185ba5082c 100644 --- a/storage/innobase/mtr/mtr0mtr.cc +++ b/storage/innobase/mtr/mtr0mtr.cc @@ -599,9 +599,6 @@ mtr_t::commit_checkpoint( ut_d(m_impl.m_state = MTR_STATE_COMMITTING); ut_ad(write_mlog_checkpoint || m_impl.m_n_log_recs > 1); - /* This is a dirty read, for debugging. */ - ut_ad(!recv_no_log_write); - switch (m_impl.m_n_log_recs) { case 0: break;