diff options
Diffstat (limited to 'storage/innobase/row/row0umod.c')
-rw-r--r-- | storage/innobase/row/row0umod.c | 112 |
1 files changed, 73 insertions, 39 deletions
diff --git a/storage/innobase/row/row0umod.c b/storage/innobase/row/row0umod.c index 6be475d8c78..80f57870316 100644 --- a/storage/innobase/row/row0umod.c +++ b/storage/innobase/row/row0umod.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1997, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1997, 2010, Innobase Oy. 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 @@ -144,13 +144,17 @@ row_undo_mod_clust_low( /***********************************************************//** Removes a clustered index record after undo if possible. +This is attempted when the record was inserted by updating a +delete-marked record and there no longer exist transactions +that would see the delete-marked record. In other words, we +roll back the insert by purging the record. @return DB_SUCCESS, DB_FAIL, or error code: we may run out of file space */ static ulint row_undo_mod_remove_clust_low( /*==========================*/ undo_node_t* node, /*!< in: row undo node */ - que_thr_t* thr __attribute__((unused)), /*!< in: query thread */ + que_thr_t* thr, /*!< in: query thread */ mtr_t* mtr, /*!< in: mtr */ ulint mode) /*!< in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE */ { @@ -159,6 +163,7 @@ row_undo_mod_remove_clust_low( ulint err; ibool success; + ut_ad(node->rec_type == TRX_UNDO_UPD_DEL_REC); pcur = &(node->pcur); btr_cur = btr_pcur_get_btr_cur(pcur); @@ -190,11 +195,13 @@ row_undo_mod_remove_clust_low( } else { ut_ad(mode == BTR_MODIFY_TREE); - /* Note that since this operation is analogous to purge, - we can free also inherited externally stored fields: - hence the RB_NONE in the call below */ + /* This operation is analogous to purge, we can free also + inherited externally stored fields */ - btr_cur_pessimistic_delete(&err, FALSE, btr_cur, RB_NONE, mtr); + btr_cur_pessimistic_delete(&err, FALSE, btr_cur, + thr_is_recv(thr) + ? RB_RECOVERY_PURGE_REC + : RB_NONE, mtr); /* The delete operation may fail if we have little file space left: TODO: easiest to crash the database @@ -307,23 +314,27 @@ row_undo_mod_del_mark_or_remove_sec_low( ulint mode) /*!< in: latch mode BTR_MODIFY_LEAF or BTR_MODIFY_TREE */ { - ibool found; - btr_pcur_t pcur; - btr_cur_t* btr_cur; - ibool success; - ibool old_has; - ulint err; - mtr_t mtr; - mtr_t mtr_vers; + btr_pcur_t pcur; + btr_cur_t* btr_cur; + ibool success; + ibool old_has; + ulint err; + mtr_t mtr; + mtr_t mtr_vers; + enum row_search_result search_result; log_free_check(); mtr_start(&mtr); - found = row_search_index_entry(index, entry, mode, &pcur, &mtr); - btr_cur = btr_pcur_get_btr_cur(&pcur); - if (!found) { + ut_ad(mode == BTR_MODIFY_TREE || mode == BTR_MODIFY_LEAF); + + search_result = row_search_index_entry(index, entry, mode, + &pcur, &mtr); + + switch (UNIV_EXPECT(search_result, ROW_FOUND)) { + case ROW_NOT_FOUND: /* In crash recovery, the secondary index record may be missing if the UPDATE did not have time to insert the secondary index records before the crash. When we @@ -334,10 +345,16 @@ row_undo_mod_del_mark_or_remove_sec_low( before it has inserted all updated secondary index records, then the undo will not find those records. */ - btr_pcur_close(&pcur); - mtr_commit(&mtr); - - return(DB_SUCCESS); + err = DB_SUCCESS; + 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; } /* We should remove the index record if no prior version of the row, @@ -370,10 +387,11 @@ row_undo_mod_del_mark_or_remove_sec_low( } 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 + /* No need to distinguish RB_RECOVERY_PURGE here, + because we are deleting a secondary index record: + the distinction between RB_NORMAL and + RB_RECOVERY_PURGE 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, @@ -386,6 +404,8 @@ row_undo_mod_del_mark_or_remove_sec_low( } btr_pcur_commit_specify_mtr(&(node->pcur), &mtr_vers); + +func_exit: btr_pcur_close(&pcur); mtr_commit(&mtr); @@ -438,15 +458,17 @@ row_undo_mod_del_unmark_sec_and_undo_update( BTR_MODIFY_TREE */ que_thr_t* thr, /*!< in: query thread */ dict_index_t* index, /*!< in: index */ - dtuple_t* entry) /*!< in: index entry */ + const dtuple_t* entry) /*!< in: index entry */ { - mem_heap_t* heap; - btr_pcur_t pcur; - upd_t* update; - ulint err = DB_SUCCESS; - big_rec_t* dummy_big_rec; - mtr_t mtr; - trx_t* trx = thr_get_trx(thr); + mem_heap_t* heap; + btr_pcur_t pcur; + btr_cur_t* btr_cur; + upd_t* update; + ulint err = DB_SUCCESS; + big_rec_t* dummy_big_rec; + mtr_t mtr; + trx_t* trx = thr_get_trx(thr); + enum row_search_result search_result; /* Ignore indexes that are being created. */ if (UNIV_UNLIKELY(*index->name == TEMP_INDEX_PREFIX)) { @@ -457,8 +479,19 @@ row_undo_mod_del_unmark_sec_and_undo_update( log_free_check(); mtr_start(&mtr); - if (UNIV_UNLIKELY(!row_search_index_entry(index, entry, - mode, &pcur, &mtr))) { + ut_ad(mode == BTR_MODIFY_TREE || mode == BTR_MODIFY_LEAF); + + search_result = row_search_index_entry(index, entry, mode, + &pcur, &mtr); + + switch (search_result) { + 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; + case ROW_NOT_FOUND: fputs("InnoDB: error in sec index entry del undo in\n" "InnoDB: ", stderr); dict_index_name_print(stderr, trx, index); @@ -473,9 +506,9 @@ row_undo_mod_del_unmark_sec_and_undo_update( fputs("\n" "InnoDB: Submit a detailed bug report" " to http://bugs.mysql.com\n", stderr); - } else { - btr_cur_t* btr_cur = btr_pcur_get_btr_cur(&pcur); - + break; + case ROW_FOUND: + btr_cur = btr_pcur_get_btr_cur(&pcur); err = btr_cur_del_mark_set_sec_rec(BTR_NO_LOCKING_FLAG, btr_cur, FALSE, thr, &mtr); ut_a(err == DB_SUCCESS); @@ -533,6 +566,7 @@ row_undo_mod_upd_del_sec( dict_index_t* index; ulint err = DB_SUCCESS; + ut_ad(node->rec_type == TRX_UNDO_UPD_DEL_REC); heap = mem_heap_create(1024); while (node->index != NULL) { @@ -550,7 +584,7 @@ row_undo_mod_upd_del_sec( does not exist. However, this situation may only occur during the rollback of incomplete transactions. */ - ut_a(trx_is_recv(thr_get_trx(thr))); + ut_a(thr_is_recv(thr)); } else { err = row_undo_mod_del_mark_or_remove_sec( node, thr, index, entry); |