summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksey Midenkov <midenok@gmail.com>2019-10-22 18:47:10 +0200
committerAleksey Midenkov <midenok@gmail.com>2020-05-19 10:08:39 +0300
commit7d4f78147969665dd998f6bdc6536f0a9b9d47ea (patch)
tree98b0b6cf9488ce68350814e835cf8170e9306667
parent141cf43e61d262ac5c0d0c031f8585c02ef7d0fe (diff)
downloadmariadb-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.cc5
-rw-r--r--storage/innobase/handler/ha_innodb.cc21
-rw-r--r--storage/innobase/include/db0err.h2
-rw-r--r--storage/innobase/include/row0mysql.h7
-rw-r--r--storage/innobase/include/row0purge.h1
-rw-r--r--storage/innobase/include/row0vers.h1
-rw-r--r--storage/innobase/row/row0ins.cc8
-rw-r--r--storage/innobase/row/row0merge.cc3
-rw-r--r--storage/innobase/row/row0mysql.cc3
-rw-r--r--storage/innobase/row/row0purge.cc42
-rw-r--r--storage/innobase/row/row0sel.cc23
-rw-r--r--storage/innobase/row/row0umod.cc4
-rw-r--r--storage/innobase/row/row0upd.cc31
-rw-r--r--storage/innobase/row/row0vers.cc3
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;