summaryrefslogtreecommitdiff
path: root/storage/innobase/row/row0vers.cc
diff options
context:
space:
mode:
authorThirunarayanan Balathandayuthapani <thiru@mariadb.com>2018-07-06 17:13:53 +0300
committerMarko Mäkelä <marko.makela@mariadb.com>2018-07-06 17:13:53 +0300
commit8b0d4cff0760b0a35285c315d82c49631c108baf (patch)
treee04a349e07fb23b7db1095f330d1c61dccdf1192 /storage/innobase/row/row0vers.cc
parente3207b6c132666e734adcd6e4c8485b1580039c4 (diff)
downloadmariadb-git-8b0d4cff0760b0a35285c315d82c49631c108baf.tar.gz
MDEV-15855 Deadlock between purge thread and DDL statement
Problem: ======== Truncate operation holds MDL on the table (t1) and tries to acquire InnoDB dict_operation_lock. Purge holds dict_operation_lock and tries to acquire MDL on the table (t1) to evaluate virtual column expressions for indexed virtual columns. It leads to deadlock of purge and truncate table (DDL). Solution: ========= If purge tries to acquire MDL on the table then it should do the following: i) Purge should release all innodb latches (including dict_operation_lock) before acquiring metadata lock on the table. ii) After acquiring metadata lock on the table, it should check whether the table was dropped or renamed. If the table is dropped then purge should ignore the undo log record. If the table is renamed then it should release the old MDL and acquire MDL on the new name. iii) Once purge acquires MDL, it should use the SQL table handle for all the remaining virtual index for the purge record. purge_node_t: Introduce new virtual column information to know whether the MDL was acquired successfully. This is joint work with Marko Mäkelä.
Diffstat (limited to 'storage/innobase/row/row0vers.cc')
-rw-r--r--storage/innobase/row/row0vers.cc146
1 files changed, 97 insertions, 49 deletions
diff --git a/storage/innobase/row/row0vers.cc b/storage/innobase/row/row0vers.cc
index aebcf70715f..9ced22fd54b 100644
--- a/storage/innobase/row/row0vers.cc
+++ b/storage/innobase/row/row0vers.cc
@@ -436,14 +436,16 @@ row_vers_must_preserve_del_marked(
@param[in,out] row the cluster index row in dtuple form
@param[in] clust_index clustered index
@param[in] index the secondary index
-@param[in] heap heap used to build virtual dtuple */
+@param[in] heap heap used to build virtual dtuple
+@param[in,out] vcol_info virtual column information. */
static
void
row_vers_build_clust_v_col(
- dtuple_t* row,
- dict_index_t* clust_index,
- dict_index_t* index,
- mem_heap_t* heap)
+ dtuple_t* row,
+ dict_index_t* clust_index,
+ dict_index_t* index,
+ mem_heap_t* heap,
+ purge_vcol_info_t* vcol_info)
{
mem_heap_t* local_heap = NULL;
VCOL_STORAGE *vcol_storage= NULL;
@@ -453,12 +455,23 @@ row_vers_build_clust_v_col(
ut_ad(dict_index_has_virtual(index));
+ if (vcol_info != NULL) {
+ vcol_info->set_used();
+ maria_table = vcol_info->mariadb_table;
+ }
+
innobase_allocate_row_for_vcol(thd, index,
&local_heap,
&maria_table,
&record,
&vcol_storage);
+ if (vcol_info && !vcol_info->mariadb_table) {
+ vcol_info->mariadb_table = maria_table;
+ ut_ad(!maria_table || vcol_info->is_first_fetch());
+ goto func_exit;
+ }
+
for (ulint i = 0; i < dict_index_get_n_fields(index); i++) {
const dict_field_t* ind_field = dict_index_get_nth_field(
index, i);
@@ -476,6 +489,7 @@ row_vers_build_clust_v_col(
}
}
+func_exit:
if (local_heap) {
if (vcol_storage)
innobase_free_row_for_vcol(vcol_storage);
@@ -497,16 +511,16 @@ row_vers_build_clust_v_col(
static
void
row_vers_build_cur_vrow_low(
- bool in_purge,
- const rec_t* rec,
- dict_index_t* clust_index,
- ulint* clust_offsets,
- dict_index_t* index,
- roll_ptr_t roll_ptr,
- trx_id_t trx_id,
- mem_heap_t* v_heap,
- const dtuple_t**vrow,
- mtr_t* mtr)
+ bool in_purge,
+ const rec_t* rec,
+ dict_index_t* clust_index,
+ ulint* clust_offsets,
+ dict_index_t* index,
+ roll_ptr_t roll_ptr,
+ trx_id_t trx_id,
+ mem_heap_t* v_heap,
+ const dtuple_t** vrow,
+ mtr_t* mtr)
{
const rec_t* version;
rec_t* prev_version;
@@ -784,21 +798,23 @@ func_exit:
@param[in,out] heap heap memory
@param[in,out] v_heap heap memory to keep virtual colum dtuple
@param[in] mtr mtr holding the latch on rec
+@param[in,out] vcol_info virtual column information for purge thread
@return dtuple contains virtual column data */
static
const dtuple_t*
row_vers_build_cur_vrow(
- bool in_purge,
- const rec_t* rec,
- dict_index_t* clust_index,
- ulint** clust_offsets,
- dict_index_t* index,
- const dtuple_t* ientry,
- roll_ptr_t roll_ptr,
- trx_id_t trx_id,
- mem_heap_t* heap,
- mem_heap_t* v_heap,
- mtr_t* mtr)
+ bool in_purge,
+ const rec_t* rec,
+ dict_index_t* clust_index,
+ ulint** clust_offsets,
+ dict_index_t* index,
+ const dtuple_t* ientry,
+ roll_ptr_t roll_ptr,
+ trx_id_t trx_id,
+ mem_heap_t* heap,
+ mem_heap_t* v_heap,
+ mtr_t* mtr,
+ purge_vcol_info_t* vcol_info)
{
const dtuple_t* cur_vrow = NULL;
@@ -818,8 +834,17 @@ row_vers_build_cur_vrow(
rec, *clust_offsets,
NULL, NULL, NULL, NULL, heap);
+ if (vcol_info && !vcol_info->used) {
+ mtr->commit();
+ }
+
row_vers_build_clust_v_col(
- row, clust_index, index, heap);
+ row, clust_index, index, heap, vcol_info);
+
+ if (vcol_info != NULL && vcol_info->is_first_fetch()) {
+ return NULL;
+ }
+
cur_vrow = dtuple_copy(row, v_heap);
dtuple_dup_v_fld(cur_vrow, v_heap);
} else {
@@ -834,27 +859,34 @@ row_vers_build_cur_vrow(
return(cur_vrow);
}
-/*****************************************************************//**
-Finds out if a version of the record, where the version >= the current
+/** Finds out if a version of the record, where the version >= the current
purge view, should have ientry as its secondary index entry. We check
if there is any not delete marked version of the record where the trx
-id >= purge view, and the secondary index entry and ientry are identified in
-the alphabetical ordering; exactly in this case we return TRUE.
+id >= purge view, and the secondary index entry == ientry; exactly in
+this case we return TRUE.
+@param[in] also_curr TRUE if also rec is included in the versions
+ to search; otherwise only versions prior
+ to it are searched
+@param[in] rec record in the clustered index; the caller
+ must have a latch on the page
+@param[in] mtr mtr holding the latch on rec; it will
+ also hold the latch on purge_view
+@param[in] index secondary index
+@param[in] ientry secondary index entry
+@param[in] roll_ptr roll_ptr for the purge record
+@param[in] trx_id transaction ID on the purging record
+@param[in,out] vcol_info virtual column information for purge thread.
@return TRUE if earlier version should have */
-ibool
+bool
row_vers_old_has_index_entry(
-/*=========================*/
- ibool also_curr,/*!< in: TRUE if also rec is included in the
- versions to search; otherwise only versions
- prior to it are searched */
- const rec_t* rec, /*!< in: record in the clustered index; the
- caller must have a latch on the page */
- mtr_t* mtr, /*!< in: mtr holding the latch on rec; it will
- also hold the latch on purge_view */
- dict_index_t* index, /*!< in: the secondary index */
- const dtuple_t* ientry, /*!< in: the secondary index entry */
- roll_ptr_t roll_ptr,/*!< in: roll_ptr for the purge record */
- trx_id_t trx_id) /*!< in: transaction ID on the purging record */
+ bool also_curr,
+ const rec_t* rec,
+ mtr_t* mtr,
+ dict_index_t* index,
+ const dtuple_t* ientry,
+ roll_ptr_t roll_ptr,
+ trx_id_t trx_id,
+ purge_vcol_info_t* vcol_info)
{
const rec_t* version;
rec_t* prev_version;
@@ -922,8 +954,18 @@ row_vers_old_has_index_entry(
columns need to be computed */
if (trx_undo_roll_ptr_is_insert(t_roll_ptr)
|| dbug_v_purge) {
+
+ if (vcol_info && !vcol_info->used) {
+ mtr->commit();
+ }
+
row_vers_build_clust_v_col(
- row, clust_index, index, heap);
+ row, clust_index, index, heap,
+ vcol_info);
+
+ if (vcol_info && vcol_info->is_first_fetch()) {
+ goto unsafe_to_purge;
+ }
entry = row_build_index_entry(
row, ext, index, heap);
@@ -988,7 +1030,7 @@ safe_to_purge:
if (v_heap) {
mem_heap_free(v_heap);
}
- return(TRUE);
+ return true;
}
}
} else if (dict_index_has_virtual(index)) {
@@ -996,9 +1038,15 @@ safe_to_purge:
deleted, but the previous version of it might not. We will
need to get the virtual column data from undo record
associated with current cluster index */
+
cur_vrow = row_vers_build_cur_vrow(
also_curr, rec, clust_index, &clust_offsets,
- index, ientry, roll_ptr, trx_id, heap, v_heap, mtr);
+ index, ientry, roll_ptr, trx_id, heap, v_heap, mtr,
+ vcol_info);
+
+ if (vcol_info && vcol_info->is_first_fetch()) {
+ goto unsafe_to_purge;
+ }
}
version = rec;
@@ -1017,14 +1065,14 @@ safe_to_purge:
if (!prev_version) {
/* Versions end here */
-
+unsafe_to_purge:
mem_heap_free(heap);
if (v_heap) {
mem_heap_free(v_heap);
}
- return(FALSE);
+ return false;
}
clust_offsets = rec_get_offsets(prev_version, clust_index,