From 5d49a2add70123fa3a54db4c1e48b9246d2f208d Mon Sep 17 00:00:00 2001 From: Iaroslav Babanin Date: Wed, 15 May 2024 17:42:08 +0300 Subject: [PATCH] MDEV-33935 fix deadlock counter - The deadlock counter was moved from Deadlock::find_cycle into Deadlock::report, because the find_cycle method is called multiple times during deadlock detection flow, which means it shouldn't have such side effects. But report() can, which called only once for a victim transaction. - Also the deadlock_detect.test and *.result test case has been extended to handle the fix. --- .../suite/innodb/r/deadlock_detect.result | 8 +++++++ .../suite/innodb/t/deadlock_detect.test | 21 +++++++++++++++++-- storage/innobase/include/srv0srv.h | 1 - storage/innobase/lock/lock0lock.cc | 2 +- 4 files changed, 28 insertions(+), 4 deletions(-) diff --git a/mysql-test/suite/innodb/r/deadlock_detect.result b/mysql-test/suite/innodb/r/deadlock_detect.result index 8131585aea2..284556e56c9 100644 --- a/mysql-test/suite/innodb/r/deadlock_detect.result +++ b/mysql-test/suite/innodb/r/deadlock_detect.result @@ -3,7 +3,12 @@ CREATE TABLE t1( id INT, PRIMARY KEY(id) ) ENGINE=InnoDB; +CREATE TABLE dl( +id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT, +cnt INT UNSIGNED +) ENGINE=InnoDB; INSERT INTO t1 VALUES(1), (2), (3); +INSERT INTO dl(cnt) SELECT variable_value FROM information_schema.global_status WHERE variable_name LIKE 'Innodb_deadlocks'; BEGIN; SELECT * FROM t1 WHERE id = 1 LOCK IN SHARE MODE; connect con1,localhost,root,,; @@ -20,5 +25,8 @@ disconnect con1; ROLLBACK; disconnect con2; connection default; +'Deadlock counter is valid'; +1 ROLLBACK; DROP TABLE t1; +DROP TABLE dl; diff --git a/mysql-test/suite/innodb/t/deadlock_detect.test b/mysql-test/suite/innodb/t/deadlock_detect.test index e853790755a..a84e6fc328f 100644 --- a/mysql-test/suite/innodb/t/deadlock_detect.test +++ b/mysql-test/suite/innodb/t/deadlock_detect.test @@ -14,7 +14,14 @@ CREATE TABLE t1( PRIMARY KEY(id) ) ENGINE=InnoDB; +CREATE TABLE dl( + id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT, + cnt INT UNSIGNED +) ENGINE=InnoDB; + INSERT INTO t1 VALUES(1), (2), (3); +# Preserve the initial value of the deadlock counter +INSERT INTO dl(cnt) SELECT variable_value FROM information_schema.global_status WHERE variable_name LIKE 'Innodb_deadlocks'; # We are not interested query results, only errors --disable_result_log @@ -61,6 +68,7 @@ disconnect con2; # and does the update. # connection default; +--let $valid_deadlock_cnt= 1 if (!$have_deadlock) { --error 0,ER_LOCK_WAIT_TIMEOUT reap; @@ -68,12 +76,21 @@ reap; if ($have_deadlock) { --error 0,ER_LOCK_DEADLOCK reap; +--disable_query_log +INSERT INTO dl(cnt) SELECT variable_value FROM information_schema.global_status WHERE variable_name LIKE 'Innodb_deadlocks'; +set @init_deadlock_cnt = (SELECT min(k.cnt) FROM dl k); +--let $valid_deadlock_cnt= `SELECT (max(t.cnt-@init_deadlock_cnt) = 1) FROM dl t` +--enable_query_log } +# Indicates that the deadlock counter works well. +# Use the default =1 where is no deadlock detection, +# to enable unconditional check. +--echo 'Deadlock counter is valid'; +--echo $valid_deadlock_cnt ROLLBACK; --enable_result_log - DROP TABLE t1; - +DROP TABLE dl; --source include/wait_until_count_sessions.inc diff --git a/storage/innobase/include/srv0srv.h b/storage/innobase/include/srv0srv.h index dc0546ac0f3..4c3c17a1a16 100644 --- a/storage/innobase/include/srv0srv.h +++ b/storage/innobase/include/srv0srv.h @@ -668,7 +668,6 @@ struct export_var_t{ ulint innodb_data_reads; /*!< I/O read requests */ ulint innodb_dblwr_pages_written; /*!< srv_dblwr_pages_written */ ulint innodb_dblwr_writes; /*!< srv_dblwr_writes */ - ulint innodb_deadlocks; ulint innodb_history_list_length; ulint innodb_log_waits; /*!< srv_log_waits */ ulint innodb_log_write_requests; /*!< srv_log_write_requests */ diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc index 4d0ac5ccc04..3e3d573ba5b 100644 --- a/storage/innobase/lock/lock0lock.cc +++ b/storage/innobase/lock/lock0lock.cc @@ -296,7 +296,6 @@ namespace Deadlock if (tortoise == hare) { ut_ad(l > 1); - lock_sys.deadlocks++; /* Note: Normally, trx should be part of any deadlock cycle that is found. However, if innodb_deadlock_detect=OFF had been in effect in the past, it is possible that trx will be waiting @@ -6825,6 +6824,7 @@ and less modified rows. Bit 0 is used to prefer orig_trx in case of a tie. if (!cycle) goto func_exit; /* One of the transactions was already aborted. */ + lock_sys.deadlocks++; victim= cycle; undo_no_t victim_weight= calc_victim_weight(victim, trx); unsigned victim_pos= l;