From ab448d4b342a3b33abe73c14ad92c8dafbb2a6a7 Mon Sep 17 00:00:00 2001 From: Thirunarayanan Balathandayuthapani Date: Thu, 20 Jun 2024 17:54:57 +0530 Subject: [PATCH] MDEV-34389 Avoid log overwrite in early recovery - InnoDB tries to write FILE_CHECKPOINT marker during early recovery when log file size is insufficient. While updating the log checkpoint at the end of the recovery, InnoDB must already have written out all pending changes to the persistent files. To complete the checkpoint, InnoDB has to write some log records for the checkpoint and to update the checkpoint header. If the server gets killed before updating the checkpoint header then it would lead the logfile to be unrecoverable. - This patch avoids FILE_CHECKPOINT marker during early recovery and narrows down the window of opportunity to make the log file unrecoverable. --- .../suite/innodb/r/log_file_overwrite.result | 8 ++++++++ .../suite/innodb/t/log_file_overwrite.test | 17 +++++++++++++++++ storage/innobase/log/log0recv.cc | 7 ++++++- 3 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 mysql-test/suite/innodb/r/log_file_overwrite.result create mode 100644 mysql-test/suite/innodb/t/log_file_overwrite.test diff --git a/mysql-test/suite/innodb/r/log_file_overwrite.result b/mysql-test/suite/innodb/r/log_file_overwrite.result new file mode 100644 index 00000000000..5f1f38784f6 --- /dev/null +++ b/mysql-test/suite/innodb/r/log_file_overwrite.result @@ -0,0 +1,8 @@ +call mtr.add_suppression("InnoDB: Plugin initialization aborted"); +call mtr.add_suppression("plugin 'InnoDB' registration as a STORAGE ENGINE failed."); +CREATE TABLE t1(f1 INT NOT NULL, f2 TEXT)ENGINE=InnoDB; +# restart: --debug_dbug=+d,ib_log_checkpoint_avoid_hard --innodb_flush_sync=0 +INSERT INTO t1 SELECT seq, repeat('a', 4000) FROM seq_1_to_1800; +# restart: --debug_dbug=+d,before_final_redo_apply --innodb_log_file_size=8M +# restart: --innodb_log_file_size=10M +DROP TABLE t1; diff --git a/mysql-test/suite/innodb/t/log_file_overwrite.test b/mysql-test/suite/innodb/t/log_file_overwrite.test new file mode 100644 index 00000000000..209f21c67cd --- /dev/null +++ b/mysql-test/suite/innodb/t/log_file_overwrite.test @@ -0,0 +1,17 @@ +--source include/have_innodb.inc +--source include/have_sequence.inc +--source include/have_debug.inc + +call mtr.add_suppression("InnoDB: Plugin initialization aborted"); +call mtr.add_suppression("plugin 'InnoDB' registration as a STORAGE ENGINE failed."); +CREATE TABLE t1(f1 INT NOT NULL, f2 TEXT)ENGINE=InnoDB; +let $restart_parameters=--debug_dbug=+d,ib_log_checkpoint_avoid_hard --innodb_flush_sync=0; +--source include/restart_mysqld.inc +INSERT INTO t1 SELECT seq, repeat('a', 4000) FROM seq_1_to_1800; +let $restart_parameters=--debug_dbug=+d,before_final_redo_apply --innodb_log_file_size=8M; +let $shutdown_timeout=0; +--source include/restart_mysqld.inc +let $restart_parameters=--innodb_log_file_size=10M; +let $shutdown_timeout=; +--source include/restart_mysqld.inc +DROP TABLE t1; diff --git a/storage/innobase/log/log0recv.cc b/storage/innobase/log/log0recv.cc index f83f5f45af6..366cf524f41 100644 --- a/storage/innobase/log/log0recv.cc +++ b/storage/innobase/log/log0recv.cc @@ -3738,7 +3738,9 @@ completed: if (!srv_read_only_mode && srv_operation <= SRV_OPERATION_EXPORT_RESTORED && (~log_t::FORMAT_ENCRYPTED & log_sys.log.format) - == log_t::FORMAT_10_5) { + == log_t::FORMAT_10_5 + && recv_sys.recovered_lsn - log_sys.last_checkpoint_lsn + < log_sys.log_capacity) { /* Write a FILE_CHECKPOINT marker as the first thing, before generating any other redo log. This ensures that subsequent crash recovery will be possible even @@ -3748,6 +3750,9 @@ completed: log_sys.next_checkpoint_no = ++checkpoint_no; + DBUG_EXECUTE_IF("before_final_redo_apply", + mysql_mutex_unlock(&log_sys.mutex); + return DB_ERROR;); mutex_enter(&recv_sys.mutex); recv_sys.apply_log_recs = true;