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:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user