diff options
Diffstat (limited to 'storage/innobase/row/row0uins.cc')
-rw-r--r-- | storage/innobase/row/row0uins.cc | 194 |
1 files changed, 131 insertions, 63 deletions
diff --git a/storage/innobase/row/row0uins.cc b/storage/innobase/row/row0uins.cc index 78fd4ad5199..25b2b6b62ce 100644 --- a/storage/innobase/row/row0uins.cc +++ b/storage/innobase/row/row0uins.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1997, 2010, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1997, 2012, 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 @@ -38,6 +38,7 @@ Created 2/25/1997 Heikki Tuuri #include "mach0data.h" #include "row0undo.h" #include "row0vers.h" +#include "row0log.h" #include "trx0trx.h" #include "trx0rec.h" #include "row0row.h" @@ -60,25 +61,64 @@ 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 -ulint +static __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; - ulint err; - ulint n_tries = 0; + 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); - success = btr_pcur_restore_position(BTR_MODIFY_LEAF, &(node->pcur), - &mtr); + /* This is similar to row_undo_mod_clust(). Even though we + call row_log_table_rollback() elsewhere, the DDL thread may + already have copied this row to the sort buffers or 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, + trx_read_trx_id(row_get_trx_id_offset(index, offsets) + + rec)); + 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 @@ -90,14 +130,12 @@ row_undo_ins_remove_clust_rec( mtr_start(&mtr); - success = btr_pcur_restore_position(BTR_MODIFY_LEAF, - &(node->pcur), &mtr); + success = btr_pcur_restore_position( + BTR_MODIFY_LEAF, &node->pcur, &mtr); ut_a(success); } - btr_cur = btr_pcur_get_btr_cur(&(node->pcur)); - - if (btr_cur_optimistic_delete(btr_cur, &mtr)) { + if (btr_cur_optimistic_delete(btr_cur, 0, &mtr)) { err = DB_SUCCESS; goto func_exit; } @@ -111,7 +149,7 @@ retry: &(node->pcur), &mtr); ut_a(success); - btr_cur_pessimistic_delete(&err, FALSE, btr_cur, + btr_cur_pessimistic_delete(&err, FALSE, btr_cur, 0, trx_is_recv(node->trx) ? RB_RECOVERY : RB_NORMAL, &mtr); @@ -142,8 +180,8 @@ func_exit: /***************************************************************//** Removes a secondary index entry if found. @return DB_SUCCESS, DB_FAIL, or DB_OUT_OF_FILE_SPACE */ -static -ulint +static __attribute__((nonnull, warn_unused_result)) +dberr_t row_undo_ins_remove_sec_low( /*========================*/ ulint mode, /*!< in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE, @@ -154,22 +192,31 @@ row_undo_ins_remove_sec_low( { btr_pcur_t pcur; btr_cur_t* btr_cur; - ulint err; + dberr_t err = DB_SUCCESS; mtr_t mtr; enum row_search_result search_result; + log_free_check(); + mtr_start(&mtr); - btr_cur = btr_pcur_get_btr_cur(&pcur); + 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); + } - ut_ad(mode == BTR_MODIFY_TREE || mode == BTR_MODIFY_LEAF); + 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: - err = DB_SUCCESS; goto func_exit; case ROW_FOUND: break; @@ -181,23 +228,24 @@ row_undo_ins_remove_sec_low( ut_error; } - if (mode == BTR_MODIFY_LEAF) { - err = btr_cur_optimistic_delete(btr_cur, &mtr) + 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 { - ut_ad(mode == BTR_MODIFY_TREE); - /* 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, + 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); @@ -207,14 +255,14 @@ func_exit: 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 -ulint +static __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 */ { - ulint err; + dberr_t err; ulint n_tries = 0; /* Try first optimistic descent to the B-tree */ @@ -261,7 +309,7 @@ row_undo_ins_parse_undo_rec( table_id_t table_id; ulint type; ulint dummy; - ibool dummy_extern; + bool dummy_extern; ut_ad(node); @@ -271,12 +319,13 @@ row_undo_ins_parse_undo_rec( node->rec_type = type; node->update = NULL; - node->table = dict_table_open_on_id(table_id, dict_locked); + node->table = dict_table_open_on_id(table_id, dict_locked, FALSE); /* 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->ibd_file_missing)) { - dict_table_close(node->table, dict_locked); +close_table: + dict_table_close(node->table, dict_locked, FALSE); node->table = NULL; } else { clust_index = dict_table_get_first_index(node->table); @@ -286,10 +335,7 @@ row_undo_ins_parse_undo_rec( ptr, clust_index, &node->ref, node->heap); if (!row_undo_search_clust_to_pcur(node)) { - - dict_table_close(node->table, dict_locked); - - node->table = NULL; + goto close_table; } } else { @@ -299,10 +345,7 @@ row_undo_ins_parse_undo_rec( node->table->name); fprintf(stderr, " has no indexes, " "ignoring the table\n"); - - dict_table_close(node->table, dict_locked); - - node->table = NULL; + goto close_table; } } } @@ -310,27 +353,32 @@ row_undo_ins_parse_undo_rec( /***************************************************************//** Removes secondary index records. @return DB_SUCCESS or DB_OUT_OF_FILE_SPACE */ -static -ulint +static __attribute__((nonnull, warn_unused_result)) +dberr_t row_undo_ins_remove_sec_rec( /*========================*/ undo_node_t* node) /*!< in/out: row undo node */ { - ulint err = DB_SUCCESS; + dberr_t err = DB_SUCCESS; + dict_index_t* index = node->index; mem_heap_t* heap; heap = mem_heap_create(1024); - while (node->index != NULL) { + while (index != NULL) { dtuple_t* entry; - if (node->index->type & DICT_FTS) { - dict_table_next_uncorrupted_index(node->index); + if (index->type & DICT_FTS) { + dict_table_next_uncorrupted_index(index); continue; } - entry = row_build_index_entry(node->row, node->ext, - node->index, heap); + /* 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 @@ -343,9 +391,7 @@ row_undo_ins_remove_sec_rec( transactions. */ ut_a(trx_is_recv(node->trx)); } else { - log_free_check(); - - err = row_undo_ins_remove_sec(node->index, entry); + err = row_undo_ins_remove_sec(index, entry); if (UNIV_UNLIKELY(err != DB_SUCCESS)) { goto func_exit; @@ -353,10 +399,11 @@ row_undo_ins_remove_sec_rec( } mem_heap_empty(heap); - dict_table_next_uncorrupted_index(node->index); + dict_table_next_uncorrupted_index(index); } func_exit: + node->index = index; mem_heap_free(heap); return(err); } @@ -369,15 +416,14 @@ 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 -ulint +dberr_t row_undo_ins( /*=========*/ undo_node_t* node) /*!< in: row undo node */ { - ulint err; - ibool dict_locked; + dberr_t err; + ibool dict_locked; - ut_ad(node); ut_ad(node->state == UNDO_NODE_INSERT); dict_locked = node->trx->dict_operation_lock_mode == RW_X_LATCH; @@ -392,24 +438,46 @@ row_undo_ins( /* 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)); + + if (dict_index_is_online_ddl(node->index)) { + /* Note that we are rolling back this transaction, so + that all inserts and updates with this DB_TRX_ID can + be skipped. */ + row_log_table_rollback(node->index, node->trx->id); + } + /* Skip the clustered index (the first index) */ - node->index = dict_table_get_next_index( - dict_table_get_first_index(node->table)); + 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 (UNIV_UNLIKELY(err != DB_SUCCESS)) { - goto func_exit; - } + if (err == DB_SUCCESS) { - log_free_check(); + log_free_check(); - err = row_undo_ins_remove_clust_rec(node); + if (node->table->id == DICT_INDEXES_ID) { -func_exit: - dict_table_close(node->table, dict_locked); + 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; |