diff options
author | Thirunarayanan Balathandayuthapani <thiru@mariadb.com> | 2018-07-06 17:13:53 +0300 |
---|---|---|
committer | Marko Mäkelä <marko.makela@mariadb.com> | 2018-07-06 17:13:53 +0300 |
commit | 8b0d4cff0760b0a35285c315d82c49631c108baf (patch) | |
tree | e04a349e07fb23b7db1095f330d1c61dccdf1192 /storage/innobase/row/row0vers.cc | |
parent | e3207b6c132666e734adcd6e4c8485b1580039c4 (diff) | |
download | mariadb-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.cc | 146 |
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, |