/***************************************************************************** Copyright (c) 2008, 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 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 api/api0misc.cc InnoDB Native API 2008-08-01 Created by Sunny Bains 3/20/2011 Jimmy Yang extracted from Embedded InnoDB *******************************************************/ #include #include #ifdef HAVE_UNISTD_H #include #endif /* HAVE_UNISTD_H */ #include "api0misc.h" #include "trx0roll.h" #include "srv0srv.h" #include "dict0mem.h" #include "dict0dict.h" #include "pars0pars.h" #include "row0sel.h" #include "lock0lock.h" #include "ha_prototypes.h" #include #include #include /*********************************************************************//** Sets a lock on a table. @return error code or DB_SUCCESS */ UNIV_INTERN dberr_t ib_trx_lock_table_with_retry( /*=========================*/ trx_t* trx, /*!< in/out: transaction */ dict_table_t* table, /*!< in: table to lock */ enum lock_mode mode) /*!< in: LOCK_X or LOCK_S */ { que_thr_t* thr; dberr_t err; mem_heap_t* heap; sel_node_t* node; heap = mem_heap_create(512); trx->op_info = "setting table lock"; node = sel_node_create(heap); thr = pars_complete_graph_for_exec(node, trx, heap); thr->graph->state = QUE_FORK_ACTIVE; /* We use the select query graph as the dummy graph needed in the lock module call */ thr = que_fork_get_first_thr(static_cast( que_node_get_parent(thr))); que_thr_move_to_run_state_for_mysql(thr, trx); run_again: thr->run_node = thr; thr->prev_node = thr->common.parent; err = lock_table(0, table, mode, thr); trx->error_state = err; if (UNIV_LIKELY(err == DB_SUCCESS)) { que_thr_stop_for_mysql_no_error(thr, trx); } else { que_thr_stop_for_mysql(thr); if (err != DB_QUE_THR_SUSPENDED) { ibool was_lock_wait; was_lock_wait = ib_handle_errors(&err, trx, thr, NULL); if (was_lock_wait) { goto run_again; } } else { que_thr_t* run_thr; que_node_t* parent; parent = que_node_get_parent(thr); run_thr = que_fork_start_command( static_cast(parent)); ut_a(run_thr == thr); /* There was a lock wait but the thread was not in a ready to run or running state. */ trx->error_state = DB_LOCK_WAIT; goto run_again; } } que_graph_free(thr->graph); trx->op_info = ""; return(err); } /****************************************************************//** Handles user errors and lock waits detected by the database engine. @return TRUE if it was a lock wait and we should continue running the query thread */ UNIV_INTERN ibool ib_handle_errors( /*=============*/ dberr_t* new_err,/*!< out: possible new error encountered in lock wait, or if no new error, the value of trx->error_state at the entry of this function */ trx_t* trx, /*!< in: transaction */ que_thr_t* thr, /*!< in: query thread */ trx_savept_t* savept) /*!< in: savepoint or NULL */ { dberr_t err; handle_new_error: err = trx->error_state; ut_a(err != DB_SUCCESS); trx->error_state = DB_SUCCESS; switch (err) { case DB_LOCK_WAIT_TIMEOUT: trx_rollback_for_mysql(trx); break; /* fall through */ case DB_DUPLICATE_KEY: case DB_FOREIGN_DUPLICATE_KEY: case DB_TOO_BIG_RECORD: case DB_ROW_IS_REFERENCED: case DB_NO_REFERENCED_ROW: case DB_CANNOT_ADD_CONSTRAINT: case DB_TOO_MANY_CONCURRENT_TRXS: case DB_OUT_OF_FILE_SPACE: if (savept) { /* Roll back the latest, possibly incomplete insertion or update */ trx_rollback_to_savepoint(trx, savept); } break; case DB_LOCK_WAIT: lock_wait_suspend_thread(thr); if (trx->error_state != DB_SUCCESS) { que_thr_stop_for_mysql(thr); goto handle_new_error; } *new_err = err; return(TRUE); /* Operation needs to be retried. */ case DB_DEADLOCK: case DB_LOCK_TABLE_FULL: /* Roll back the whole transaction; this resolution was added to version 3.23.43 */ trx_rollback_for_mysql(trx); break; case DB_CORRUPTION: case DB_FOREIGN_EXCEED_MAX_CASCADE: break; default: ut_error; } if (trx->error_state != DB_SUCCESS) { *new_err = trx->error_state; } else { *new_err = err; } trx->error_state = DB_SUCCESS; return(FALSE); }