Skip to content

Commit

Permalink
MDEV-25683 Atomic DDL: With innodb_force_recovery=3 InnoDB: Trying to…
Browse files Browse the repository at this point in the history
… 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.
  • Loading branch information
dr-m committed Oct 29, 2021
1 parent ea45f0e commit dbd6c6d
Show file tree
Hide file tree
Showing 5 changed files with 11 additions and 12 deletions.
2 changes: 1 addition & 1 deletion storage/innobase/dict/dict0stats.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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. */
Expand Down
4 changes: 2 additions & 2 deletions storage/innobase/handler/ha_innodb.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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;

Expand Down
6 changes: 2 additions & 4 deletions storage/innobase/include/srv0srv.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 4 additions & 4 deletions storage/innobase/srv/srv0start.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -1704,7 +1704,7 @@ dberr_t srv_start(bool create_new_db)

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. */
Expand Down Expand Up @@ -1745,7 +1745,7 @@ dberr_t srv_start(bool create_new_db)
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
Expand All @@ -1759,7 +1759,7 @@ dberr_t srv_start(bool create_new_db)
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
Expand Down
3 changes: 2 additions & 1 deletion storage/innobase/trx/trx0roll.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit dbd6c6d

Please sign in to comment.