mirror of
https://github.com/MariaDB/server.git
synced 2025-12-09 08:01:34 +03:00
MDEV-25683 Atomic DDL: With innodb_force_recovery=3 InnoDB: Trying to load index but the index tree has been freed
The purpose of the parameter innodb_force_recovery is to allow some data to be dumped from a corrupted database. Its values used to be as follows: innodb_force_recovery=0: normal (default) innodb_force_recovery=1: ignore (skip log for) corrupted pages or missing data files when applying the redo log innodb_force_recovery=2: additionally, disable background tasks (such as the purge of committed undo logs) innodb_force_recovery=3: additionally, disable the rollback of recovered incomplete (not committed or XA PREPARE) transactions innodb_force_recovery=4: same as 3 (since MDEV-19514 in MariaDB 10.5) innodb_force_recovery=5: additionally, do not process any undo log, disallow any writes, and force READ UNCOMMITTED isolation level innodb_force_recovery=6: additionally, pretend that ib_logfile0 does not exist (prevent any recovery). Never use this! The bad thing that happens with innodb_force_recovery=3 and innodb_force_recovery=4 is that also the rollback of any recovered DDL transaction will be skipped. This would break the DDL log recovery that was introduced in MDEV-17567. For one data directory sample, the DDL log recovery would hangs due to a conflict on the InnoDB SYS_TABLES table, because the lock holder transaction was not rolled back due to innodb_force_recovery=3. Fix: Make innodb_force_recovery=3 skip the DML transaction rollback only, and make innodb_force_recovery=4 (renamed to SRV_FORCE_NO_DDL_UNDO) behave like innodb_force_recovery=3 used to (skip the rollback of all recovered transactions, both DML and DDL). Startup with innodb_force_recovery=4 will be unaffected by this change. (There may be hangs, possibly preceded by messages about failing to load an index.) Side note: With innodb_force_recovery=5, any DDL log for InnoDB tables will be essentially ignored by InnoDB, but the server will start up.
This commit is contained in:
@@ -3812,7 +3812,7 @@ dict_stats_update(
|
|||||||
|
|
||||||
if (!table->is_readable()) {
|
if (!table->is_readable()) {
|
||||||
return (dict_stats_report_error(table));
|
return (dict_stats_report_error(table));
|
||||||
} else if (srv_force_recovery > SRV_FORCE_NO_IBUF_MERGE) {
|
} else if (srv_force_recovery >= SRV_FORCE_NO_UNDO_LOG_SCAN) {
|
||||||
/* If we have set a high innodb_force_recovery level, do
|
/* If we have set a high innodb_force_recovery level, do
|
||||||
not calculate statistics, as a badly corrupted index can
|
not calculate statistics, as a badly corrupted index can
|
||||||
cause a crash in it. */
|
cause a crash in it. */
|
||||||
|
|||||||
@@ -5845,7 +5845,7 @@ initialize_auto_increment(dict_table_t* table, const Field* field)
|
|||||||
table->persistent_autoinc without
|
table->persistent_autoinc without
|
||||||
autoinc_mutex protection, and there might be multiple
|
autoinc_mutex protection, and there might be multiple
|
||||||
ha_innobase::open() executing concurrently. */
|
ha_innobase::open() executing concurrently. */
|
||||||
} else if (srv_force_recovery > SRV_FORCE_NO_IBUF_MERGE) {
|
} else if (srv_force_recovery >= SRV_FORCE_NO_UNDO_LOG_SCAN) {
|
||||||
/* If the recovery level is set so high that writes
|
/* If the recovery level is set so high that writes
|
||||||
are disabled we force the AUTOINC counter to 0
|
are disabled we force the AUTOINC counter to 0
|
||||||
value effectively disabling writes to the table.
|
value effectively disabling writes to the table.
|
||||||
@@ -14872,7 +14872,7 @@ ha_innobase::info_low(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (srv_force_recovery > SRV_FORCE_NO_IBUF_MERGE) {
|
if (srv_force_recovery >= SRV_FORCE_NO_UNDO_LOG_SCAN) {
|
||||||
|
|
||||||
goto func_exit;
|
goto func_exit;
|
||||||
|
|
||||||
|
|||||||
@@ -562,11 +562,9 @@ enum {
|
|||||||
SRV_FORCE_NO_BACKGROUND = 2, /*!< prevent the main thread from
|
SRV_FORCE_NO_BACKGROUND = 2, /*!< prevent the main thread from
|
||||||
running: if a crash would occur
|
running: if a crash would occur
|
||||||
in purge, this prevents it */
|
in purge, this prevents it */
|
||||||
SRV_FORCE_NO_TRX_UNDO = 3, /*!< do not run trx rollback after
|
SRV_FORCE_NO_TRX_UNDO = 3, /*!< do not run DML rollback after
|
||||||
recovery */
|
recovery */
|
||||||
SRV_FORCE_NO_IBUF_MERGE = 4, /*!< prevent also ibuf operations:
|
SRV_FORCE_NO_DDL_UNDO = 4, /*!< prevent also DDL rollback */
|
||||||
if they would cause a crash, better
|
|
||||||
not do them */
|
|
||||||
SRV_FORCE_NO_UNDO_LOG_SCAN = 5, /*!< do not look at undo logs when
|
SRV_FORCE_NO_UNDO_LOG_SCAN = 5, /*!< do not look at undo logs when
|
||||||
starting the database: InnoDB will
|
starting the database: InnoDB will
|
||||||
treat even incomplete transactions
|
treat even incomplete transactions
|
||||||
|
|||||||
@@ -1065,7 +1065,7 @@ dberr_t srv_start(bool create_new_db)
|
|||||||
}
|
}
|
||||||
|
|
||||||
high_level_read_only = srv_read_only_mode
|
high_level_read_only = srv_read_only_mode
|
||||||
|| srv_force_recovery > SRV_FORCE_NO_IBUF_MERGE
|
|| srv_force_recovery >= SRV_FORCE_NO_UNDO_LOG_SCAN
|
||||||
|| srv_sys_space.created_new_raw();
|
|| srv_sys_space.created_new_raw();
|
||||||
|
|
||||||
srv_started_redo = false;
|
srv_started_redo = false;
|
||||||
@@ -1704,7 +1704,7 @@ file_checked:
|
|||||||
|
|
||||||
if (!create_new_db) {
|
if (!create_new_db) {
|
||||||
ut_ad(high_level_read_only
|
ut_ad(high_level_read_only
|
||||||
|| srv_force_recovery <= SRV_FORCE_NO_IBUF_MERGE);
|
|| srv_force_recovery < SRV_FORCE_NO_UNDO_LOG_SCAN);
|
||||||
|
|
||||||
/* Validate a few system page types that were left
|
/* Validate a few system page types that were left
|
||||||
uninitialized before MySQL or MariaDB 5.5. */
|
uninitialized before MySQL or MariaDB 5.5. */
|
||||||
@@ -1745,7 +1745,7 @@ file_checked:
|
|||||||
should guarantee that there is at most one data
|
should guarantee that there is at most one data
|
||||||
dictionary transaction active at a time. */
|
dictionary transaction active at a time. */
|
||||||
if (!high_level_read_only
|
if (!high_level_read_only
|
||||||
&& srv_force_recovery < SRV_FORCE_NO_TRX_UNDO) {
|
&& srv_force_recovery <= SRV_FORCE_NO_TRX_UNDO) {
|
||||||
/* If the following call is ever removed, the
|
/* If the following call is ever removed, the
|
||||||
first-time ha_innobase::open() must hold (or
|
first-time ha_innobase::open() must hold (or
|
||||||
acquire and release) a table lock that
|
acquire and release) a table lock that
|
||||||
@@ -1759,7 +1759,7 @@ file_checked:
|
|||||||
trx_rollback_recovered(false);
|
trx_rollback_recovered(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (srv_force_recovery <= SRV_FORCE_NO_IBUF_MERGE) {
|
if (srv_force_recovery < SRV_FORCE_NO_UNDO_LOG_SCAN) {
|
||||||
/* The following call is necessary for the insert
|
/* The following call is necessary for the insert
|
||||||
buffer to work with multiple tablespaces. We must
|
buffer to work with multiple tablespaces. We must
|
||||||
know the mapping between space id's and .ibd file
|
know the mapping between space id's and .ibd file
|
||||||
|
|||||||
@@ -709,7 +709,8 @@ void trx_rollback_recovered(bool all)
|
|||||||
{
|
{
|
||||||
std::vector<trx_t*> trx_list;
|
std::vector<trx_t*> trx_list;
|
||||||
|
|
||||||
ut_a(srv_force_recovery < SRV_FORCE_NO_TRX_UNDO);
|
ut_a(srv_force_recovery <
|
||||||
|
(all ? SRV_FORCE_NO_TRX_UNDO : SRV_FORCE_NO_DDL_UNDO));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Collect list of recovered ACTIVE transaction ids first. Once collected, no
|
Collect list of recovered ACTIVE transaction ids first. Once collected, no
|
||||||
|
|||||||
Reference in New Issue
Block a user