summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--storage/innobase/handler/handler0alter.cc4
-rw-r--r--storage/innobase/row/row0uins.cc7
-rw-r--r--storage/innobase/row/row0umod.cc57
-rw-r--r--storage/innobase/row/row0undo.cc22
4 files changed, 65 insertions, 25 deletions
diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc
index 44942bf164b..b766cac5dd5 100644
--- a/storage/innobase/handler/handler0alter.cc
+++ b/storage/innobase/handler/handler0alter.cc
@@ -8273,11 +8273,11 @@ ha_innobase::commit_inplace_alter_table(
/* Exclusively lock the table, to ensure that no other
transaction is holding locks on the table while we
- change the table definition. The meta-data lock (MDL)
+ change the table definition. The MySQL meta-data lock
should normally guarantee that no conflicting locks
exist. However, FOREIGN KEY constraints checks and any
transactions collected during crash recovery could be
- holding InnoDB locks only, not MDL. */
+ holding InnoDB locks only, not MySQL locks. */
dberr_t error = row_merge_lock_table(
m_prebuilt->trx, ctx->old_table, LOCK_X);
diff --git a/storage/innobase/row/row0uins.cc b/storage/innobase/row/row0uins.cc
index 7e5aac1ba9f..54fa244fca6 100644
--- a/storage/innobase/row/row0uins.cc
+++ b/storage/innobase/row/row0uins.cc
@@ -81,7 +81,6 @@ row_undo_ins_remove_clust_rec(
mtr.set_log_mode(MTR_LOG_NO_REDO);
} else {
mtr.set_named_space(index->space);
- ut_ad(lock_table_has_locks(index->table));
}
/* This is similar to row_undo_mod_clust(). The DDL thread may
@@ -92,7 +91,8 @@ row_undo_ins_remove_clust_rec(
online = dict_index_is_online_ddl(index);
if (online) {
- ut_ad(!node->trx->dict_operation_lock_mode);
+ ut_ad(node->trx->dict_operation_lock_mode
+ != RW_X_LATCH);
ut_ad(node->table->id != DICT_INDEXES_ID);
mtr_s_lock(dict_index_get_lock(index), &mtr);
}
@@ -491,9 +491,6 @@ row_undo_ins(
return(DB_SUCCESS);
}
- ut_ad(node->table->is_temporary()
- || lock_table_has_locks(node->table));
-
/* Iterate over all the indexes and undo the insert.*/
node->index = dict_table_get_first_index(node->table);
diff --git a/storage/innobase/row/row0umod.cc b/storage/innobase/row/row0umod.cc
index 0de0760834e..80d90f40379 100644
--- a/storage/innobase/row/row0umod.cc
+++ b/storage/innobase/row/row0umod.cc
@@ -264,7 +264,10 @@ 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;
@@ -275,12 +278,11 @@ row_undo_mod_clust(
mtr.set_log_mode(MTR_LOG_NO_REDO);
} else {
mtr.set_named_space(index->space);
- ut_ad(lock_table_has_locks(index->table));
}
online = dict_index_is_online_ddl(index);
if (online) {
- ut_ad(!node->trx->dict_operation_lock_mode);
+ ut_ad(node->trx->dict_operation_lock_mode != RW_X_LATCH);
mtr_s_lock(dict_index_get_lock(index), &mtr);
}
@@ -319,7 +321,17 @@ row_undo_mod_clust(
ut_ad(err == DB_SUCCESS || err == DB_OUT_OF_FILE_SPACE);
}
- if (err == DB_SUCCESS && online && dict_index_is_online_ddl(index)) {
+ /* Online rebuild cannot be initiated while we are holding
+ dict_operation_lock and index->lock. (It can be aborted.) */
+ ut_ad(online || !dict_index_is_online_ddl(index));
+
+ if (err == DB_SUCCESS && online) {
+
+ ut_ad(rw_lock_own_flagged(
+ &index->lock,
+ RW_LOCK_FLAG_S | RW_LOCK_FLAG_X
+ | RW_LOCK_FLAG_SX));
+
switch (node->rec_type) {
case TRX_UNDO_DEL_MARK_REC:
row_log_table_insert(
@@ -795,6 +807,37 @@ 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))
@@ -907,7 +950,8 @@ row_undo_mod_del_mark_sec(
}
if (err == DB_DUPLICATE_KEY) {
- index->type |= DICT_CORRUPT;
+ row_undo_mod_sec_flag_corrupted(
+ thr_get_trx(thr), index);
err = DB_SUCCESS;
/* Do not return any error to the caller. The
duplicate will be reported by ALTER TABLE or
@@ -1053,7 +1097,8 @@ row_undo_mod_upd_exist_sec(
}
if (err == DB_DUPLICATE_KEY) {
- index->type |= DICT_CORRUPT;
+ row_undo_mod_sec_flag_corrupted(
+ thr_get_trx(thr), index);
err = DB_SUCCESS;
} else if (err != DB_SUCCESS) {
break;
@@ -1205,8 +1250,6 @@ row_undo_mod(
return(DB_SUCCESS);
}
- ut_ad(node->table->is_temporary()
- || lock_table_has_locks(node->table));
node->index = dict_table_get_first_index(node->table);
ut_ad(dict_index_is_clust(node->index));
/* Skip the clustered index (the first index) */
diff --git a/storage/innobase/row/row0undo.cc b/storage/innobase/row/row0undo.cc
index 185a71e670b..b65b173fedb 100644
--- a/storage/innobase/row/row0undo.cc
+++ b/storage/innobase/row/row0undo.cc
@@ -279,16 +279,15 @@ row_undo(
? UNDO_NODE_INSERT : UNDO_NODE_MODIFY;
}
- /* Prevent prepare_inplace_alter_table_dict() from adding
- dict_table_t::indexes while we are processing the record.
- Recovered transactions are not protected by MDL, and the
- secondary index creation is not protected by table locks
- for online operation. (A table lock would only be acquired
- when committing the ALTER TABLE operation.) */
- const bool locked_data_dict = UNIV_UNLIKELY(trx->is_recovered)
- && !trx->dict_operation_lock_mode;
-
- if (UNIV_UNLIKELY(locked_data_dict)) {
+ /* 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);
}
@@ -304,7 +303,8 @@ row_undo(
err = row_undo_mod(node, thr);
}
- if (UNIV_UNLIKELY(locked_data_dict)) {
+ if (locked_data_dict) {
+
row_mysql_unfreeze_data_dictionary(trx);
}