summaryrefslogtreecommitdiff
path: root/storage/innobase/lock/lock0lock.cc
diff options
context:
space:
mode:
Diffstat (limited to 'storage/innobase/lock/lock0lock.cc')
-rw-r--r--storage/innobase/lock/lock0lock.cc157
1 files changed, 76 insertions, 81 deletions
diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc
index b397735e997..7e7558aff32 100644
--- a/storage/innobase/lock/lock0lock.cc
+++ b/storage/innobase/lock/lock0lock.cc
@@ -72,44 +72,39 @@ extern "C" void thd_rpl_deadlock_check(MYSQL_THD thd, MYSQL_THD other_thd);
extern "C" int thd_need_wait_reports(const MYSQL_THD thd);
extern "C" int thd_need_ordering_with(const MYSQL_THD thd, const MYSQL_THD other_thd);
-/** Print info of a table lock.
+/** Pretty-print a table lock.
@param[in,out] file output stream
@param[in] lock table lock */
-static
-void
-lock_table_print(FILE* file, const lock_t* lock);
+static void lock_table_print(FILE* file, const lock_t* lock);
-/** Print info of a record lock.
+/** Pretty-print a record lock.
@param[in,out] file output stream
-@param[in] lock record lock */
-static
-void
-lock_rec_print(FILE* file, const lock_t* lock);
+@param[in] lock record lock
+@param[in,out] mtr mini-transaction for accessing the record */
+static void lock_rec_print(FILE* file, const lock_t* lock, mtr_t& mtr);
/** Deadlock checker. */
class DeadlockChecker {
public:
- /** Checks if a joining lock request results in a deadlock. If
- a deadlock is found this function will resolve the deadlock
- by choosing a victim transaction and rolling it back. It
- will attempt to resolve all deadlocks. The returned transaction
- id will be the joining transaction id or 0 if some other
- transaction was chosen as a victim and rolled back or no
- deadlock found.
-
- @param lock lock the transaction is requesting
- @param trx transaction requesting the lock
-
- @return id of transaction chosen as victim or 0 */
- static const trx_t* check_and_resolve(
- const lock_t* lock,
- trx_t* trx);
+ /** Check if a joining lock request results in a deadlock.
+ If a deadlock is found, we will resolve the deadlock by
+ choosing a victim transaction and rolling it back.
+ We will attempt to resolve all deadlocks.
+
+ @param[in] lock the lock request
+ @param[in,out] trx transaction requesting the lock
+
+ @return trx if it was chosen as victim
+ @retval NULL if another victim was chosen,
+ or there is no deadlock (any more) */
+ static const trx_t* check_and_resolve(const lock_t* lock, trx_t* trx);
private:
/** Do a shallow copy. Default destructor OK.
@param trx the start transaction (start node)
@param wait_lock lock that a transaction wants
- @param mark_start visited node counter */
+ @param mark_start visited node counter
+ @param report_waiters whether to call thd_rpl_deadlock_check() */
DeadlockChecker(
const trx_t* trx,
const lock_t* wait_lock,
@@ -751,11 +746,12 @@ lock_rec_has_to_wait(
thread, we need to look at trx ordering and lock types */
if (wsrep_thd_is_BF(trx->mysql_thd, FALSE)
&& wsrep_thd_is_BF(lock2->trx->mysql_thd, TRUE)) {
+ mtr_t mtr;
if (wsrep_debug) {
ib::info() << "BF-BF lock conflict, locking: "
<< for_locking;
- lock_rec_print(stderr, lock2);
+ lock_rec_print(stderr, lock2, mtr);
ib::info()
<< " SQL1: " << wsrep_thd_query(trx->mysql_thd)
<< " SQL2: "
@@ -777,7 +773,7 @@ lock_rec_has_to_wait(
<< " locked "
<< wsrep_thd_transaction_state_str(
lock2->trx->mysql_thd);
- lock_rec_print(stderr, lock2);
+ lock_rec_print(stderr, lock2, mtr);
ib::info() << " SQL1: "
<< wsrep_thd_query(trx->mysql_thd)
<< " SQL2: "
@@ -1100,6 +1096,7 @@ wsrep_kill_victim(
}
my_bool bf_other = wsrep_thd_is_BF(lock->trx->mysql_thd, TRUE);
+ mtr_t mtr;
if ((!bf_other) ||
(wsrep_thd_order_before(
@@ -1127,7 +1124,7 @@ wsrep_kill_victim(
ib::info() << "*** WAITING FOR THIS LOCK TO BE GRANTED:";
if (lock_get_type(lock) == LOCK_REC) {
- lock_rec_print(stderr, lock);
+ lock_rec_print(stderr, lock, mtr);
} else {
lock_table_print(stderr, lock);
}
@@ -1293,6 +1290,7 @@ wsrep_print_wait_locks(
lock_t* c_lock) /* conflicting lock to print */
{
if (wsrep_debug && c_lock->trx->lock.wait_lock != c_lock) {
+ mtr_t mtr;
ib::info() << "WSREP: c_lock != wait lock";
ib::info() << " SQL: "
<< wsrep_thd_query(c_lock->trx->mysql_thd);
@@ -1300,13 +1298,14 @@ wsrep_print_wait_locks(
if (lock_get_type_low(c_lock) & LOCK_TABLE) {
lock_table_print(stderr, c_lock);
} else {
- lock_rec_print(stderr, c_lock);
+ lock_rec_print(stderr, c_lock, mtr);
}
if (lock_get_type_low(c_lock->trx->lock.wait_lock) & LOCK_TABLE) {
lock_table_print(stderr, c_lock->trx->lock.wait_lock);
} else {
- lock_rec_print(stderr, c_lock->trx->lock.wait_lock);
+ lock_rec_print(stderr, c_lock->trx->lock.wait_lock,
+ mtr);
}
}
}
@@ -1519,11 +1518,7 @@ If only one of them is a wait lock, it has lower priority.
If either is a high priority transaction, the lock has higher priority.
Otherwise, the one with an older transaction has higher priority.
@returns true if lock1 has higher priority, false otherwise. */
-static
-bool
-has_higher_priority(
- lock_t *lock1,
- lock_t *lock2)
+static bool has_higher_priority(lock_t *lock1, lock_t *lock2)
{
if (lock1 == NULL) {
return false;
@@ -1730,10 +1725,7 @@ lock_rec_enqueue_waiting(
lock_prdt_set_prdt(lock, prdt);
}
- if (
-#ifdef UNIV_DEBUG
- const trx_t* victim =
-#endif
+ if (ut_d(const trx_t* victim =)
DeadlockChecker::check_and_resolve(lock, trx)) {
ut_ad(victim == trx);
lock_reset_lock_and_trx_wait(lock);
@@ -1757,7 +1749,7 @@ lock_rec_enqueue_waiting(
trx->lock.que_state = TRX_QUE_LOCK_WAIT;
trx->lock.was_chosen_as_deadlock_victim = false;
- trx->lock.wait_started = ut_time();
+ trx->lock.wait_started = time(NULL);
ut_a(que_thr_stop(thr));
@@ -2067,12 +2059,13 @@ lock_rec_has_to_wait_in_queue(
if (wsrep_thd_is_BF(wait_lock->trx->mysql_thd, FALSE) &&
wsrep_thd_is_BF(lock->trx->mysql_thd, TRUE)) {
if (wsrep_debug) {
+ mtr_t mtr;
ib::info() << "WSREP: waiting BF trx: " << ib::hex(wait_lock->trx->id)
<< " query: " << wsrep_thd_query(wait_lock->trx->mysql_thd);
- lock_rec_print(stderr, wait_lock);
+ lock_rec_print(stderr, wait_lock, mtr);
ib::info() << "WSREP: do not wait another BF trx: " << ib::hex(lock->trx->id)
<< " query: " << wsrep_thd_query(lock->trx->mysql_thd);
- lock_rec_print(stderr, lock);
+ lock_rec_print(stderr, lock, mtr);
}
/* don't wait for another BF lock */
continue;
@@ -3768,7 +3761,7 @@ lock_table_enqueue_waiting(
);
const trx_t* victim_trx =
- DeadlockChecker::check_and_resolve(lock, trx);
+ DeadlockChecker::check_and_resolve(lock, trx);
if (victim_trx != 0) {
ut_ad(victim_trx == trx);
@@ -3789,7 +3782,7 @@ lock_table_enqueue_waiting(
trx->lock.que_state = TRX_QUE_LOCK_WAIT;
- trx->lock.wait_started = ut_time();
+ trx->lock.wait_started = time(NULL);
trx->lock.was_chosen_as_deadlock_victim = false;
ut_a(que_thr_stop(thr));
@@ -4427,20 +4420,14 @@ lock_table_print(FILE* file, const lock_t* lock)
putc('\n', file);
}
-/** Print info of a record lock.
+/** Pretty-print a record lock.
@param[in,out] file output stream
-@param[in] lock record lock */
-static
-void
-lock_rec_print(FILE* file, const lock_t* lock)
+@param[in] lock record lock
+@param[in,out] mtr mini-transaction for accessing the record */
+static void lock_rec_print(FILE* file, const lock_t* lock, mtr_t& mtr)
{
ulint space;
ulint page_no;
- mtr_t mtr;
- mem_heap_t* heap = NULL;
- ulint offsets_[REC_OFFS_NORMAL_SIZE];
- ulint* offsets = offsets_;
- rec_offs_init(offsets_);
ut_ad(lock_mutex_own());
ut_a(lock_get_type_low(lock) == LOCK_REC);
@@ -4480,13 +4467,16 @@ lock_rec_print(FILE* file, const lock_t* lock)
fputs(" waiting", file);
}
- mtr_start(&mtr);
-
putc('\n', file);
- const buf_block_t* block;
+ mem_heap_t* heap = NULL;
+ ulint offsets_[REC_OFFS_NORMAL_SIZE];
+ ulint* offsets = offsets_;
+ rec_offs_init(offsets_);
- block = buf_page_try_get(page_id_t(space, page_no), &mtr);
+ mtr.start();
+ const buf_block_t* block = buf_page_try_get(page_id_t(space, page_no),
+ &mtr);
for (ulint i = 0; i < lock_rec_get_n_bits(lock); ++i) {
@@ -4515,9 +4505,9 @@ lock_rec_print(FILE* file, const lock_t* lock)
putc('\n', file);
}
- mtr_commit(&mtr);
+ mtr.commit();
- if (heap) {
+ if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
}
@@ -4620,11 +4610,10 @@ lock_print_info_summary(
/** Prints transaction lock wait and MVCC state.
@param[in,out] file file where to print
-@param[in] trx transaction */
+@param[in] trx transaction
+@param[in] now current time */
void
-lock_trx_print_wait_and_mvcc_state(
- FILE* file,
- const trx_t* trx)
+lock_trx_print_wait_and_mvcc_state(FILE* file, const trx_t* trx, time_t now)
{
fprintf(file, "---");
@@ -4644,10 +4633,11 @@ lock_trx_print_wait_and_mvcc_state(
fprintf(file,
"------- TRX HAS BEEN WAITING %lu SEC"
" FOR THIS LOCK TO BE GRANTED:\n",
- (ulong) difftime(ut_time(), trx->lock.wait_started));
+ (ulong) difftime(now, trx->lock.wait_started));
if (lock_get_type_low(trx->lock.wait_lock) == LOCK_REC) {
- lock_rec_print(file, trx->lock.wait_lock);
+ mtr_t mtr;
+ lock_rec_print(file, trx->lock.wait_lock, mtr);
} else {
lock_table_print(file, trx->lock.wait_lock);
}
@@ -4665,6 +4655,7 @@ lock_trx_print_locks(
FILE* file, /*!< in/out: File to write */
const trx_t* trx) /*!< in: current transaction */
{
+ mtr_t mtr;
uint32_t i= 0;
/* Iterate over the transaction's locks. */
for (lock_t *lock = UT_LIST_GET_FIRST(trx->lock.trx_locks);
@@ -4672,7 +4663,7 @@ lock_trx_print_locks(
lock = UT_LIST_GET_NEXT(trx_locks, lock)) {
if (lock_get_type_low(lock) == LOCK_REC) {
- lock_rec_print(file, lock);
+ lock_rec_print(file, lock, mtr);
} else {
ut_ad(lock_get_type_low(lock) & LOCK_TABLE);
@@ -4693,20 +4684,21 @@ lock_trx_print_locks(
/** Functor to display all transactions */
struct lock_print_info
{
- lock_print_info(FILE* file) : file(file) {}
+ lock_print_info(FILE* file, time_t now) : file(file), now(now) {}
void operator()(const trx_t* trx) const
{
ut_ad(mutex_own(&trx_sys.mutex));
if (trx == purge_sys.query->trx)
return;
- lock_trx_print_wait_and_mvcc_state(file, trx);
+ lock_trx_print_wait_and_mvcc_state(file, trx, now);
if (trx->will_lock && srv_print_innodb_lock_monitor)
lock_trx_print_locks(file, trx);
}
FILE* const file;
+ const time_t now;
};
/*********************************************************************//**
@@ -4721,9 +4713,10 @@ lock_print_info_all_transactions(
ut_ad(lock_mutex_own());
fprintf(file, "LIST OF TRANSACTIONS FOR EACH SESSION:\n");
+ const time_t now = time(NULL);
mutex_enter(&trx_sys.mutex);
- ut_list_map(trx_sys.trx_list, lock_print_info(file));
+ ut_list_map(trx_sys.trx_list, lock_print_info(file, now));
mutex_exit(&trx_sys.mutex);
lock_mutex_exit();
@@ -6549,10 +6542,11 @@ DeadlockChecker::print(const lock_t* lock)
ut_ad(lock_mutex_own());
if (lock_get_type_low(lock) == LOCK_REC) {
- lock_rec_print(lock_latest_err_file, lock);
+ mtr_t mtr;
+ lock_rec_print(lock_latest_err_file, lock, mtr);
if (srv_print_all_deadlocks) {
- lock_rec_print(stderr, lock);
+ lock_rec_print(stderr, lock, mtr);
}
} else {
lock_table_print(lock_latest_err_file, lock);
@@ -6847,7 +6841,7 @@ DeadlockChecker::search()
@param trx transaction rolled back
@param lock lock trx wants */
void
-DeadlockChecker::rollback_print(const trx_t* trx, const lock_t* lock)
+DeadlockChecker::rollback_print(const trx_t* trx, const lock_t* lock)
{
ut_ad(lock_mutex_own());
@@ -6892,16 +6886,17 @@ DeadlockChecker::trx_rollback()
trx_mutex_exit(trx);
}
-/** Checks if a joining lock request results in a deadlock. If a deadlock is
-found this function will resolve the deadlock by choosing a victim transaction
-and rolling it back. It will attempt to resolve all deadlocks. The returned
-transaction id will be the joining transaction instance or NULL if some other
-transaction was chosen as a victim and rolled back or no deadlock found.
+/** Check if a joining lock request results in a deadlock.
+If a deadlock is found, we will resolve the deadlock by
+choosing a victim transaction and rolling it back.
+We will attempt to resolve all deadlocks.
-@param[in] lock lock the transaction is requesting
-@param[in,out] trx transaction requesting the lock
+@param[in] lock the lock request
+@param[in,out] trx transaction requesting the lock
-@return transaction instanace chosen as victim or 0 */
+@return trx if it was chosen as victim
+@retval NULL if another victim was chosen,
+or there is no deadlock (any more) */
const trx_t*
DeadlockChecker::check_and_resolve(const lock_t* lock, trx_t* trx)
{