diff options
Diffstat (limited to 'storage/innobase/row/row0purge.cc')
-rw-r--r-- | storage/innobase/row/row0purge.cc | 196 |
1 files changed, 183 insertions, 13 deletions
diff --git a/storage/innobase/row/row0purge.cc b/storage/innobase/row/row0purge.cc index af8cd682288..e70da7e5501 100644 --- a/storage/innobase/row/row0purge.cc +++ b/storage/innobase/row/row0purge.cc @@ -78,10 +78,31 @@ row_purge_node_create( node->common.parent = parent; node->done = TRUE; node->heap = mem_heap_create(256); + node->vcol_heap = NULL; + node->vcol_info = NULL; return(node); } +/** Create virtual column information node for the purge thread. +@param[in] node purge node. */ +static void row_purge_vcol_create(purge_node_t* node) +{ + if (node->vcol_info != NULL) { + return; + } + + if (node->vcol_heap == NULL) { + node->vcol_heap = mem_heap_create(128); + } + + node->vcol_info = static_cast<purge_vcol_info_t*>( + mem_heap_zalloc(node->vcol_heap, sizeof(purge_vcol_info_t*))); + + node->vcol_info->mariadb_table = NULL; + node->vcol_info->use_vcol = false; +} + /***********************************************************//** Repositions the pcur in the purge node on the clustered index record, if found. If the record is not found, close pcur. @@ -136,7 +157,8 @@ row_purge_remove_clust_if_poss_low( ulint offsets_[REC_OFFS_NORMAL_SIZE]; rec_offs_init(offsets_); - ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_S)); + ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_S) + || node->vcol_info->uses_vcol_info()); index = dict_table_get_first_index(node->table); @@ -230,6 +252,71 @@ row_purge_remove_clust_if_poss( return(false); } +/** Tries to store secondary index cursor before openin mysql table for +virtual index condition computation. +@param[in,out] node row purge node +@param[in] index secondary index +@param[in,out] sec_pcur secondary index cursor +@param[in,out] sec_mtr mini-transaction which holds + secondary index entry */ +static void row_purge_store_vsec_cur( + purge_node_t* node, + dict_index_t* index, + btr_pcur_t* sec_pcur, + mtr_t* sec_mtr) +{ + if (!dict_index_has_virtual(index) || sec_mtr == NULL) { + return; + } + + row_purge_vcol_create(node); + + row_purge_reposition_pcur(BTR_SEARCH_LEAF, node, sec_mtr); + + if (!node->found_clust) { + return; + } + + btr_pcur_store_position(sec_pcur, sec_mtr); + + node->sec_pcur = *sec_pcur; + + node->pcur.latch_mode = BTR_NO_LATCHES; + + btr_pcur_commit_specify_mtr(sec_pcur, sec_mtr); + + node->pcur.pos_state = BTR_PCUR_WAS_POSITIONED; +} + +/** Tries to restore secondary index cursor after opening the mysql table +@param[in,out] node row purge node +@param[in] index secondary index +@param[in,out] sec_mtr mini-transaction which holds secondary index entry +@param[in] is_tree purge check happening for tree mode. +@return restored cursor or NULL in case of failure. */ +static bool row_purge_restore_vsec_cur( + purge_node_t* node, + dict_index_t* index, + mtr_t* sec_mtr, + bool is_tree) +{ + if (!dict_index_has_virtual(index) || sec_mtr == NULL) { + return false; + } + + sec_mtr->start(); + + index->set_modified(*sec_mtr); + + if (btr_pcur_restore_position(is_tree ? BTR_MODIFY_TREE: BTR_PURGE_LEAF, + &node->sec_pcur, sec_mtr)) { + return true; + } + + btr_pcur_close(&node->sec_pcur); + return false; +} + /***********************************************************//** Determines if it is possible to remove a secondary index entry. Removal is possible if the secondary index entry does not refer to any @@ -244,25 +331,54 @@ inserts a record that the secondary index entry would refer to. However, in that case, the user transaction would also re-insert the secondary index entry after purge has removed it and released the leaf page latch. +@param[in,out] node row purge node +@param[in] index secondary index +@param[in] entry secondary index entry +@param[in,out] sec_pcur secondary index cursor +@param[in,out] sec_mtr mini-transaction which holds + secondary index entry +@param[in] is_tree purge checking for tree mode @return true if the secondary index record can be purged */ bool row_purge_poss_sec( -/*===============*/ - purge_node_t* node, /*!< in/out: row purge node */ - dict_index_t* index, /*!< in: secondary index */ - const dtuple_t* entry) /*!< in: secondary index entry */ + purge_node_t* node, + dict_index_t* index, + const dtuple_t* entry, + btr_pcur_t* sec_pcur, + mtr_t* sec_mtr, + bool is_tree) { - bool can_delete; + bool can_delete, use_vcol_first = false; mtr_t mtr; ut_ad(!dict_index_is_clust(index)); + + row_purge_store_vsec_cur(node, index, sec_pcur, sec_mtr); + +retry_purge_sec: + + use_vcol_first = node->is_vcol_info_exist() + && !node->vcol_info->uses_vcol_info(); + mtr_start(&mtr); can_delete = !row_purge_reposition_pcur(BTR_SEARCH_LEAF, node, &mtr) || !row_vers_old_has_index_entry(TRUE, btr_pcur_get_rec(&node->pcur), &mtr, index, entry, - node->roll_ptr, node->trx_id); + node->roll_ptr, node->trx_id, + node->vcol_info); + + if (use_vcol_first && node->vcol_info->uses_vcol_info()) { + + if (node->vcol_info->is_table_exists()) { + goto retry_purge_sec; + } + + node->table = NULL; + sec_pcur = NULL; + return false; + } /* Persistent cursor is closed if reposition fails. */ if (node->found_clust) { @@ -271,6 +387,10 @@ row_purge_poss_sec( mtr_commit(&mtr); } + if (row_purge_restore_vsec_cur(node, index, sec_mtr, is_tree)) { + sec_pcur = &node->sec_pcur; + } + return(can_delete); } @@ -354,7 +474,7 @@ row_purge_remove_sec_if_poss_tree( which cannot be purged yet, requires its existence. If some requires, we should do nothing. */ - if (row_purge_poss_sec(node, index, entry)) { + if (row_purge_poss_sec(node, index, entry, &pcur, &mtr, true)) { /* Remove the index record, which should have been marked for deletion. */ if (!rec_get_deleted_flag(btr_cur_get_rec(btr_cur), @@ -385,6 +505,10 @@ row_purge_remove_sec_if_poss_tree( } } + if (node->is_vcol_info_exist() && !node->validate_vcol_info()) { + return false; + } + func_exit: btr_pcur_close(&pcur); func_exit_no_pcur: @@ -474,7 +598,7 @@ row_purge_remove_sec_if_poss_leaf( case ROW_FOUND: /* Before attempting to purge a record, check if it is safe to do so. */ - if (row_purge_poss_sec(node, index, entry)) { + if (row_purge_poss_sec(node, index, entry, &pcur, &mtr, false)) { btr_cur_t* btr_cur = btr_pcur_get_btr_cur(&pcur); /* Only delete-marked records should be purged. */ @@ -540,6 +664,10 @@ row_purge_remove_sec_if_poss_leaf( success = false; } } + + if (node->is_vcol_info_exist() && !node->validate_vcol_info()) { + return false; + } /* (The index entry is still needed, or the deletion succeeded) */ /* fall through */ @@ -585,7 +713,12 @@ row_purge_remove_sec_if_poss( return; } + retry: + if (node->is_vcol_info_exist() && !node->validate_vcol_info()) { + return; + } + success = row_purge_remove_sec_if_poss_tree(node, index, entry); /* The delete operation may fail if we have little file space left: TODO: easiest to crash the database @@ -652,6 +785,13 @@ row_purge_del_mark( node->row, NULL, node->index, heap, ROW_BUILD_FOR_PURGE); row_purge_remove_sec_if_poss(node, node->index, entry); + + if (node->is_vcol_info_exist() + && !node->validate_vcol_info()) { + mem_heap_free(heap); + return false; + } + mem_heap_empty(heap); } @@ -671,7 +811,8 @@ static void row_purge_reset_trx_id(purge_node_t* node, mtr_t* mtr) { - ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_S)); + ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_S) + || node->vcol_info->uses_vcol_info()); /* Reset DB_TRX_ID, DB_ROLL_PTR for old records. */ mtr->start(); @@ -746,7 +887,8 @@ row_purge_upd_exist_or_extern_func( { mem_heap_t* heap; - ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_S)); + ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_S) + || node->vcol_info->uses_vcol_info()); ut_ad(!node->table->skip_alter_undo); if (node->rec_type == TRX_UNDO_UPD_DEL_REC @@ -1107,10 +1249,16 @@ row_purge( bool purged = row_purge_record( node, undo_rec, thr, updated_extern); - rw_lock_s_unlock(dict_operation_lock); + if (!node->is_vcol_info_exist() + || !node->vcol_info->uses_vcol_info()) { + + rw_lock_s_unlock(dict_operation_lock); + } if (purged - || srv_shutdown_state != SRV_SHUTDOWN_NONE) { + || srv_shutdown_state != SRV_SHUTDOWN_NONE + || (node->is_vcol_info_exist() + && !node->validate_vcol_info())) { return; } @@ -1142,8 +1290,14 @@ row_purge_end( node->done = TRUE; + node->vcol_info = NULL; + ut_a(thr->run_node != NULL); + if (node->vcol_heap != NULL) { + mem_heap_empty(node->vcol_heap); + } + mem_heap_empty(node->heap); } @@ -1189,6 +1343,7 @@ row_purge_step( row_purge_end(thr); } else { thr->run_node = node; + node->vcol_info = NULL; } } else { row_purge_end(thr); @@ -1248,3 +1403,18 @@ purge_node_t::validate_pcur() return(true); } #endif /* UNIV_DEBUG */ + +/** Check whether the virtual column information exist for the purge +node. +@return true if virtual column exist. */ +bool purge_node_t::is_vcol_info_exist() +{ + return vcol_info != NULL; +} + +/** Validate the virtual column information stored in purge thread. +@return true if purge node opens the mariadb table successfully. */ +bool purge_node_t::validate_vcol_info() +{ + return vcol_info->validate(); +} |