diff options
Diffstat (limited to 'storage/xtradb/row/row0upd.cc')
-rw-r--r-- | storage/xtradb/row/row0upd.cc | 382 |
1 files changed, 220 insertions, 162 deletions
diff --git a/storage/xtradb/row/row0upd.cc b/storage/xtradb/row/row0upd.cc index 9d40848c2fc..9b733410c00 100644 --- a/storage/xtradb/row/row0upd.cc +++ b/storage/xtradb/row/row0upd.cc @@ -176,25 +176,47 @@ func_exit: } #ifdef WITH_WSREP -ulint -wsrep_append_foreign_key( - trx_t* trx, - dict_foreign_t* foreign, - const rec_t* clust_rec, - dict_index_t* clust_index, - ibool referenced, - ibool shared); +static +ibool +wsrep_row_upd_index_is_foreign( +/*========================*/ + dict_index_t* index, /*!< in: index */ + trx_t* trx) /*!< in: transaction */ +{ + dict_table_t* table = index->table; + dict_foreign_t* foreign; + ibool froze_data_dict = FALSE; + ibool is_referenced = FALSE; -ulint -wsrep_row_upd_check_foreign_constraints( - upd_node_t* node, /*!< in: row update node */ - btr_pcur_t* pcur, /*!< in: cursor positioned on a record; NOTE: the - cursor position is lost in this function! */ - dict_table_t* table, /*!< in: table in question */ - dict_index_t* index, /*!< in: index of the cursor */ - ulint* offsets,/*!< in/out: rec_get_offsets(pcur.rec, index) */ - que_thr_t* thr, /*!< in: query thread */ - mtr_t* mtr); /*!< in: mtr */ + if (!UT_LIST_GET_FIRST(table->foreign_list)) { + + return(FALSE); + } + + if (trx->dict_operation_lock_mode == 0) { + row_mysql_freeze_data_dictionary(trx); + froze_data_dict = TRUE; + } + + foreign = UT_LIST_GET_FIRST(table->foreign_list); + + while (foreign) { + if (foreign->foreign_index == index) { + + is_referenced = TRUE; + goto func_exit; + } + + foreign = UT_LIST_GET_NEXT(foreign_list, foreign); + } + +func_exit: + if (froze_data_dict) { + row_mysql_unfreeze_data_dictionary(trx); + } + + return(is_referenced); +} #endif /* WITH_WSREP */ /*********************************************************************//** @@ -314,7 +336,123 @@ run_again: } err = DB_SUCCESS; +func_exit: + if (got_s_lock) { + row_mysql_unfreeze_data_dictionary(trx); + } + + mem_heap_free(heap); + + return(err); +} +#ifdef WITH_WSREP +static +dberr_t +wsrep_row_upd_check_foreign_constraints( +/*=================================*/ + upd_node_t* node, /*!< in: row update node */ + btr_pcur_t* pcur, /*!< in: cursor positioned on a record; NOTE: the + cursor position is lost in this function! */ + dict_table_t* table, /*!< in: table in question */ + dict_index_t* index, /*!< in: index of the cursor */ + ulint* offsets,/*!< in/out: rec_get_offsets(pcur.rec, index) */ + que_thr_t* thr, /*!< in: query thread */ + mtr_t* mtr) /*!< in: mtr */ +{ + dict_foreign_t* foreign; + mem_heap_t* heap; + dtuple_t* entry; + trx_t* trx; + const rec_t* rec; + ulint n_ext; + dberr_t err; + ibool got_s_lock = FALSE; + + if (UT_LIST_GET_FIRST(table->foreign_list) == NULL) { + + return(DB_SUCCESS); + } + + trx = thr_get_trx(thr); + + rec = btr_pcur_get_rec(pcur); + ut_ad(rec_offs_validate(rec, index, offsets)); + + heap = mem_heap_create(500); + + entry = row_rec_to_index_entry(rec, index, offsets, + &n_ext, heap); + + mtr_commit(mtr); + + mtr_start(mtr); + + if (trx->dict_operation_lock_mode == 0) { + got_s_lock = TRUE; + + row_mysql_freeze_data_dictionary(trx); + } + + foreign = UT_LIST_GET_FIRST(table->foreign_list); + + while (foreign) { + /* Note that we may have an update which updates the index + record, but does NOT update the first fields which are + referenced in a foreign key constraint. Then the update does + NOT break the constraint. */ + + if (foreign->foreign_index == index + && (node->is_delete + || row_upd_changes_first_fields_binary( + entry, index, node->update, + foreign->n_fields))) { + + if (foreign->referenced_table == NULL) { + foreign->referenced_table = + dict_table_open_on_name( + foreign->referenced_table_name_lookup, + FALSE, FALSE, DICT_ERR_IGNORE_NONE); + } + + if (foreign->referenced_table) { + mutex_enter(&(dict_sys->mutex)); + + (foreign->referenced_table + ->n_foreign_key_checks_running)++; + + mutex_exit(&(dict_sys->mutex)); + } + + /* NOTE that if the thread ends up waiting for a lock + we will release dict_operation_lock temporarily! + But the counter on the table protects 'foreign' from + being dropped while the check is running. */ + + err = row_ins_check_foreign_constraint( + TRUE, foreign, table, entry, thr); + + if (foreign->referenced_table) { + mutex_enter(&(dict_sys->mutex)); + + ut_a(foreign->referenced_table + ->n_foreign_key_checks_running > 0); + + (foreign->referenced_table + ->n_foreign_key_checks_running)--; + + mutex_exit(&(dict_sys->mutex)); + } + if (err != DB_SUCCESS) { + + goto func_exit; + } + } + + foreign = UT_LIST_GET_NEXT(foreign_list, foreign); + } + + err = DB_SUCCESS; func_exit: if (got_s_lock) { row_mysql_unfreeze_data_dictionary(trx); @@ -326,6 +464,7 @@ func_exit: return(err); } +#endif /* WITH_WSREP */ /*********************************************************************//** Creates an update node for a query graph. @@ -1700,6 +1839,9 @@ row_upd_sec_index_entry( index = node->index; referenced = row_upd_index_is_referenced(index, trx); +#ifdef WITH_WSREP + ibool foreign = wsrep_row_upd_index_is_foreign(index, trx); +#endif /* WITH_WSREP */ heap = mem_heap_create(1024); @@ -1830,6 +1972,9 @@ row_upd_sec_index_entry( row_ins_sec_index_entry() below */ if (!rec_get_deleted_flag( rec, dict_table_is_comp(index->table))) { +#ifdef WITH_WSREP + que_node_t *parent = que_node_get_parent(node); +#endif /* WITH_WSREP */ err = btr_cur_del_mark_set_sec_rec( 0, btr_cur, TRUE, thr, &mtr); @@ -1848,29 +1993,32 @@ row_upd_sec_index_entry( index, offsets, thr, &mtr); } #ifdef WITH_WSREP - if (err == DB_SUCCESS && !referenced) { + if (err == DB_SUCCESS && !referenced && + !(parent && que_node_get_type(parent) == + QUE_NODE_UPDATE && + ((upd_node_t*)parent)->cascade_node == node) && + foreign + ) { ulint* offsets = rec_get_offsets( - rec, index, NULL, ULINT_UNDEFINED, - &heap); - err = (dberr_t) wsrep_row_upd_check_foreign_constraints( + rec, index, NULL, ULINT_UNDEFINED, + &heap); + err = wsrep_row_upd_check_foreign_constraints( node, &pcur, index->table, index, offsets, thr, &mtr); - switch (err) { case DB_SUCCESS: case DB_NO_REFERENCED_ROW: err = DB_SUCCESS; break; case DB_DEADLOCK: - if (wsrep_debug) - fprintf (stderr, - "WSREP: sec index FK check fail for deadlock"); + if (wsrep_debug) fprintf (stderr, + "WSREP: sec index FK check fail for deadlock"); break; default: - fprintf (stderr, - "WSREP: referenced FK check fail: %d", - err); + fprintf (stderr, + "WSREP: referenced FK check fail: %d", + (int)err); break; } } @@ -2015,123 +2163,6 @@ row_upd_clust_rec_by_insert_inherit_func( return(inherit); } -#ifdef WITH_WSREP -ulint -wsrep_row_upd_check_foreign_constraints( -/*=================================*/ - upd_node_t* node, /*!< in: row update node */ - btr_pcur_t* pcur, /*!< in: cursor positioned on a record; NOTE: the - cursor position is lost in this function! */ - dict_table_t* table, /*!< in: table in question */ - dict_index_t* index, /*!< in: index of the cursor */ - ulint* offsets,/*!< in/out: rec_get_offsets(pcur.rec, index) */ - que_thr_t* thr, /*!< in: query thread */ - mtr_t* mtr) /*!< in: mtr */ -{ - dict_foreign_t* foreign; - mem_heap_t* heap; - dtuple_t* entry; - trx_t* trx; - const rec_t* rec; - ulint n_ext; - ulint err; - ibool got_s_lock = FALSE; - - if (UT_LIST_GET_FIRST(table->foreign_list) == NULL) { - - return(DB_SUCCESS); - } - - trx = thr_get_trx(thr); - - rec = btr_pcur_get_rec(pcur); - ut_ad(rec_offs_validate(rec, index, offsets)); - - heap = mem_heap_create(500); - - entry = row_rec_to_index_entry(rec, index, offsets, &n_ext, heap); - - mtr_commit(mtr); - - mtr_start(mtr); - - if (trx->dict_operation_lock_mode == 0) { - got_s_lock = TRUE; - - row_mysql_freeze_data_dictionary(trx); - } - - foreign = UT_LIST_GET_FIRST(table->foreign_list); - - while (foreign) { - /* Note that we may have an update which updates the index - record, but does NOT update the first fields which are - referenced in a foreign key constraint. Then the update does - NOT break the constraint. */ - - if (foreign->foreign_index == index - && (node->is_delete - || row_upd_changes_first_fields_binary( - entry, index, node->update, - foreign->n_fields))) { - - if (foreign->referenced_table == NULL) { - foreign->referenced_table = - dict_table_open_on_name( - foreign->referenced_table_name_lookup, - FALSE, FALSE, DICT_ERR_IGNORE_NONE); - } - - if (foreign->referenced_table) { - mutex_enter(&(dict_sys->mutex)); - - (foreign->referenced_table - ->n_foreign_key_checks_running)++; - - mutex_exit(&(dict_sys->mutex)); - } - - /* NOTE that if the thread ends up waiting for a lock - we will release dict_operation_lock temporarily! - But the counter on the table protects 'foreign' from - being dropped while the check is running. */ - - err = row_ins_check_foreign_constraint( - TRUE, foreign, table, entry, thr); - - if (foreign->referenced_table) { - mutex_enter(&(dict_sys->mutex)); - - ut_a(foreign->referenced_table - ->n_foreign_key_checks_running > 0); - - (foreign->referenced_table - ->n_foreign_key_checks_running)--; - - mutex_exit(&(dict_sys->mutex)); - } - - if (err != DB_SUCCESS) { - - goto func_exit; - } - } - - foreign = UT_LIST_GET_NEXT(foreign_list, foreign); - } - - err = DB_SUCCESS; -func_exit: - if (got_s_lock) { - row_mysql_unfreeze_data_dictionary(trx); - } - - mem_heap_free(heap); - - return(err); -} -#endif /* WITH_WSREP */ - /***********************************************************//** Marks the clustered index record deleted and inserts the updated version of the record to the index. This function should be used when the ordering @@ -2148,6 +2179,9 @@ row_upd_clust_rec_by_insert( que_thr_t* thr, /*!< in: query thread */ ibool referenced,/*!< in: TRUE if index may be referenced in a foreign key constraint */ +#ifdef WITH_WSREP + ibool foreign, /*!< in: TRUE if index is foreign key index */ +#endif /* WITH_WSREP */ mtr_t* mtr) /*!< in/out: mtr; gets committed here */ { mem_heap_t* heap; @@ -2161,6 +2195,9 @@ row_upd_clust_rec_by_insert( rec_t* rec; ulint* offsets = NULL; +#ifdef WITH_WSREP + que_node_t *parent = que_node_get_parent(node); +#endif /* WITH_WSREP */ ut_ad(node); ut_ad(dict_index_is_clust(index)); @@ -2241,23 +2278,26 @@ err_exit: } } #ifdef WITH_WSREP - if (!referenced) { - err = (dberr_t) wsrep_row_upd_check_foreign_constraints( + if (!referenced && + !(parent && que_node_get_type(parent) == QUE_NODE_UPDATE && + ((upd_node_t*)parent)->cascade_node == node) && + foreign + ) { + err = wsrep_row_upd_check_foreign_constraints( node, pcur, table, index, offsets, thr, mtr); - switch (err) { case DB_SUCCESS: case DB_NO_REFERENCED_ROW: err = DB_SUCCESS; break; case DB_DEADLOCK: - if (wsrep_debug) fprintf (stderr, + if (wsrep_debug) fprintf (stderr, "WSREP: insert FK check fail for deadlock"); break; default: fprintf (stderr, - "WSREP: referenced FK check fail: %d", - err); + "WSREP: referenced FK check fail: %d", + (int)err); break; } if (err != DB_SUCCESS) { @@ -2495,6 +2535,9 @@ row_upd_del_mark_clust_rec( ibool referenced, /*!< in: TRUE if index may be referenced in a foreign key constraint */ +#ifdef WITH_WSREP + ibool foreign,/*!< in: TRUE if index is foreign key index */ +#endif /* WITH_WSREP */ mtr_t* mtr) /*!< in: mtr; gets committed here */ { btr_pcur_t* pcur; @@ -2502,6 +2545,7 @@ row_upd_del_mark_clust_rec( dberr_t err; #ifdef WITH_WSREP rec_t* rec; + que_node_t *parent = que_node_get_parent(node); #endif /* WITH_WSREP */ ut_ad(node); @@ -2524,25 +2568,27 @@ row_upd_del_mark_clust_rec( #endif /* WITH_WSREP */ err = btr_cur_del_mark_set_clust_rec( - btr_cur_get_block(btr_cur), #ifdef WITH_WSREP - rec, index, offsets, thr, mtr); + btr_cur_get_block(btr_cur), rec, #else - btr_cur_get_rec(btr_cur), index, offsets, thr, mtr); + btr_cur_get_block(btr_cur), btr_cur_get_rec(btr_cur), #endif /* WITH_WSREP */ - + index, offsets, thr, mtr); if (err == DB_SUCCESS && referenced) { /* NOTE that the following call loses the position of pcur ! */ err = row_upd_check_references_constraints( node, pcur, index->table, index, offsets, thr, mtr); } - #ifdef WITH_WSREP - if (err == DB_SUCCESS && !referenced) { - err = (dberr_t) wsrep_row_upd_check_foreign_constraints( + if (err == DB_SUCCESS && !referenced && + !(parent && que_node_get_type(parent) == QUE_NODE_UPDATE && + ((upd_node_t*)parent)->cascade_node == node) && + thr_get_trx(thr) && + foreign + ) { + err = wsrep_row_upd_check_foreign_constraints( node, pcur, index->table, index, offsets, thr, mtr); - switch (err) { case DB_SUCCESS: case DB_NO_REFERENCED_ROW: @@ -2554,8 +2600,8 @@ row_upd_del_mark_clust_rec( break; default: fprintf (stderr, - "WSREP: clust rec referenced FK check fail: %u", - err); + "WSREP: clust rec referenced FK check fail: %d", + (int)err); break; } } @@ -2592,6 +2638,10 @@ row_upd_clust_step( index = dict_table_get_first_index(node->table); referenced = row_upd_index_is_referenced(index, thr_get_trx(thr)); +#ifdef WITH_WSREP + ibool foreign = wsrep_row_upd_index_is_foreign( + index, thr_get_trx(thr)); +#endif /* WITH_WSREP */ pcur = node->pcur; @@ -2688,7 +2738,11 @@ row_upd_clust_step( if (node->is_delete) { err = row_upd_del_mark_clust_rec( +#ifdef WITH_WSREP + node, index, offsets, thr, referenced, foreign, &mtr); +#else node, index, offsets, thr, referenced, &mtr); +#endif /* WITH_WSREP */ if (err == DB_SUCCESS) { node->state = UPD_NODE_UPDATE_ALL_SEC; @@ -2733,7 +2787,11 @@ row_upd_clust_step( externally! */ err = row_upd_clust_rec_by_insert( +#ifdef WITH_WSREP + node, index, thr, referenced, foreign, &mtr); +#else node, index, thr, referenced, &mtr); +#endif /* WITH_WSREP */ if (err != DB_SUCCESS) { |