diff options
Diffstat (limited to 'storage/innobase/row/row0uins.cc')
-rw-r--r-- | storage/innobase/row/row0uins.cc | 120 |
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) { |