diff options
author | Marko Mäkelä <marko.makela@mariadb.com> | 2021-10-29 10:20:58 +0300 |
---|---|---|
committer | Marko Mäkelä <marko.makela@mariadb.com> | 2021-10-29 10:20:58 +0300 |
commit | dbd6c6dc01228fe6e63f3f7dc695eb56ca8cd28d (patch) | |
tree | 759a48f4054861ea2a350fc91a442ad6be3c6ab0 | |
parent | ea45f0ebfb2193fa5b578c1463dae79ff8940f29 (diff) | |
download | mariadb-git-dbd6c6dc01228fe6e63f3f7dc695eb56ca8cd28d.tar.gz |
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.
-rw-r--r-- | storage/innobase/dict/dict0stats.cc | 2 | ||||
-rw-r--r-- | storage/innobase/handler/ha_innodb.cc | 4 | ||||
-rw-r--r-- | storage/innobase/include/srv0srv.h | 6 | ||||
-rw-r--r-- | storage/innobase/srv/srv0start.cc | 8 | ||||
-rw-r--r-- | storage/innobase/trx/trx0roll.cc | 3 |
5 files changed, 11 insertions, 12 deletions
diff --git a/storage/innobase/dict/dict0stats.cc b/storage/innobase/dict/dict0stats.cc index f92beac0f67..0af5982806f 100644 --- a/storage/innobase/dict/dict0stats.cc +++ b/storage/innobase/dict/dict0stats.cc @@ -3812,7 +3812,7 @@ dict_stats_update( if (!table->is_readable()) { 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 not calculate statistics, as a badly corrupted index can cause a crash in it. */ diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index b508d0246e7..64ecc7ae957 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -5845,7 +5845,7 @@ initialize_auto_increment(dict_table_t* table, const Field* field) table->persistent_autoinc without autoinc_mutex protection, and there might be multiple 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 are disabled we force the AUTOINC counter to 0 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; diff --git a/storage/innobase/include/srv0srv.h b/storage/innobase/include/srv0srv.h index 0c32d5d686a..be25bc86519 100644 --- a/storage/innobase/include/srv0srv.h +++ b/storage/innobase/include/srv0srv.h @@ -562,11 +562,9 @@ enum { SRV_FORCE_NO_BACKGROUND = 2, /*!< prevent the main thread from running: if a crash would occur 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 */ - SRV_FORCE_NO_IBUF_MERGE = 4, /*!< prevent also ibuf operations: - if they would cause a crash, better - not do them */ + SRV_FORCE_NO_DDL_UNDO = 4, /*!< prevent also DDL rollback */ SRV_FORCE_NO_UNDO_LOG_SCAN = 5, /*!< do not look at undo logs when starting the database: InnoDB will treat even incomplete transactions diff --git a/storage/innobase/srv/srv0start.cc b/storage/innobase/srv/srv0start.cc index 3f0ccf44b1e..1fc5905ce26 100644 --- a/storage/innobase/srv/srv0start.cc +++ b/storage/innobase/srv/srv0start.cc @@ -1065,7 +1065,7 @@ dberr_t srv_start(bool create_new_db) } 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_started_redo = false; @@ -1704,7 +1704,7 @@ file_checked: if (!create_new_db) { 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 uninitialized before MySQL or MariaDB 5.5. */ @@ -1745,7 +1745,7 @@ file_checked: should guarantee that there is at most one data dictionary transaction active at a time. */ 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 first-time ha_innobase::open() must hold (or acquire and release) a table lock that @@ -1759,7 +1759,7 @@ file_checked: 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 buffer to work with multiple tablespaces. We must know the mapping between space id's and .ibd file diff --git a/storage/innobase/trx/trx0roll.cc b/storage/innobase/trx/trx0roll.cc index a0582413d07..34e623b6b1a 100644 --- a/storage/innobase/trx/trx0roll.cc +++ b/storage/innobase/trx/trx0roll.cc @@ -709,7 +709,8 @@ void trx_rollback_recovered(bool all) { 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 |