summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarko Mäkelä <marko.makela@mariadb.com>2020-08-14 15:33:46 +0300
committerMarko Mäkelä <marko.makela@mariadb.com>2020-08-14 15:33:46 +0300
commit9d360e558ca24164e275cfc04d8fc15558f65bf0 (patch)
treededbc8465e2ec9e8fdabe41240a37f84106b0244
parent78c3a948b19ca805d3634bac8ce53dd0c05b3197 (diff)
downloadmariadb-git-bb-10.2-MDEV-23474.tar.gz
MDEV-23484 Rollback unnecessarily acquires dict_operation_lock for every rowbb-10.2-MDEV-23474
InnoDB transaction rollback includes an unnecessary work-around for a data corruption bug that was fixed by me in MySQL 5.6.12 mysql/mysql-server@935ba09d52c1908bde273ad1940b5ab919d9763d and ported to MariaDB 10.0.8 by commit c291ddfdf774b50c34b9741c6e39c57bae8fd1dc in 2013 and 2014, respectively. By acquiring and releasing dict_operation_lock in shared mode, row_undo() hopes to prevent the table from being dropped while the undo log record is being rolled back. But, thanks to mentioned fix, the rollback is guaranteed to be protected by transactional locks (table IX lock, in addition to implicit or explicit exclusive locks on the records that had been modified). Because row_drop_table_for_mysql() would invoke row_add_table_to_background_drop_list() if any locks exist on the table, the mere existence of locks (which is guaranteed during ROLLBACK) is enough to protect the table from disappearing. Hence, acquiring and releasing dict_operation_lock for every row that is being rolled back is unnecessary. row_undo(): Remove the unnecessary acquisition and release of dict_operation_lock. Note: row_add_table_to_background_drop_list() is mostly working around bugs outside InnoDB: MDEV-21175 (insufficient MDL protection of FOREIGN KEY operations) MDEV-21602 (incorrect error handling of CREATE TABLE...SELECT).
-rw-r--r--storage/innobase/row/row0uins.cc3
-rw-r--r--storage/innobase/row/row0umod.cc42
-rw-r--r--storage/innobase/row/row0undo.cc17
3 files changed, 4 insertions, 58 deletions
diff --git a/storage/innobase/row/row0uins.cc b/storage/innobase/row/row0uins.cc
index 54fa244fca6..4bdb9b03e1c 100644
--- a/storage/innobase/row/row0uins.cc
+++ b/storage/innobase/row/row0uins.cc
@@ -91,8 +91,7 @@ row_undo_ins_remove_clust_rec(
online = dict_index_is_online_ddl(index);
if (online) {
- ut_ad(node->trx->dict_operation_lock_mode
- != RW_X_LATCH);
+ ut_ad(!node->trx->dict_operation_lock_mode);
ut_ad(node->table->id != DICT_INDEXES_ID);
mtr_s_lock(dict_index_get_lock(index), &mtr);
}
diff --git a/storage/innobase/row/row0umod.cc b/storage/innobase/row/row0umod.cc
index 80d90f40379..a0c51627fe8 100644
--- a/storage/innobase/row/row0umod.cc
+++ b/storage/innobase/row/row0umod.cc
@@ -264,10 +264,7 @@ row_undo_mod_clust(
bool online;
ut_ad(thr_get_trx(thr) == node->trx);
- ut_ad(node->trx->dict_operation_lock_mode);
ut_ad(node->trx->in_rollback);
- ut_ad(rw_lock_own_flagged(&dict_operation_lock,
- RW_LOCK_FLAG_X | RW_LOCK_FLAG_S));
log_free_check();
pcur = &node->pcur;
@@ -282,7 +279,7 @@ row_undo_mod_clust(
online = dict_index_is_online_ddl(index);
if (online) {
- ut_ad(node->trx->dict_operation_lock_mode != RW_X_LATCH);
+ ut_ad(!node->trx->dict_operation_lock_mode);
mtr_s_lock(dict_index_get_lock(index), &mtr);
}
@@ -807,37 +804,6 @@ func_exit_no_pcur:
}
/***********************************************************//**
-Flags a secondary index corrupted. */
-static MY_ATTRIBUTE((nonnull))
-void
-row_undo_mod_sec_flag_corrupted(
-/*============================*/
- trx_t* trx, /*!< in/out: transaction */
- dict_index_t* index) /*!< in: secondary index */
-{
- ut_ad(!dict_index_is_clust(index));
-
- switch (trx->dict_operation_lock_mode) {
- case RW_S_LATCH:
- /* Because row_undo() is holding an S-latch
- on the data dictionary during normal rollback,
- we can only mark the index corrupted in the
- data dictionary cache. TODO: fix this somehow.*/
- mutex_enter(&dict_sys->mutex);
- dict_set_corrupted_index_cache_only(index);
- mutex_exit(&dict_sys->mutex);
- break;
- default:
- ut_ad(0);
- /* fall through */
- case RW_X_LATCH:
- /* This should be the rollback of a data dictionary
- transaction. */
- dict_set_corrupted(index, trx, "rollback");
- }
-}
-
-/***********************************************************//**
Undoes a modify in secondary indexes when undo record type is UPD_DEL.
@return DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
static MY_ATTRIBUTE((nonnull, warn_unused_result))
@@ -950,8 +916,7 @@ row_undo_mod_del_mark_sec(
}
if (err == DB_DUPLICATE_KEY) {
- row_undo_mod_sec_flag_corrupted(
- thr_get_trx(thr), index);
+ index->type |= DICT_CORRUPT;
err = DB_SUCCESS;
/* Do not return any error to the caller. The
duplicate will be reported by ALTER TABLE or
@@ -1097,8 +1062,7 @@ row_undo_mod_upd_exist_sec(
}
if (err == DB_DUPLICATE_KEY) {
- row_undo_mod_sec_flag_corrupted(
- thr_get_trx(thr), index);
+ index->type |= DICT_CORRUPT;
err = DB_SUCCESS;
} else if (err != DB_SUCCESS) {
break;
diff --git a/storage/innobase/row/row0undo.cc b/storage/innobase/row/row0undo.cc
index b65b173fedb..34b55f25527 100644
--- a/storage/innobase/row/row0undo.cc
+++ b/storage/innobase/row/row0undo.cc
@@ -279,18 +279,6 @@ row_undo(
? UNDO_NODE_INSERT : UNDO_NODE_MODIFY;
}
- /* Prevent DROP TABLE etc. while we are rolling back this row.
- If we are doing a TABLE CREATE or some other dictionary operation,
- then we already have dict_operation_lock locked in x-mode. Do not
- try to lock again, because that would cause a hang. */
-
- const bool locked_data_dict = (trx->dict_operation_lock_mode == 0);
-
- if (locked_data_dict) {
-
- row_mysql_freeze_data_dictionary(trx);
- }
-
dberr_t err;
if (node->state == UNDO_NODE_INSERT) {
@@ -303,11 +291,6 @@ row_undo(
err = row_undo_mod(node, thr);
}
- if (locked_data_dict) {
-
- row_mysql_unfreeze_data_dictionary(trx);
- }
-
/* Do some cleanup */
btr_pcur_close(&(node->pcur));