summaryrefslogtreecommitdiff
path: root/storage/innobase/row/row0uins.cc
diff options
context:
space:
mode:
Diffstat (limited to 'storage/innobase/row/row0uins.cc')
-rw-r--r--storage/innobase/row/row0uins.cc120
1 files changed, 76 insertions, 44 deletions
diff --git a/storage/innobase/row/row0uins.cc b/storage/innobase/row/row0uins.cc
index 651042fb820..ce5e02908b2 100644
--- a/storage/innobase/row/row0uins.cc
+++ b/storage/innobase/row/row0uins.cc
@@ -60,7 +60,7 @@ introduced where a call to log_free_check() is bypassed. */
/***************************************************************//**
Removes a clustered index record. The pcur in node was positioned on the
record, now it is detached.
-@return DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
+@return DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
static MY_ATTRIBUTE((nonnull, warn_unused_result))
dberr_t
row_undo_ins_remove_clust_rec(
@@ -76,8 +76,11 @@ row_undo_ins_remove_clust_rec(
bool online;
ut_ad(dict_index_is_clust(index));
+ ut_ad(node->trx->in_rollback);
mtr_start(&mtr);
+ mtr.set_named_space(index->space);
+ dict_disable_redo_if_temporary(index->table, &mtr);
/* This is similar to row_undo_mod_clust(). The DDL thread may
already have copied this row from the log to the new table.
@@ -103,24 +106,26 @@ row_undo_ins_remove_clust_rec(
ut_ad(rec_get_trx_id(btr_cur_get_rec(btr_cur), btr_cur->index)
== node->trx->id);
+ ut_ad(!rec_get_deleted_flag(
+ btr_cur_get_rec(btr_cur),
+ dict_table_is_comp(btr_cur->index->table)));
if (online && dict_index_is_online_ddl(index)) {
const rec_t* rec = btr_cur_get_rec(btr_cur);
mem_heap_t* heap = NULL;
const ulint* offsets = rec_get_offsets(
rec, index, NULL, ULINT_UNDEFINED, &heap);
- row_log_table_delete(rec, index, offsets, NULL);
+ row_log_table_delete(rec, node->row, index, offsets, NULL);
mem_heap_free(heap);
}
if (node->table->id == DICT_INDEXES_ID) {
+
ut_ad(!online);
ut_ad(node->trx->dict_operation_lock_mode == RW_X_LATCH);
- /* Drop the index tree associated with the row in
- SYS_INDEXES table: */
-
- dict_drop_index_tree(btr_pcur_get_rec(&(node->pcur)), &mtr);
+ dict_drop_index_tree(
+ btr_pcur_get_rec(&node->pcur), &(node->pcur), &mtr);
mtr_commit(&mtr);
@@ -140,15 +145,15 @@ row_undo_ins_remove_clust_rec(
retry:
/* If did not succeed, try pessimistic descent to tree */
mtr_start(&mtr);
+ mtr.set_named_space(index->space);
+ dict_disable_redo_if_temporary(index->table, &mtr);
- success = btr_pcur_restore_position(BTR_MODIFY_TREE,
- &(node->pcur), &mtr);
+ success = btr_pcur_restore_position(
+ BTR_MODIFY_TREE | BTR_LATCH_FOR_DELETE,
+ &node->pcur, &mtr);
ut_a(success);
- btr_cur_pessimistic_delete(&err, FALSE, btr_cur, 0,
- trx_is_recv(node->trx)
- ? RB_RECOVERY
- : RB_NORMAL, &mtr);
+ btr_cur_pessimistic_delete(&err, FALSE, btr_cur, 0, true, &mtr);
/* The delete operation may fail if we have little
file space left: TODO: easiest to crash the database
@@ -168,14 +173,13 @@ retry:
func_exit:
btr_pcur_commit_specify_mtr(&node->pcur, &mtr);
- trx_undo_rec_release(node->trx, node->undo_no);
return(err);
}
/***************************************************************//**
Removes a secondary index entry if found.
-@return DB_SUCCESS, DB_FAIL, or DB_OUT_OF_FILE_SPACE */
+@return DB_SUCCESS, DB_FAIL, or DB_OUT_OF_FILE_SPACE */
static MY_ATTRIBUTE((nonnull, warn_unused_result))
dberr_t
row_undo_ins_remove_sec_low(
@@ -184,30 +188,44 @@ row_undo_ins_remove_sec_low(
depending on whether we wish optimistic or
pessimistic descent down the index tree */
dict_index_t* index, /*!< in: index */
- dtuple_t* entry) /*!< in: index entry to remove */
+ dtuple_t* entry, /*!< in: index entry to remove */
+ que_thr_t* thr) /*!< in: query thread */
{
btr_pcur_t pcur;
btr_cur_t* btr_cur;
dberr_t err = DB_SUCCESS;
mtr_t mtr;
enum row_search_result search_result;
+ ibool modify_leaf = false;
log_free_check();
+ memset(&pcur, 0, sizeof(pcur));
mtr_start(&mtr);
+ mtr.set_named_space(index->space);
+ dict_disable_redo_if_temporary(index->table, &mtr);
if (mode == BTR_MODIFY_LEAF) {
mode = BTR_MODIFY_LEAF | BTR_ALREADY_S_LATCHED;
mtr_s_lock(dict_index_get_lock(index), &mtr);
+ modify_leaf = true;
} else {
- ut_ad(mode == BTR_MODIFY_TREE);
- mtr_x_lock(dict_index_get_lock(index), &mtr);
+ ut_ad(mode == (BTR_MODIFY_TREE | BTR_LATCH_FOR_DELETE));
+ mtr_sx_lock(dict_index_get_lock(index), &mtr);
}
if (row_log_online_op_try(index, entry, 0)) {
goto func_exit_no_pcur;
}
+ if (dict_index_is_spatial(index)) {
+ if (mode & BTR_MODIFY_LEAF) {
+ btr_pcur_get_btr_cur(&pcur)->thr = thr;
+ mode |= BTR_RTREE_DELETE_MARK;
+ }
+ mode |= BTR_RTREE_UNDO_INS;
+ }
+
search_result = row_search_index_entry(index, entry, mode,
&pcur, &mtr);
@@ -216,6 +234,7 @@ row_undo_ins_remove_sec_low(
goto func_exit;
case ROW_FOUND:
break;
+
case ROW_BUFFERED:
case ROW_NOT_DELETED_REF:
/* These are invalid outcomes, because the mode passed
@@ -224,20 +243,28 @@ row_undo_ins_remove_sec_low(
ut_error;
}
+ if (search_result == ROW_FOUND && dict_index_is_spatial(index)) {
+ rec_t* rec = btr_pcur_get_rec(&pcur);
+ if (rec_get_deleted_flag(rec,
+ dict_table_is_comp(index->table))) {
+ ib::error() << "Record found in index " << index->name
+ << " is deleted marked on insert rollback.";
+ }
+ }
+
btr_cur = btr_pcur_get_btr_cur(&pcur);
- if (mode != BTR_MODIFY_TREE) {
+ if (modify_leaf) {
err = btr_cur_optimistic_delete(btr_cur, 0, &mtr)
? DB_SUCCESS : DB_FAIL;
} else {
- /* No need to distinguish RB_RECOVERY here, because we
- are deleting a secondary index record: the distinction
- between RB_NORMAL and RB_RECOVERY only matters when
- deleting a record that contains externally stored
- columns. */
+ /* Passing rollback=false here, because we are
+ deleting a secondary index record: the distinction
+ only matters when deleting a record that contains
+ externally stored columns. */
ut_ad(!dict_index_is_clust(index));
btr_cur_pessimistic_delete(&err, FALSE, btr_cur, 0,
- RB_NORMAL, &mtr);
+ false, &mtr);
}
func_exit:
btr_pcur_close(&pcur);
@@ -250,20 +277,21 @@ func_exit_no_pcur:
/***************************************************************//**
Removes a secondary index entry from the index if found. Tries first
optimistic, then pessimistic descent down the tree.
-@return DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
+@return DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
static MY_ATTRIBUTE((nonnull, warn_unused_result))
dberr_t
row_undo_ins_remove_sec(
/*====================*/
dict_index_t* index, /*!< in: index */
- dtuple_t* entry) /*!< in: index entry to insert */
+ dtuple_t* entry, /*!< in: index entry to insert */
+ que_thr_t* thr) /*!< in: query thread */
{
dberr_t err;
ulint n_tries = 0;
/* Try first optimistic descent to the B-tree */
- err = row_undo_ins_remove_sec_low(BTR_MODIFY_LEAF, index, entry);
+ err = row_undo_ins_remove_sec_low(BTR_MODIFY_LEAF, index, entry, thr);
if (err == DB_SUCCESS) {
@@ -272,7 +300,9 @@ row_undo_ins_remove_sec(
/* Try then pessimistic descent to the B-tree */
retry:
- err = row_undo_ins_remove_sec_low(BTR_MODIFY_TREE, index, entry);
+ err = row_undo_ins_remove_sec_low(
+ BTR_MODIFY_TREE | BTR_LATCH_FOR_DELETE,
+ index, entry, thr);
/* The delete operation may fail if we have little
file space left: TODO: easiest to crash the database
@@ -328,20 +358,21 @@ close_table:
clust_index = dict_table_get_first_index(node->table);
if (clust_index != NULL) {
- trx_undo_rec_get_row_ref(
+ ptr = trx_undo_rec_get_row_ref(
ptr, clust_index, &node->ref, node->heap);
if (!row_undo_search_clust_to_pcur(node)) {
goto close_table;
}
+ if (node->table->n_v_cols) {
+ trx_undo_read_v_cols(node->table, ptr,
+ node->row, false, NULL);
+ }
} else {
- ut_print_timestamp(stderr);
- fprintf(stderr, " InnoDB: table ");
- ut_print_name(stderr, node->trx, TRUE,
- node->table->name);
- fprintf(stderr, " has no indexes, "
- "ignoring the table\n");
+ ib::warn() << "Table " << node->table->name
+ << " has no indexes,"
+ " ignoring the table";
goto close_table;
}
}
@@ -349,12 +380,13 @@ close_table:
/***************************************************************//**
Removes secondary index records.
-@return DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
+@return DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
static MY_ATTRIBUTE((nonnull, warn_unused_result))
dberr_t
row_undo_ins_remove_sec_rec(
/*========================*/
- undo_node_t* node) /*!< in/out: row undo node */
+ undo_node_t* node, /*!< in/out: row undo node */
+ que_thr_t* thr) /*!< in: query thread */
{
dberr_t err = DB_SUCCESS;
dict_index_t* index = node->index;
@@ -389,7 +421,7 @@ row_undo_ins_remove_sec_rec(
assume that the secondary index record does
not exist. */
} else {
- err = row_undo_ins_remove_sec(index, entry);
+ err = row_undo_ins_remove_sec(index, entry, thr);
if (UNIV_UNLIKELY(err != DB_SUCCESS)) {
goto func_exit;
@@ -412,25 +444,25 @@ the same clustered index unique key did not have any record, even delete
marked, at the time of the insert. InnoDB is eager in a rollback:
if it figures out that an index record will be removed in the purge
anyway, it will remove it in the rollback.
-@return DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
-UNIV_INTERN
+@return DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
dberr_t
row_undo_ins(
/*=========*/
- undo_node_t* node) /*!< in: row undo node */
+ undo_node_t* node, /*!< in: row undo node */
+ que_thr_t* thr) /*!< in: query thread */
{
dberr_t err;
ibool dict_locked;
ut_ad(node->state == UNDO_NODE_INSERT);
+ ut_ad(node->trx->in_rollback);
+ ut_ad(trx_undo_roll_ptr_is_insert(node->roll_ptr));
dict_locked = node->trx->dict_operation_lock_mode == RW_X_LATCH;
row_undo_ins_parse_undo_rec(node, dict_locked);
if (node->table == NULL) {
- trx_undo_rec_release(node->trx, node->undo_no);
-
return(DB_SUCCESS);
}
@@ -443,7 +475,7 @@ row_undo_ins(
dict_table_skip_corrupt_index(node->index);
- err = row_undo_ins_remove_sec_rec(node);
+ err = row_undo_ins_remove_sec_rec(node, thr);
if (err == DB_SUCCESS) {