diff options
Diffstat (limited to 'storage/xtradb/row/row0uins.cc')
-rw-r--r-- | storage/xtradb/row/row0uins.cc | 475 |
1 files changed, 0 insertions, 475 deletions
diff --git a/storage/xtradb/row/row0uins.cc b/storage/xtradb/row/row0uins.cc deleted file mode 100644 index f14a4ef9bcf..00000000000 --- a/storage/xtradb/row/row0uins.cc +++ /dev/null @@ -1,475 +0,0 @@ -/***************************************************************************** - -Copyright (c) 1997, 2016, Oracle and/or its affiliates. All Rights Reserved. - -This program is free software; you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free Software -Foundation; version 2 of the License. - -This program is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along with -this program; if not, write to the Free Software Foundation, Inc., -51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA - -*****************************************************************************/ - -/**************************************************//** -@file row/row0uins.cc -Fresh insert undo - -Created 2/25/1997 Heikki Tuuri -*******************************************************/ - -#include "row0uins.h" - -#ifdef UNIV_NONINL -#include "row0uins.ic" -#endif - -#include "dict0dict.h" -#include "dict0boot.h" -#include "dict0crea.h" -#include "trx0undo.h" -#include "trx0roll.h" -#include "btr0btr.h" -#include "mach0data.h" -#include "row0undo.h" -#include "row0vers.h" -#include "row0log.h" -#include "trx0trx.h" -#include "trx0rec.h" -#include "row0row.h" -#include "row0upd.h" -#include "que0que.h" -#include "ibuf0ibuf.h" -#include "log0log.h" - -/************************************************************************* -IMPORTANT NOTE: Any operation that generates redo MUST check that there -is enough space in the redo log before for that operation. This is -done by calling log_free_check(). The reason for checking the -availability of the redo log space before the start of the operation is -that we MUST not hold any synchonization objects when performing the -check. -If you make a change in this module make sure that no codepath is -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 */ -static MY_ATTRIBUTE((nonnull, warn_unused_result)) -dberr_t -row_undo_ins_remove_clust_rec( -/*==========================*/ - undo_node_t* node) /*!< in: undo node */ -{ - btr_cur_t* btr_cur; - ibool success; - dberr_t err; - ulint n_tries = 0; - mtr_t mtr; - dict_index_t* index = node->pcur.btr_cur.index; - bool online; - - ut_ad(dict_index_is_clust(index)); - - mtr_start(&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. - We must log the removal, so that the row will be correctly - purged. However, we can log the removal out of sync with the - B-tree modification. */ - - online = dict_index_is_online_ddl(index); - if (online) { - ut_ad(node->trx->dict_operation_lock_mode - != RW_X_LATCH); - ut_ad(node->table->id != DICT_INDEXES_ID); - mtr_s_lock(dict_index_get_lock(index), &mtr); - } - - success = btr_pcur_restore_position( - online - ? BTR_MODIFY_LEAF | BTR_ALREADY_S_LATCHED - : BTR_MODIFY_LEAF, &node->pcur, &mtr); - ut_a(success); - - btr_cur = btr_pcur_get_btr_cur(&node->pcur); - - ut_ad(rec_get_trx_id(btr_cur_get_rec(btr_cur), btr_cur->index) - == node->trx->id); - - 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); - 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); - - mtr_commit(&mtr); - - mtr_start(&mtr); - - success = btr_pcur_restore_position( - BTR_MODIFY_LEAF, &node->pcur, &mtr); - ut_a(success); - } - - if (btr_cur_optimistic_delete(btr_cur, 0, &mtr)) { - err = DB_SUCCESS; - goto func_exit; - } - - btr_pcur_commit_specify_mtr(&node->pcur, &mtr); -retry: - /* If did not succeed, try pessimistic descent to tree */ - mtr_start(&mtr); - - success = btr_pcur_restore_position(BTR_MODIFY_TREE, - &(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); - - /* The delete operation may fail if we have little - file space left: TODO: easiest to crash the database - and restart with more file space */ - - if (err == DB_OUT_OF_FILE_SPACE - && n_tries < BTR_CUR_RETRY_DELETE_N_TIMES) { - - btr_pcur_commit_specify_mtr(&(node->pcur), &mtr); - - n_tries++; - - os_thread_sleep(BTR_CUR_RETRY_SLEEP_TIME); - - goto 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 */ -static MY_ATTRIBUTE((nonnull, warn_unused_result)) -dberr_t -row_undo_ins_remove_sec_low( -/*========================*/ - ulint mode, /*!< in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE, - 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 */ -{ - btr_pcur_t pcur; - btr_cur_t* btr_cur; - dberr_t err = DB_SUCCESS; - mtr_t mtr; - enum row_search_result search_result; - - log_free_check(); - - mtr_start(&mtr); - - if (mode == BTR_MODIFY_LEAF) { - mode = BTR_MODIFY_LEAF | BTR_ALREADY_S_LATCHED; - mtr_s_lock(dict_index_get_lock(index), &mtr); - } else { - ut_ad(mode == BTR_MODIFY_TREE); - mtr_x_lock(dict_index_get_lock(index), &mtr); - } - - if (row_log_online_op_try(index, entry, 0)) { - goto func_exit_no_pcur; - } - - search_result = row_search_index_entry(index, entry, mode, - &pcur, &mtr); - - switch (search_result) { - case ROW_NOT_FOUND: - goto func_exit; - case ROW_FOUND: - break; - case ROW_BUFFERED: - case ROW_NOT_DELETED_REF: - /* These are invalid outcomes, because the mode passed - to row_search_index_entry() did not include any of the - flags BTR_INSERT, BTR_DELETE, or BTR_DELETE_MARK. */ - ut_error; - } - - btr_cur = btr_pcur_get_btr_cur(&pcur); - - if (mode != BTR_MODIFY_TREE) { - 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. */ - ut_ad(!dict_index_is_clust(index)); - btr_cur_pessimistic_delete(&err, FALSE, btr_cur, 0, - RB_NORMAL, &mtr); - } -func_exit: - btr_pcur_close(&pcur); -func_exit_no_pcur: - mtr_commit(&mtr); - - return(err); -} - -/***************************************************************//** -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 */ -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 */ -{ - 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); - - if (err == DB_SUCCESS) { - - return(err); - } - - /* Try then pessimistic descent to the B-tree */ -retry: - err = row_undo_ins_remove_sec_low(BTR_MODIFY_TREE, index, entry); - - /* The delete operation may fail if we have little - file space left: TODO: easiest to crash the database - and restart with more file space */ - - if (err != DB_SUCCESS && n_tries < BTR_CUR_RETRY_DELETE_N_TIMES) { - - n_tries++; - - os_thread_sleep(BTR_CUR_RETRY_SLEEP_TIME); - - goto retry; - } - - return(err); -} - -/***********************************************************//** -Parses the row reference and other info in a fresh insert undo record. */ -static -void -row_undo_ins_parse_undo_rec( -/*========================*/ - undo_node_t* node, /*!< in/out: row undo node */ - ibool dict_locked) /*!< in: TRUE if own dict_sys->mutex */ -{ - dict_index_t* clust_index; - byte* ptr; - undo_no_t undo_no; - table_id_t table_id; - ulint type; - ulint dummy; - bool dummy_extern; - - ut_ad(node); - - ptr = trx_undo_rec_get_pars(node->undo_rec, &type, &dummy, - &dummy_extern, &undo_no, &table_id); - ut_ad(type == TRX_UNDO_INSERT_REC); - node->rec_type = type; - - node->update = NULL; - node->table = dict_table_open_on_id( - table_id, dict_locked, DICT_TABLE_OP_NORMAL); - - /* Skip the UNDO if we can't find the table or the .ibd file. */ - if (UNIV_UNLIKELY(node->table == NULL)) { - } else if (UNIV_UNLIKELY(node->table->file_unreadable)) { -close_table: - dict_table_close(node->table, dict_locked, FALSE); - node->table = NULL; - } else { - clust_index = dict_table_get_first_index(node->table); - - if (clust_index != NULL) { - trx_undo_rec_get_row_ref( - ptr, clust_index, &node->ref, node->heap); - - if (!row_undo_search_clust_to_pcur(node)) { - goto close_table; - } - - } 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"); - goto close_table; - } - } -} - -/***************************************************************//** -Removes secondary index records. -@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 */ -{ - dberr_t err = DB_SUCCESS; - dict_index_t* index = node->index; - mem_heap_t* heap; - - heap = mem_heap_create(1024); - - while (index != NULL) { - dtuple_t* entry; - - if (index->type & DICT_FTS) { - dict_table_next_uncorrupted_index(index); - continue; - } - - /* An insert undo record TRX_UNDO_INSERT_REC will - always contain all fields of the index. It does not - matter if any indexes were created afterwards; all - index entries can be reconstructed from the row. */ - entry = row_build_index_entry( - node->row, node->ext, index, heap); - if (UNIV_UNLIKELY(!entry)) { - /* The database must have crashed after - inserting a clustered index record but before - writing all the externally stored columns of - that record, or a statement is being rolled - back because an error occurred while storing - off-page columns. - - Because secondary index entries are inserted - after the clustered index record, we may - assume that the secondary index record does - not exist. */ - } else { - err = row_undo_ins_remove_sec(index, entry); - - if (UNIV_UNLIKELY(err != DB_SUCCESS)) { - goto func_exit; - } - } - - mem_heap_empty(heap); - dict_table_next_uncorrupted_index(index); - } - -func_exit: - node->index = index; - mem_heap_free(heap); - return(err); -} - -/***********************************************************//** -Undoes a fresh insert of a row to a table. A fresh insert means that -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 -dberr_t -row_undo_ins( -/*=========*/ - undo_node_t* node) /*!< in: row undo node */ -{ - dberr_t err; - ibool dict_locked; - - ut_ad(node->state == UNDO_NODE_INSERT); - - 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); - } - - /* Iterate over all the indexes and undo the insert.*/ - - node->index = dict_table_get_first_index(node->table); - ut_ad(dict_index_is_clust(node->index)); - /* Skip the clustered index (the first index) */ - node->index = dict_table_get_next_index(node->index); - - dict_table_skip_corrupt_index(node->index); - - err = row_undo_ins_remove_sec_rec(node); - - if (err == DB_SUCCESS) { - - log_free_check(); - - if (node->table->id == DICT_INDEXES_ID) { - - if (!dict_locked) { - mutex_enter(&dict_sys->mutex); - } - } - - // FIXME: We need to update the dict_index_t::space and - // page number fields too. - err = row_undo_ins_remove_clust_rec(node); - - if (node->table->id == DICT_INDEXES_ID - && !dict_locked) { - - mutex_exit(&dict_sys->mutex); - } - } - - dict_table_close(node->table, dict_locked, FALSE); - - node->table = NULL; - - return(err); -} |