diff options
author | Aleksey Midenkov <midenok@gmail.com> | 2019-10-22 18:47:10 +0200 |
---|---|---|
committer | Aleksey Midenkov <midenok@gmail.com> | 2020-05-19 10:08:39 +0300 |
commit | 7d4f78147969665dd998f6bdc6536f0a9b9d47ea (patch) | |
tree | 98b0b6cf9488ce68350814e835cf8170e9306667 | |
parent | 141cf43e61d262ac5c0d0c031f8585c02ef7d0fe (diff) | |
download | mariadb-git-bb-10.2-midenok-MDEV-20874.tar.gz |
MDEV-20874 Wrong handling of 'table was dropped' error in purge threadbb-10.2-midenok-MDEV-20874
Proper error handling by allowing innobase_allocate_row_for_vcol()
return dberr_t and handle it properly up the stack.
Refactor a row of functions which were not supposed to fail with error.
Handle DB_OUT_OF_MEMORY in row_mysql_handle_errors().
-rw-r--r-- | storage/innobase/btr/btr0cur.cc | 5 | ||||
-rw-r--r-- | storage/innobase/handler/ha_innodb.cc | 21 | ||||
-rw-r--r-- | storage/innobase/include/db0err.h | 2 | ||||
-rw-r--r-- | storage/innobase/include/row0mysql.h | 7 | ||||
-rw-r--r-- | storage/innobase/include/row0purge.h | 1 | ||||
-rw-r--r-- | storage/innobase/include/row0vers.h | 1 | ||||
-rw-r--r-- | storage/innobase/row/row0ins.cc | 8 | ||||
-rw-r--r-- | storage/innobase/row/row0merge.cc | 3 | ||||
-rw-r--r-- | storage/innobase/row/row0mysql.cc | 3 | ||||
-rw-r--r-- | storage/innobase/row/row0purge.cc | 42 | ||||
-rw-r--r-- | storage/innobase/row/row0sel.cc | 23 | ||||
-rw-r--r-- | storage/innobase/row/row0umod.cc | 4 | ||||
-rw-r--r-- | storage/innobase/row/row0upd.cc | 31 | ||||
-rw-r--r-- | storage/innobase/row/row0vers.cc | 3 |
14 files changed, 97 insertions, 57 deletions
diff --git a/storage/innobase/btr/btr0cur.cc b/storage/innobase/btr/btr0cur.cc index 37ba133cb0f..a3331d25a4a 100644 --- a/storage/innobase/btr/btr0cur.cc +++ b/storage/innobase/btr/btr0cur.cc @@ -1322,8 +1322,11 @@ retry_page_get: ut_ad(!dict_index_is_spatial(index)); if (!row_purge_poss_sec(cursor->purge_node, - index, tuple)) { + index, tuple, err)) { + if (err) { + goto func_exit; + } /* The record cannot be purged yet. */ cursor->flag = BTR_CUR_DELETE_REF; } else if (ibuf_insert(IBUF_OP_DELETE, tuple, diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index b917bdab19e..2bfb5f22e43 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -21843,10 +21843,10 @@ innobase_get_field_from_update_vector( for purge thread. */ -bool innobase_allocate_row_for_vcol( +dberr_t innobase_allocate_row_for_vcol( THD * thd, dict_index_t* index, - mem_heap_t** heap, + mem_heap_t*& heap, TABLE** table, byte** record, VCOL_STORAGE** storage) @@ -21859,25 +21859,26 @@ bool innobase_allocate_row_for_vcol( /* For purge thread, there is a possiblity that table could have dropped, corrupted or unaccessible. */ if (!*table) - return true; + return DB_TABLE_NOT_FOUND; maria_table= *table; - if (!*heap && !(*heap= mem_heap_create(srv_page_size))) + if (!heap && !(heap= mem_heap_create(srv_page_size))) { *storage= 0; - return TRUE; + return DB_OUT_OF_MEMORY; } - *record= static_cast<byte*>(mem_heap_alloc(*heap, + *record= static_cast<byte*>(mem_heap_alloc(heap, maria_table->s->reclength)); *storage= static_cast<VCOL_STORAGE*> - (mem_heap_alloc(*heap, sizeof(**storage))); + (mem_heap_alloc(heap, sizeof(**storage))); blob_value_storage= static_cast<String*> - (mem_heap_alloc(*heap, + (mem_heap_alloc(heap, maria_table->s->virtual_not_stored_blob_fields * sizeof(String))); if (!*record || !*storage || !blob_value_storage) { + mem_heap_free(heap); *storage= 0; - return TRUE; + return DB_OUT_OF_MEMORY; } (*storage)->maria_table= maria_table; (*storage)->innobase_record= *record; @@ -21888,7 +21889,7 @@ bool innobase_allocate_row_for_vcol( (*storage)->maria_record); maria_table->remember_blob_values(blob_value_storage); - return FALSE; + return DB_SUCCESS; } diff --git a/storage/innobase/include/db0err.h b/storage/innobase/include/db0err.h index f70a65890c9..76a4e61a0a5 100644 --- a/storage/innobase/include/db0err.h +++ b/storage/innobase/include/db0err.h @@ -30,7 +30,7 @@ Created 5/24/1996 Heikki Tuuri /* Do not include univ.i because univ.i includes this. */ enum dberr_t { - DB_SUCCESS, + DB_SUCCESS = 0, DB_SUCCESS_LOCKED_REC = 9, /*!< like DB_SUCCESS, but a new explicit record lock was created */ diff --git a/storage/innobase/include/row0mysql.h b/storage/innobase/include/row0mysql.h index 60f53221c9a..f00a0be97dc 100644 --- a/storage/innobase/include/row0mysql.h +++ b/storage/innobase/include/row0mysql.h @@ -827,14 +827,13 @@ struct VCOL_STORAGE @param[out] rec Pointer to allocated MariaDB record @param[out] storage Internal storage for blobs etc -@return FALSE ok -@return TRUE malloc failure +@return error code */ -bool innobase_allocate_row_for_vcol( +dberr_t innobase_allocate_row_for_vcol( THD * thd, dict_index_t* index, - mem_heap_t** heap, + mem_heap_t*& heap, TABLE** table, byte** record, VCOL_STORAGE** storage); diff --git a/storage/innobase/include/row0purge.h b/storage/innobase/include/row0purge.h index c4ddff4243c..936b1ab44e6 100644 --- a/storage/innobase/include/row0purge.h +++ b/storage/innobase/include/row0purge.h @@ -65,6 +65,7 @@ row_purge_poss_sec( purge_node_t* node, dict_index_t* index, const dtuple_t* entry, + dberr_t& err, btr_pcur_t* sec_pcur=NULL, mtr_t* sec_mtr=NULL, bool is_tree=false); diff --git a/storage/innobase/include/row0vers.h b/storage/innobase/include/row0vers.h index 3b1f16ef15f..aace69d31be 100644 --- a/storage/innobase/include/row0vers.h +++ b/storage/innobase/include/row0vers.h @@ -95,6 +95,7 @@ row_vers_old_has_index_entry( const dtuple_t* ientry, roll_ptr_t roll_ptr, trx_id_t trx_id, + dberr_t& err, purge_vcol_info_t* vcol_info=NULL); /*****************************************************************//** diff --git a/storage/innobase/row/row0ins.cc b/storage/innobase/row/row0ins.cc index 123566132f4..b0401485bab 100644 --- a/storage/innobase/row/row0ins.cc +++ b/storage/innobase/row/row0ins.cc @@ -970,11 +970,9 @@ row_ins_foreign_fill_virtual( innobase_init_vc_templ(index->table); } - if (innobase_allocate_row_for_vcol(thd, index, &v_heap, - &mysql_table, - &record, &vcol_storage)) { - if (v_heap) mem_heap_free(v_heap); - *err = DB_OUT_OF_MEMORY; + if ((*err = innobase_allocate_row_for_vcol(thd, index, v_heap, + &mysql_table, + &record, &vcol_storage))) { goto func_exit; } diff --git a/storage/innobase/row/row0merge.cc b/storage/innobase/row/row0merge.cc index 8c8f1674374..99f866a732d 100644 --- a/storage/innobase/row/row0merge.cc +++ b/storage/innobase/row/row0merge.cc @@ -595,8 +595,7 @@ row_merge_buf_add( = dict_table_get_first_index(new_table); if (!vcol_storage && - innobase_allocate_row_for_vcol(trx->mysql_thd, clust_index, v_heap, &my_table, &record, &vcol_storage)) { - *err = DB_OUT_OF_MEMORY; + (*err = innobase_allocate_row_for_vcol(trx->mysql_thd, clust_index, *v_heap, &my_table, &record, &vcol_storage))) { goto error; } diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc index 9bbd531cb9a..5fc14c7fad2 100644 --- a/storage/innobase/row/row0mysql.cc +++ b/storage/innobase/row/row0mysql.cc @@ -781,6 +781,9 @@ handle_new_error: << FK_MAX_CASCADE_DEL << ". Please drop excessive" " foreign constraints and try again"; goto rollback_to_savept; + case DB_OUT_OF_MEMORY: + ib::fatal() << "Out of memory"; + break; default: ib::fatal() << "Unknown error code " << err << ": " << ut_strerr(err); diff --git a/storage/innobase/row/row0purge.cc b/storage/innobase/row/row0purge.cc index f4fd617f154..8f9756bdc53 100644 --- a/storage/innobase/row/row0purge.cc +++ b/storage/innobase/row/row0purge.cc @@ -284,6 +284,7 @@ row_purge_poss_sec( purge_node_t* node, dict_index_t* index, const dtuple_t* entry, + dberr_t& err, btr_pcur_t* sec_pcur, mtr_t* sec_mtr, bool is_tree) @@ -318,7 +319,10 @@ retry_purge_sec: btr_pcur_get_rec(&node->pcur), &mtr, index, entry, node->roll_ptr, node->trx_id, - &node->vcol_info); + err, &node->vcol_info); + if (err) { + return false; + } if (node->vcol_info.is_first_fetch()) { ut_ad(store_cur); @@ -375,11 +379,11 @@ row_purge_remove_sec_if_poss_tree( /*==============================*/ purge_node_t* node, /*!< in: row purge node */ dict_index_t* index, /*!< in: index */ - const dtuple_t* entry) /*!< in: index entry */ + const dtuple_t* entry, /*!< in: index entry */ + dberr_t& err) { btr_pcur_t pcur; ibool success = TRUE; - dberr_t err; mtr_t mtr; enum row_search_result search_result; @@ -442,7 +446,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, &pcur, &mtr, true)) { + if (row_purge_poss_sec(node, index, entry, err, &pcur, &mtr, true)) { /* Remove the index record, which should have been marked for deletion. */ @@ -476,6 +480,8 @@ row_purge_remove_sec_if_poss_tree( default: ut_error; } + } else { + success = false; } if (node->vcol_op_failed()) { @@ -510,6 +516,7 @@ row_purge_remove_sec_if_poss_leaf( btr_pcur_t pcur; enum btr_latch_mode mode; enum row_search_result search_result; + dberr_t err = DB_SUCCESS; bool success = true; log_free_check(); @@ -576,7 +583,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, &pcur, &mtr, false)) { + if (row_purge_poss_sec(node, index, entry, err, &pcur, &mtr, false)) { btr_cur_t* btr_cur = btr_pcur_get_btr_cur(&pcur); /* Only delete-marked records should be purged. */ @@ -643,7 +650,7 @@ row_purge_remove_sec_if_poss_leaf( } } - if (node->vcol_op_failed()) { + if (err || node->vcol_op_failed()) { btr_pcur_close(&pcur); return false; } @@ -670,7 +677,7 @@ func_exit_no_pcur: /***********************************************************//** Removes a secondary index entry if possible. */ UNIV_INLINE MY_ATTRIBUTE((nonnull(1,2))) -void +dberr_t row_purge_remove_sec_if_poss( /*=========================*/ purge_node_t* node, /*!< in: row purge node */ @@ -678,6 +685,7 @@ row_purge_remove_sec_if_poss( const dtuple_t* entry) /*!< in: index entry */ { ibool success; + dberr_t err = DB_SUCCESS; ulint n_tries = 0; /* fputs("Purge: Removing secondary record\n", stderr); */ @@ -686,19 +694,19 @@ row_purge_remove_sec_if_poss( /* The node->row must have lacked some fields of this index. This is possible when the undo log record was written before this index was created. */ - return; + return err; } if (row_purge_remove_sec_if_poss_leaf(node, index, entry)) { - return; + return err; } retry: if (node->vcol_op_failed()) { - return; + return err; } - success = row_purge_remove_sec_if_poss_tree(node, index, entry); + success = row_purge_remove_sec_if_poss_tree(node, index, entry, err); /* The delete operation may fail if we have little file space left: TODO: easiest to crash the database and restart with more file space */ @@ -712,7 +720,8 @@ retry: goto retry; } - ut_a(success); + ut_a(success || err); + return err; } /** Skip uncommitted virtual indexes on newly added virtual column. @@ -763,9 +772,10 @@ row_purge_del_mark( dtuple_t* entry = row_build_index_entry_low( node->row, NULL, node->index, heap, ROW_BUILD_FOR_PURGE); - row_purge_remove_sec_if_poss(node, node->index, entry); - if (node->vcol_op_failed()) { + + if (row_purge_remove_sec_if_poss(node, node->index, entry) + || node->vcol_op_failed()) { mem_heap_free(heap); return false; } @@ -823,9 +833,9 @@ row_purge_upd_exist_or_extern_func( dtuple_t* entry = row_build_index_entry_low( node->row, NULL, node->index, heap, ROW_BUILD_FOR_PURGE); - row_purge_remove_sec_if_poss(node, node->index, entry); - if (node->vcol_op_failed()) { + if (row_purge_remove_sec_if_poss(node, node->index, entry) + || node->vcol_op_failed()) { ut_ad(!node->table); mem_heap_free(heap); return; diff --git a/storage/innobase/row/row0sel.cc b/storage/innobase/row/row0sel.cc index 15486500b37..74b48bd799c 100644 --- a/storage/innobase/row/row0sel.cc +++ b/storage/innobase/row/row0sel.cc @@ -164,6 +164,7 @@ row_sel_sec_rec_is_for_clust_rec( dict_index_t* sec_index, const rec_t* clust_rec, dict_index_t* clust_index, + dberr_t& err, que_thr_t* thr) { const byte* sec_field; @@ -179,6 +180,7 @@ row_sel_sec_rec_is_for_clust_rec( ibool is_equal = TRUE; VCOL_STORAGE* vcol_storage= 0; byte* record; + err = DB_SUCCESS; rec_offs_init(clust_offsets_); rec_offs_init(sec_offsets_); @@ -228,12 +230,15 @@ row_sel_sec_rec_is_for_clust_rec( if (!vcol_storage) { TABLE *mysql_table= thr->prebuilt->m_mysql_table; - innobase_allocate_row_for_vcol(thr_get_trx(thr)->mysql_thd, + err = innobase_allocate_row_for_vcol(thr_get_trx(thr)->mysql_thd, clust_index, - &heap, + heap, &mysql_table, &record, &vcol_storage); + if (err) { + return false; + } } v_col = reinterpret_cast<const dict_v_col_t*>(col); @@ -1035,8 +1040,12 @@ row_sel_get_clust_rec( plan->table))) && !row_sel_sec_rec_is_for_clust_rec(rec, plan->index, clust_rec, index, - thr)) { - goto func_exit; + err, thr)) { + if (!err) { + goto func_exit; + } else { + goto err_exit; + } } } @@ -3581,8 +3590,12 @@ Row_sel_get_clust_rec_for_mysql::operator()( || rec_get_deleted_flag(rec, dict_table_is_comp( sec_index->table))) && !row_sel_sec_rec_is_for_clust_rec( - rec, sec_index, clust_rec, clust_index, thr)) { + rec, sec_index, clust_rec, clust_index, err, thr)) { clust_rec = NULL; + if (err) { + goto err_exit; + } + } err = DB_SUCCESS; diff --git a/storage/innobase/row/row0umod.cc b/storage/innobase/row/row0umod.cc index ac4500f5c3e..8b5c7aad8a3 100644 --- a/storage/innobase/row/row0umod.cc +++ b/storage/innobase/row/row0umod.cc @@ -511,11 +511,11 @@ row_undo_mod_del_mark_or_remove_sec_low( if (dict_table_is_temporary(node->table) || row_vers_old_has_index_entry( false, btr_pcur_get_rec(&(node->pcur)), - &mtr_vers, index, entry, 0, 0)) { + &mtr_vers, index, entry, 0, 0, err)) { err = btr_cur_del_mark_set_sec_rec(BTR_NO_LOCKING_FLAG, btr_cur, TRUE, thr, &mtr); ut_ad(err == DB_SUCCESS); - } else { + } else if (!err) { /* Remove the index record */ if (dict_index_is_spatial(index)) { diff --git a/storage/innobase/row/row0upd.cc b/storage/innobase/row/row0upd.cc index a316041ed0e..1a47d27affc 100644 --- a/storage/innobase/row/row0upd.cc +++ b/storage/innobase/row/row0upd.cc @@ -1130,9 +1130,9 @@ row_upd_build_difference_binary( ut_ad(!update->old_vrow); - innobase_allocate_row_for_vcol(thd, index, &v_heap, - &mysql_table, - &record, &vcol_storage); + *error = innobase_allocate_row_for_vcol(thd, index, v_heap, + &mysql_table, + &record, &vcol_storage); for (i = 0; i < n_v_fld; i++) { const dict_v_col_t* col @@ -2117,7 +2117,7 @@ row_upd_eval_new_vals( @param[in] thd mysql thread handle @param[in,out] mysql_table mysql table object */ static -void +dberr_t row_upd_store_v_row( upd_node_t* node, const upd_t* update, @@ -2129,9 +2129,13 @@ row_upd_store_v_row( byte* record= 0; VCOL_STORAGE *vcol_storage= 0; - if (!update) - innobase_allocate_row_for_vcol(thd, index, &heap, &mysql_table, + if (!update) { + dberr_t err = innobase_allocate_row_for_vcol(thd, index, heap, &mysql_table, &record, &vcol_storage); + if (err) { + return err; + } + } for (ulint col_no = 0; col_no < dict_table_get_n_v_cols(node->table); col_no++) { @@ -2198,7 +2202,7 @@ row_upd_store_v_row( innobase_free_row_for_vcol(vcol_storage); mem_heap_free(heap); } - + return DB_SUCCESS; } /** Stores to the heap the row on which the node->pcur is positioned. @@ -2207,7 +2211,7 @@ row_upd_store_v_row( @param[in,out] mysql_table NULL, or mysql table object when user thread invokes dml */ static -void +dberr_t row_upd_store_row( upd_node_t* node, THD* thd, @@ -2219,6 +2223,7 @@ row_upd_store_row( row_ext_t** ext; rec_offs offsets_[REC_OFFS_NORMAL_SIZE]; const rec_offs* offsets; + dberr_t err = DB_SUCCESS; rec_offs_init(offsets_); ut_ad(node->pcur->latch_mode != BTR_NO_LATCHES); @@ -2251,8 +2256,11 @@ row_upd_store_row( NULL, NULL, NULL, ext, node->heap); if (node->table->n_v_cols) { - row_upd_store_v_row(node, node->is_delete ? NULL : node->update, + err = row_upd_store_v_row(node, node->is_delete ? NULL : node->update, thd, mysql_table); + if (err) { + goto err_exit; + } } if (node->is_delete) { @@ -2264,9 +2272,12 @@ row_upd_store_row( clust_index, node->update, node->heap); } + +err_exit: if (UNIV_LIKELY_NULL(heap)) { mem_heap_free(heap); } + return err; } /***********************************************************//** @@ -2982,7 +2993,7 @@ row_upd_del_mark_clust_rec( /* Store row because we have to build also the secondary index entries */ - row_upd_store_row(node, trx->mysql_thd, + err = row_upd_store_row(node, trx->mysql_thd, thr->prebuilt && thr->prebuilt->table == node->table ? thr->prebuilt->m_mysql_table : NULL); diff --git a/storage/innobase/row/row0vers.cc b/storage/innobase/row/row0vers.cc index 3627c659231..544c9aad313 100644 --- a/storage/innobase/row/row0vers.cc +++ b/storage/innobase/row/row0vers.cc @@ -470,7 +470,7 @@ row_vers_build_clust_v_col( } innobase_allocate_row_for_vcol(thd, index, - &local_heap, + local_heap, &maria_table, &record, &vcol_storage); @@ -887,6 +887,7 @@ row_vers_old_has_index_entry( const dtuple_t* ientry, roll_ptr_t roll_ptr, trx_id_t trx_id, + dberr_t& err, purge_vcol_info_t* vcol_info) { const rec_t* version; |