1
0
mirror of https://github.com/MariaDB/server.git synced 2026-10-23 18:49:29 +03:00

MDEV-41318 Incorrect recovery of FILE_CREATE after FILE_RENAME

recv_recovery_from_checkpoint_start(): Before applying any page-level
log records by invoking recv_scan_log(true, parser), invoke
recv_rename_files() to replay FILE_RENAME records. In this way,
recv_sys_t::recover_deferred() will not overwrite any old data files
that had been renamed before a new file was created.

recv_sys_t::validate_checkpoint(): Refer to recv_sys.scanned_lsn
rather than recv_sys.lsn, because recv_scan_log(false, parser)
may reset the latter to rewound_lsn in case we run out of memory for
recv_sys.pages. In any case, the second call to recv_scan_log() will
proceed to the end of the log and parse all records.

Reviewed by: Thirunarayanan Balathandayuthapani
This commit is contained in:
Marko Mäkelä
2026-10-12 08:28:06 +03:00
parent 507a7217d3
commit 7aecfef107

View File

@@ -4743,13 +4743,13 @@ inline void log_t::set_recovered() noexcept
inline bool recv_sys_t::validate_checkpoint() const noexcept
{
const lsn_t last_checkpoint_lsn{log_sys.last_checkpoint_lsn};
if (lsn >= file_checkpoint && lsn >= last_checkpoint_lsn)
if (scanned_lsn >= file_checkpoint && scanned_lsn >= last_checkpoint_lsn)
return false;
sql_print_error("InnoDB: The log was only scanned up to "
LSN_PF ", while the current LSN at the "
"time of the latest checkpoint " LSN_PF
" was " LSN_PF "!",
lsn, last_checkpoint_lsn, file_checkpoint);
scanned_lsn, last_checkpoint_lsn, file_checkpoint);
return true;
}
@@ -4818,11 +4818,7 @@ func_exit:
parser[true] = get_parse_mmap<recv_sys_t::store::YES>();
recv_scan_log(false, parser);
if (recv_needed_recovery) {
read_only_recovery:
sql_print_warning("InnoDB: innodb_read_only"
" prevents crash recovery");
err = DB_READ_ONLY;
goto func_exit;
goto read_only_recovery;
}
if (recv_sys.is_corrupt_log()) {
sql_print_error("InnoDB: Log scan aborted at LSN "
@@ -4841,19 +4837,27 @@ read_only_recovery:
}
rescan = recv_scan_log(false, parser);
if (srv_read_only_mode && recv_needed_recovery) {
goto read_only_recovery;
}
if ((recv_sys.is_corrupt_log() && !srv_force_recovery)
|| recv_sys.is_corrupt_fs()) {
|| recv_sys.is_corrupt_fs()
|| recv_sys.validate_checkpoint()) {
goto err_exit;
}
}
ut_ad(recv_sys.scanned_lsn >= recv_sys.lsn);
ut_ad(recv_sys.scanned_lsn == recv_sys.lsn || rescan);
log_sys.set_recovered_lsn(recv_sys.scanned_lsn);
if (recv_needed_recovery) {
if (srv_read_only_mode) {
read_only_recovery:
sql_print_warning("InnoDB: innodb_read_only"
" prevents crash recovery");
err = DB_READ_ONLY;
goto func_exit;
}
bool missing_tablespace = false;
err = recv_init_crash_recovery_spaces(
@@ -4910,59 +4914,46 @@ read_only_recovery:
}
ut_ad(srv_force_recovery <= SRV_FORCE_NO_UNDO_LOG_SCAN);
if (rescan) {
recv_scan_log(true, parser);
if ((recv_sys.is_corrupt_log()
&& !srv_force_recovery)
|| recv_sys.is_corrupt_fs()) {
goto err_exit;
}
/* In case of multi-batch recovery,
redo log for the last batch is not
applied yet. */
ut_d(recv_sys.after_apply = false);
}
} else {
ut_ad(recv_sys.pages.empty());
}
if (!log_sys.is_recoverable()) {
} else if (recv_sys.validate_checkpoint()) {
err_exit:
err = DB_ERROR;
goto func_exit;
}
if (!srv_read_only_mode && log_sys.is_recoverable()) {
log_sys.set_recovered();
}
DBUG_EXECUTE_IF("before_final_redo_apply", goto err_exit;);
mysql_mutex_lock(&recv_sys.mutex);
if (UNIV_UNLIKELY(recv_sys.scanned_lsn != recv_sys.lsn)
&& log_sys.is_recoverable()) {
ut_ad("log parsing error" == 0);
mysql_mutex_unlock(&recv_sys.mutex);
err = DB_CORRUPTION;
goto func_exit;
}
recv_sys.apply_log_recs = true;
recv_no_ibuf_operations = false;
ut_d(recv_no_log_write = srv_operation == SRV_OPERATION_RESTORE
|| srv_operation == SRV_OPERATION_RESTORE_EXPORT);
if (srv_operation == SRV_OPERATION_NORMAL) {
err = recv_rename_files();
}
mysql_mutex_unlock(&recv_sys.mutex);
if (err != DB_SUCCESS) {
goto func_exit;
}
if (rescan) {
recv_scan_log(true, parser);
if ((recv_sys.is_corrupt_log() && !srv_force_recovery)
|| recv_sys.is_corrupt_fs()) {
err_exit:
err = DB_ERROR;
goto func_exit;
}
/* In case of multi-batch recovery, redo log
for the last batch is not applied yet. */
ut_d(recv_sys.after_apply = false);
}
ut_ad(recv_sys.scanned_lsn == recv_sys.lsn);
recv_sys.apply_log_recs = true;
recv_no_ibuf_operations = false;
log_sys.set_recovered();
/* The database is now ready to start almost normal processing of user
transactions: transaction rollbacks and the application of the log
records in the hash table can be run in background. */
if (err == DB_SUCCESS && deferred_spaces.reinit_all()
&& !srv_force_recovery) {
if (deferred_spaces.reinit_all() && !srv_force_recovery) {
err = DB_CORRUPTION;
}