1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-29 05:21:33 +03:00

MDEV-24738 Improve the InnoDB deadlock checker

A new configuration parameter innodb_deadlock_report is introduced:
* innodb_deadlock_report=off: Do not report any details of deadlocks.
* innodb_deadlock_report=basic: Report transactions and waiting locks.
* innodb_deadlock_report=full (default): Report also the blocking locks.

The improved deadlock checker will consider all involved transactions
in one loop, even if the deadlock loop includes several transactions.
The theoretical maximum number of transactions that can be involved in
a deadlock is `innodb_page_size` * 8, limited by the persistent data
structures.

Note: Similar to
mysql/mysql-server@3859219875
our deadlock checker will consider at most one blocking transaction
for each waiting transaction. The new field trx->lock.wait_trx be
nullptr if and only if trx->lock.wait_lock is nullptr. Note that
trx->lock.wait_lock->trx == trx (the waiting transaction), while
trx->lock.wait_trx points to one of the transactions whose lock is
conflicting with trx->lock.wait_lock.

Considering only one blocking transaction will greatly simplify
our deadlock checker, but it may also make the deadlock checker
blind to some deadlocks where the deadlock cycle is 'hidden' by
the fact that the registered trx->lock.wait_trx is not actually
waiting for any InnoDB lock, but something else. So, instead of
deadlocks, sometimes lock wait timeout may be reported.

To improve on this, whenever trx->lock.wait_trx is changed, we
will register further 'candidate' transactions in Deadlock::to_check(),
and check for 'revealed' deadlocks as soon as possible, in lock_release()
and innobase_kill_query().

The old DeadlockChecker was holding lock_sys.latch, even though using
lock_sys.wait_mutex should be less contended (and thus preferred)
in the likely case that no deadlock is present.

lock_wait(): Defer the deadlock check to this function, instead of
executing it in lock_rec_enqueue_waiting(), lock_table_enqueue_waiting().

DeadlockChecker: Complete rewrite:
(1) Explicitly keep track of transactions that are being waited for,
in trx->lock.wait_trx, protected by lock_sys.wait_mutex. Previously,
we were painstakingly traversing the lock heaps while blocking
concurrent registration or removal of any locks (even uncontended ones).
(2) Use Brent's cycle-detection algorithm for deadlock detection,
traversing each trx->lock.wait_trx edge at most 2 times.
(3) If a deadlock is detected, release lock_sys.wait_mutex,
acquire LockMutexGuard, re-acquire lock_sys.wait_mutex and re-invoke
find_cycle() to find out whether the deadlock is still present.
(4) Display information on all transactions that are involved in the
deadlock, and choose a victim to be rolled back.

lock_sys.deadlocks: Replaces lock_deadlock_found. Protected by wait_mutex.

Deadlock::find_cycle(): Quickly find a cycle of trx->lock.wait_trx...
using Brent's cycle detection algorithm.

Deadlock::report(): Report a deadlock cycle that was found by
Deadlock::find_cycle(), and choose a victim with the least weight.
Altogether, we may traverse each trx->lock.wait_trx edge up to 5
times (2*find_cycle()+1 time for reporting and choosing the victim).

Deadlock::check_and_resolve(): Find and resolve a deadlock.

lock_wait_rpl_report(): Report the waits-for information to
replication. This used to be executed as part of DeadlockChecker.
Replication must know the waits-for relations even if no deadlocks
are present in InnoDB.

Reviewed by: Vladislav Vaintroub
This commit is contained in:
Marko Mäkelä
2021-02-17 12:43:33 +02:00
parent 3ddb4fddf1
commit c68007d958
14 changed files with 647 additions and 859 deletions

View File

@ -104,6 +104,10 @@ disconnect con2;
connection default;
SET @@global.innodb_strict_mode = @old_innodb_strict_mode;
SET @@global.innodb_file_per_table = @old_innodb_file_per_table;
SET @save_detect= @@GLOBAL.innodb_deadlock_detect;
SET @save_report= @@GLOBAL.innodb_deadlock_report;
SET GLOBAL innodb_deadlock_detect=ON;
SET GLOBAL innodb_deadlock_report=BASIC;
SET NAMES utf8;
CREATE TABLE `t``\""e` (a INT, PRIMARY KEY (a))
ENGINE=InnoDB
@ -148,6 +152,8 @@ set sql_mode = 'ANSI_QUOTES';
SHOW ENGINE InnoDB STATUS;
Type Name Status
InnoDB index PRIMARY of table `test`.`t``\""e` /* Partition `p0``\""e`, Subpartition `sp0``\""e` */
SET GLOBAL innodb_deadlock_detect= @save_detect;
SET GLOBAL innodb_deadlock_report= @save_report;
set @@sql_mode = @old_sql_mode;
connection con1;
ROLLBACK;

View File

@ -100,6 +100,10 @@ SET GLOBAL innodb_read_only_compressed=@save_innodb_read_only_compressed;
#
# Bug#32430 - show engine innodb status causes errors
#
SET @save_detect= @@GLOBAL.innodb_deadlock_detect;
SET @save_report= @@GLOBAL.innodb_deadlock_report;
SET GLOBAL innodb_deadlock_detect=ON;
SET GLOBAL innodb_deadlock_report=BASIC;
SET NAMES utf8;
CREATE TABLE `t``\""e` (a INT, PRIMARY KEY (a))
ENGINE=InnoDB
@ -150,6 +154,8 @@ set @old_sql_mode = @@sql_mode;
set sql_mode = 'ANSI_QUOTES';
--replace_regex /.*RECORD LOCKS space id [0-9]* page no [0-9]* n bits [0-9]* // / trx id .*// /.*index .* in // /trx table locks [0-9]* // /total table locks [0-9]* //
SHOW ENGINE InnoDB STATUS;
SET GLOBAL innodb_deadlock_detect= @save_detect;
SET GLOBAL innodb_deadlock_report= @save_report;
set @@sql_mode = @old_sql_mode;
connection con1;
REAP;

View File

@ -0,0 +1,11 @@
@@ -16,7 +16,10 @@
connection default;
SELECT * FROM t1 WHERE id = 2 FOR UPDATE;
connection con2;
+connection con1;
+COMMIT;
disconnect con1;
+connection con2;
ROLLBACK;
disconnect con2;
connection default;

View File

@ -16,9 +16,9 @@ SELECT * FROM t1 WHERE id = 1 FOR UPDATE;
connection default;
SELECT * FROM t1 WHERE id = 2 FOR UPDATE;
connection con2;
disconnect con1;
ROLLBACK;
disconnect con2;
disconnect con1;
connection default;
ROLLBACK;
DROP TABLE t1;

View File

@ -39,14 +39,18 @@ connection con2;
if (!$have_deadlock) {
--error ER_LOCK_WAIT_TIMEOUT
reap;
disconnect con1;
}
if ($have_deadlock) {
--error 0,ER_LOCK_DEADLOCK
connection con1;
COMMIT;
disconnect con1;
connection con2;
--error 0,ER_LOCK_DEADLOCK,ER_LOCK_WAIT_TIMEOUT
reap;
}
ROLLBACK;
disconnect con2;
disconnect con1;
#
# Note here that con1 is the older transaction as it

View File

@ -9,7 +9,7 @@
VARIABLE_COMMENT Number of InnoDB Adaptive Hash Index Partitions (default 8)
NUMERIC_MIN_VALUE 1
NUMERIC_MAX_VALUE 512
@@ -85,7 +85,7 @@
@@ -73,7 +73,7 @@
SESSION_VALUE NULL
DEFAULT_VALUE 1
VARIABLE_SCOPE GLOBAL
@ -18,7 +18,7 @@
VARIABLE_COMMENT The AUTOINC lock modes supported by InnoDB: 0 => Old style AUTOINC locking (for backward compatibility); 1 => New style AUTOINC locking; 2 => No AUTOINC locking (unsafe for SBR)
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 2
@@ -157,10 +157,10 @@
@@ -97,10 +97,10 @@
SESSION_VALUE NULL
DEFAULT_VALUE 134217728
VARIABLE_SCOPE GLOBAL
@ -31,7 +31,7 @@
NUMERIC_BLOCK_SIZE 1048576
ENUM_VALUE_LIST NULL
READ_ONLY YES
@@ -193,7 +193,7 @@
@@ -133,7 +133,7 @@
SESSION_VALUE NULL
DEFAULT_VALUE 25
VARIABLE_SCOPE GLOBAL
@ -40,16 +40,7 @@
VARIABLE_COMMENT Dump only the hottest N% of each buffer pool, defaults to 25
NUMERIC_MIN_VALUE 1
NUMERIC_MAX_VALUE 100
@@ -229,7 +229,7 @@
SESSION_VALUE NULL
DEFAULT_VALUE 0
VARIABLE_SCOPE GLOBAL
-VARIABLE_TYPE BIGINT UNSIGNED
+VARIABLE_TYPE INT UNSIGNED
VARIABLE_COMMENT Deprecated parameter with no effect.
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 64
@@ -289,7 +289,7 @@
@@ -217,7 +217,7 @@
SESSION_VALUE NULL
DEFAULT_VALUE 0
VARIABLE_SCOPE GLOBAL
@ -58,7 +49,7 @@
VARIABLE_COMMENT A number between [0, 100] that tells how oftern buffer pool dump status in percentages should be printed. E.g. 10 means that buffer pool dump status is printed when every 10% of number of buffer pool pages are dumped. Default is 0 (only start and end status is printed).
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 100
@@ -421,7 +421,7 @@
@@ -337,7 +337,7 @@
SESSION_VALUE NULL
DEFAULT_VALUE 5
VARIABLE_SCOPE GLOBAL
@ -67,7 +58,7 @@
VARIABLE_COMMENT If the compression failure rate of a table is greater than this number more padding is added to the pages to reduce the failures. A value of zero implies no padding
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 100
@@ -445,7 +445,7 @@
@@ -361,7 +361,7 @@
SESSION_VALUE NULL
DEFAULT_VALUE 50
VARIABLE_SCOPE GLOBAL
@ -76,7 +67,7 @@
VARIABLE_COMMENT Percentage of empty space on a data page that can be reserved to make the page compressible.
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 75
@@ -745,7 +745,7 @@
@@ -661,7 +661,7 @@
SESSION_VALUE NULL
DEFAULT_VALUE 600
VARIABLE_SCOPE GLOBAL
@ -85,7 +76,7 @@
VARIABLE_COMMENT Maximum number of seconds that semaphore times out in InnoDB.
NUMERIC_MIN_VALUE 1
NUMERIC_MAX_VALUE 4294967295
@@ -805,7 +805,7 @@
@@ -709,7 +709,7 @@
SESSION_VALUE NULL
DEFAULT_VALUE 30
VARIABLE_SCOPE GLOBAL
@ -94,7 +85,7 @@
VARIABLE_COMMENT Number of iterations over which the background flushing is averaged.
NUMERIC_MIN_VALUE 1
NUMERIC_MAX_VALUE 1000
@@ -829,7 +829,7 @@
@@ -733,7 +733,7 @@
SESSION_VALUE NULL
DEFAULT_VALUE 1
VARIABLE_SCOPE GLOBAL
@ -103,7 +94,7 @@
VARIABLE_COMMENT Controls the durability/speed trade-off for commits. Set to 0 (write and flush redo log to disk only once per second), 1 (flush to disk at each commit), 2 (write to log at commit but flush to disk only once per second) or 3 (flush to disk at prepare and at commit, slower and usually redundant). 1 and 3 guarantees that after a crash, committed transactions will not be lost and will be consistent with the binlog and other transactional engines. 2 can get inconsistent and lose transactions if there is a power failure or kernel crash but not if mysqld crashes. 0 has no guarantees in case of crash. 0 and 2 can be faster than 1 or 3.
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 3
@@ -853,7 +853,7 @@
@@ -757,7 +757,7 @@
SESSION_VALUE NULL
DEFAULT_VALUE 1
VARIABLE_SCOPE GLOBAL
@ -112,7 +103,7 @@
VARIABLE_COMMENT Set to 0 (don't flush neighbors from buffer pool), 1 (flush contiguous neighbors from buffer pool) or 2 (flush neighbors from buffer pool), when flushing a block
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 2
@@ -901,7 +901,7 @@
@@ -805,7 +805,7 @@
SESSION_VALUE NULL
DEFAULT_VALUE 0
VARIABLE_SCOPE GLOBAL
@ -121,7 +112,7 @@
VARIABLE_COMMENT Helps to save your data in case the disk image of the database becomes corrupt. Value 5 can return bogus data, and 6 can permanently corrupt data.
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 6
@@ -925,7 +925,7 @@
@@ -829,7 +829,7 @@
SESSION_VALUE NULL
DEFAULT_VALUE 8000000
VARIABLE_SCOPE GLOBAL
@ -130,7 +121,7 @@
VARIABLE_COMMENT InnoDB Fulltext search cache size in bytes
NUMERIC_MIN_VALUE 1600000
NUMERIC_MAX_VALUE 80000000
@@ -961,7 +961,7 @@
@@ -865,7 +865,7 @@
SESSION_VALUE NULL
DEFAULT_VALUE 84
VARIABLE_SCOPE GLOBAL
@ -139,7 +130,7 @@
VARIABLE_COMMENT InnoDB Fulltext search maximum token size in characters
NUMERIC_MIN_VALUE 10
NUMERIC_MAX_VALUE 84
@@ -973,7 +973,7 @@
@@ -877,7 +877,7 @@
SESSION_VALUE NULL
DEFAULT_VALUE 3
VARIABLE_SCOPE GLOBAL
@ -148,7 +139,7 @@
VARIABLE_COMMENT InnoDB Fulltext search minimum token size in characters
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 16
@@ -985,7 +985,7 @@
@@ -889,7 +889,7 @@
SESSION_VALUE NULL
DEFAULT_VALUE 2000
VARIABLE_SCOPE GLOBAL
@ -157,7 +148,7 @@
VARIABLE_COMMENT InnoDB Fulltext search number of words to optimize for each optimize table call
NUMERIC_MIN_VALUE 1000
NUMERIC_MAX_VALUE 10000
@@ -997,10 +997,10 @@
@@ -901,10 +901,10 @@
SESSION_VALUE NULL
DEFAULT_VALUE 2000000000
VARIABLE_SCOPE GLOBAL
@ -170,7 +161,7 @@
NUMERIC_BLOCK_SIZE 0
ENUM_VALUE_LIST NULL
READ_ONLY NO
@@ -1021,7 +1021,7 @@
@@ -925,7 +925,7 @@
SESSION_VALUE NULL
DEFAULT_VALUE 2
VARIABLE_SCOPE GLOBAL
@ -179,7 +170,7 @@
VARIABLE_COMMENT InnoDB Fulltext search parallel sort degree, will round up to nearest power of 2 number
NUMERIC_MIN_VALUE 1
NUMERIC_MAX_VALUE 16
@@ -1033,7 +1033,7 @@
@@ -937,7 +937,7 @@
SESSION_VALUE NULL
DEFAULT_VALUE 640000000
VARIABLE_SCOPE GLOBAL
@ -188,7 +179,7 @@
VARIABLE_COMMENT Total memory allocated for InnoDB Fulltext Search cache
NUMERIC_MIN_VALUE 32000000
NUMERIC_MAX_VALUE 1600000000
@@ -1093,22 +1093,22 @@
@@ -985,22 +985,22 @@
SESSION_VALUE NULL
DEFAULT_VALUE 200
VARIABLE_SCOPE GLOBAL
@ -216,7 +207,7 @@
NUMERIC_BLOCK_SIZE 0
ENUM_VALUE_LIST NULL
READ_ONLY NO
@@ -1153,7 +1153,7 @@
@@ -1021,7 +1021,7 @@
SESSION_VALUE 50
DEFAULT_VALUE 50
VARIABLE_SCOPE SESSION
@ -225,7 +216,7 @@
VARIABLE_COMMENT Timeout in seconds an InnoDB transaction may wait for a lock before being rolled back. Values above 100000000 disable the timeout.
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 1073741824
@@ -1165,10 +1165,10 @@
@@ -1033,10 +1033,10 @@
SESSION_VALUE NULL
DEFAULT_VALUE 16777216
VARIABLE_SCOPE GLOBAL
@ -238,16 +229,7 @@
NUMERIC_BLOCK_SIZE 1024
ENUM_VALUE_LIST NULL
READ_ONLY YES
@@ -1213,7 +1213,7 @@
SESSION_VALUE NULL
DEFAULT_VALUE 1
VARIABLE_SCOPE GLOBAL
-VARIABLE_TYPE BIGINT UNSIGNED
+VARIABLE_TYPE INT UNSIGNED
VARIABLE_COMMENT Deprecated parameter with no effect.
NUMERIC_MIN_VALUE 1
NUMERIC_MAX_VALUE 100
@@ -1261,7 +1261,7 @@
@@ -1081,7 +1081,7 @@
SESSION_VALUE NULL
DEFAULT_VALUE 8192
VARIABLE_SCOPE GLOBAL
@ -256,9 +238,9 @@
VARIABLE_COMMENT Redo log write ahead unit size to avoid read-on-write, it should match the OS cache block IO size
NUMERIC_MIN_VALUE 512
NUMERIC_MAX_VALUE 16384
@@ -1273,10 +1273,10 @@
@@ -1093,10 +1093,10 @@
SESSION_VALUE NULL
DEFAULT_VALUE 100
DEFAULT_VALUE 32
VARIABLE_SCOPE GLOBAL
-VARIABLE_TYPE BIGINT UNSIGNED
+VARIABLE_TYPE INT UNSIGNED
@ -269,9 +251,9 @@
NUMERIC_BLOCK_SIZE 0
ENUM_VALUE_LIST NULL
READ_ONLY NO
@@ -1285,10 +1285,10 @@
@@ -1105,10 +1105,10 @@
SESSION_VALUE NULL
DEFAULT_VALUE 1024
DEFAULT_VALUE 1536
VARIABLE_SCOPE GLOBAL
-VARIABLE_TYPE BIGINT UNSIGNED
+VARIABLE_TYPE INT UNSIGNED
@ -282,7 +264,7 @@
NUMERIC_BLOCK_SIZE 0
ENUM_VALUE_LIST NULL
READ_ONLY NO
@@ -1333,10 +1333,10 @@
@@ -1153,10 +1153,10 @@
SESSION_VALUE NULL
DEFAULT_VALUE 0
VARIABLE_SCOPE GLOBAL
@ -295,7 +277,7 @@
NUMERIC_BLOCK_SIZE 0
ENUM_VALUE_LIST NULL
READ_ONLY NO
@@ -1345,7 +1345,7 @@
@@ -1165,7 +1165,7 @@
SESSION_VALUE NULL
DEFAULT_VALUE 0
VARIABLE_SCOPE GLOBAL
@ -304,7 +286,7 @@
VARIABLE_COMMENT Maximum delay of user threads in micro-seconds
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 10000000
@@ -1465,10 +1465,10 @@
@@ -1297,10 +1297,10 @@
SESSION_VALUE NULL
DEFAULT_VALUE 0
VARIABLE_SCOPE GLOBAL
@ -317,16 +299,7 @@
NUMERIC_BLOCK_SIZE 0
ENUM_VALUE_LIST NULL
READ_ONLY YES
@@ -1489,7 +1489,7 @@
SESSION_VALUE NULL
DEFAULT_VALUE 0
VARIABLE_SCOPE GLOBAL
-VARIABLE_TYPE BIGINT UNSIGNED
+VARIABLE_TYPE INT UNSIGNED
VARIABLE_COMMENT Deprecated parameter with no effect.
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 64
@@ -1513,7 +1513,7 @@
@@ -1333,7 +1333,7 @@
SESSION_VALUE NULL
DEFAULT_VALUE 16384
VARIABLE_SCOPE GLOBAL
@ -335,7 +308,7 @@
VARIABLE_COMMENT Page size to use for all InnoDB tablespaces.
NUMERIC_MIN_VALUE 4096
NUMERIC_MAX_VALUE 65536
@@ -1549,7 +1549,7 @@
@@ -1369,7 +1369,7 @@
SESSION_VALUE NULL
DEFAULT_VALUE 300
VARIABLE_SCOPE GLOBAL
@ -344,7 +317,7 @@
VARIABLE_COMMENT Number of UNDO log pages to purge in one batch from the history list.
NUMERIC_MIN_VALUE 1
NUMERIC_MAX_VALUE 5000
@@ -1561,7 +1561,7 @@
@@ -1381,7 +1381,7 @@
SESSION_VALUE NULL
DEFAULT_VALUE 128
VARIABLE_SCOPE GLOBAL
@ -353,7 +326,7 @@
VARIABLE_COMMENT Dictates rate at which UNDO records are purged. Value N means purge rollback segment(s) on every Nth iteration of purge invocation
NUMERIC_MIN_VALUE 1
NUMERIC_MAX_VALUE 128
@@ -1597,7 +1597,7 @@
@@ -1417,7 +1417,7 @@
SESSION_VALUE NULL
DEFAULT_VALUE 56
VARIABLE_SCOPE GLOBAL
@ -362,7 +335,7 @@
VARIABLE_COMMENT Number of pages that must be accessed sequentially for InnoDB to trigger a readahead.
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 64
@@ -1705,7 +1705,7 @@
@@ -1501,7 +1501,7 @@
SESSION_VALUE NULL
DEFAULT_VALUE 1048576
VARIABLE_SCOPE GLOBAL
@ -371,16 +344,7 @@
VARIABLE_COMMENT Memory buffer size for index creation
NUMERIC_MIN_VALUE 65536
NUMERIC_MAX_VALUE 67108864
@@ -1873,7 +1873,7 @@
SESSION_VALUE NULL
DEFAULT_VALUE 1
VARIABLE_SCOPE GLOBAL
-VARIABLE_TYPE BIGINT UNSIGNED
+VARIABLE_TYPE INT UNSIGNED
VARIABLE_COMMENT Size of the mutex/lock wait array.
NUMERIC_MIN_VALUE 1
NUMERIC_MAX_VALUE 1024
@@ -1897,10 +1897,10 @@
@@ -1669,10 +1669,10 @@
SESSION_VALUE NULL
DEFAULT_VALUE 30
VARIABLE_SCOPE GLOBAL
@ -393,16 +357,7 @@
NUMERIC_BLOCK_SIZE 0
ENUM_VALUE_LIST NULL
READ_ONLY NO
@@ -2005,7 +2005,7 @@
SESSION_VALUE NULL
DEFAULT_VALUE 128
VARIABLE_SCOPE GLOBAL
-VARIABLE_TYPE BIGINT UNSIGNED
+VARIABLE_TYPE INT UNSIGNED
VARIABLE_COMMENT Deprecated parameter with no effect.
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 128
@@ -2029,7 +2029,7 @@
@@ -1765,7 +1765,7 @@
SESSION_VALUE NULL
DEFAULT_VALUE 0
VARIABLE_SCOPE GLOBAL

View File

@ -417,6 +417,18 @@ NUMERIC_BLOCK_SIZE NULL
ENUM_VALUE_LIST OFF,ON
READ_ONLY NO
COMMAND_LINE_ARGUMENT NONE
VARIABLE_NAME INNODB_DEADLOCK_REPORT
SESSION_VALUE NULL
DEFAULT_VALUE full
VARIABLE_SCOPE GLOBAL
VARIABLE_TYPE ENUM
VARIABLE_COMMENT How to report deadlocks (if innodb_deadlock_detect=ON).
NUMERIC_MIN_VALUE NULL
NUMERIC_MAX_VALUE NULL
NUMERIC_BLOCK_SIZE NULL
ENUM_VALUE_LIST off,basic,full
READ_ONLY NO
COMMAND_LINE_ARGUMENT REQUIRED
VARIABLE_NAME INNODB_DEFAULT_ENCRYPTION_KEY_ID
SESSION_VALUE 1
DEFAULT_VALUE 1

View File

@ -372,6 +372,26 @@ TYPELIB innodb_flush_method_typelib = {
NULL
};
/** Names of allowed values of innodb_deadlock_report */
static const char *innodb_deadlock_report_names[]= {
"off", /* Do not report any details of deadlocks */
"basic", /* Report waiting transactions and lock requests */
"full", /* Also report blocking locks */
NullS
};
static_assert(Deadlock::REPORT_OFF == 0, "compatibility");
static_assert(Deadlock::REPORT_BASIC == 1, "compatibility");
static_assert(Deadlock::REPORT_FULL == 2, "compatibility");
/** Enumeration of innodb_deadlock_report */
static TYPELIB innodb_deadlock_report_typelib = {
array_elements(innodb_deadlock_report_names) - 1,
"innodb_deadlock_report_typelib",
innodb_deadlock_report_names,
NULL
};
/** Allowed values of innodb_change_buffering */
static const char* innodb_change_buffering_names[] = {
"none", /* IBUF_USE_NONE */
@ -4476,6 +4496,7 @@ static void innobase_kill_query(handlerton*, THD *thd, enum thd_kill_levels)
trx->mutex_unlock();
}
}
lock_sys.deadlock_check();
mysql_mutex_unlock(&lock_sys.wait_mutex);
}
}
@ -18601,13 +18622,18 @@ static MYSQL_SYSVAR_ULONG(flush_neighbors, srv_flush_neighbors,
" when flushing a block",
NULL, NULL, 1, 0, 2, 0);
static MYSQL_SYSVAR_BOOL(deadlock_detect, innobase_deadlock_detect,
static MYSQL_SYSVAR_BOOL(deadlock_detect, innodb_deadlock_detect,
PLUGIN_VAR_NOCMDARG,
"Enable/disable InnoDB deadlock detector (default ON)."
" if set to OFF, deadlock detection is skipped,"
" and we rely on innodb_lock_wait_timeout in case of deadlock.",
NULL, NULL, TRUE);
static MYSQL_SYSVAR_ENUM(deadlock_report, innodb_deadlock_report,
PLUGIN_VAR_RQCMDARG,
"How to report deadlocks (if innodb_deadlock_detect=ON).",
NULL, NULL, Deadlock::REPORT_FULL, &innodb_deadlock_report_typelib);
static MYSQL_SYSVAR_UINT(fill_factor, innobase_fill_factor,
PLUGIN_VAR_RQCMDARG,
"Percentage of B-tree page filled during bulk insert",
@ -19190,6 +19216,7 @@ static struct st_mysql_sys_var* innobase_system_variables[]= {
MYSQL_SYSVAR(force_load_corrupted),
MYSQL_SYSVAR(lock_wait_timeout),
MYSQL_SYSVAR(deadlock_detect),
MYSQL_SYSVAR(deadlock_report),
MYSQL_SYSVAR(page_size),
MYSQL_SYSVAR(log_buffer_size),
MYSQL_SYSVAR(log_file_size),

View File

@ -43,7 +43,15 @@ Created 5/7/1996 Heikki Tuuri
class ReadView;
/** The value of innodb_deadlock_detect */
extern my_bool innobase_deadlock_detect;
extern my_bool innodb_deadlock_detect;
/** The value of innodb_deadlock_report */
extern ulong innodb_deadlock_report;
namespace Deadlock
{
/** The allowed values of innodb_deadlock_report */
enum report { REPORT_OFF, REPORT_BASIC, REPORT_FULL };
}
/*********************************************************************//**
Gets the heap_no of the smallest user record on a page.
@ -704,22 +712,21 @@ public:
hash_table prdt_hash;
/** page locks for SPATIAL INDEX */
hash_table prdt_page_hash;
/** number of deadlocks detected; protected by mutex */
ulint deadlocks;
/** mutex covering lock waits; @see trx_lock_t::wait_lock */
MY_ALIGNED(CPU_LEVEL1_DCACHE_LINESIZE) mysql_mutex_t wait_mutex;
private:
/** Pending number of lock waits; protected by wait_mutex */
ulint wait_pending;
/** Cumulative number of lock waits; protected by wait_mutex */
ulint wait_count;
/** Pending number of lock waits; protected by wait_mutex */
uint32_t wait_pending;
/** Cumulative wait time; protected by wait_mutex */
ulint wait_time;
uint32_t wait_time;
/** Longest wait time; protected by wait_mutex */
ulint wait_time_max;
uint32_t wait_time_max;
public:
/** number of deadlocks detected; protected by wait_mutex */
ulint deadlocks;
/**
Constructor.
@ -821,6 +828,10 @@ public:
void close();
/** Check for deadlocks */
static void deadlock_check();
/** Note that a record lock wait started */
inline void wait_start();
@ -940,8 +951,8 @@ UNIV_INLINE
lock_t*
lock_rec_create(
/*============*/
#ifdef WITH_WSREP
lock_t* c_lock, /*!< conflicting lock */
#ifdef WITH_WSREP
que_thr_t* thr, /*!< thread owning trx */
#endif
unsigned type_mode,/*!< in: lock mode and wait flag */
@ -961,6 +972,7 @@ void lock_rec_discard(lock_sys_t::hash_table &lock_hash, lock_t *in_lock);
/** Create a new record lock and inserts it to the lock queue,
without checking for deadlocks or conflicts.
@param[in] c_lock conflicting lock, or NULL
@param[in] type_mode lock mode and wait flag
@param[in] page_id index page number
@param[in] page R-tree index page, or NULL
@ -971,8 +983,8 @@ without checking for deadlocks or conflicts.
@return created lock */
lock_t*
lock_rec_create_low(
lock_t* c_lock,
#ifdef WITH_WSREP
lock_t* c_lock, /*!< conflicting lock */
que_thr_t* thr, /*!< thread owning trx */
#endif
unsigned type_mode,
@ -985,6 +997,7 @@ lock_rec_create_low(
/** Enqueue a waiting request for a lock which cannot be granted immediately.
Check for deadlocks.
@param[in] c_lock conflicting lock
@param[in] type_mode the requested lock mode (LOCK_S or LOCK_X)
possibly ORed with LOCK_GAP or
LOCK_REC_NOT_GAP, ORed with
@ -1002,9 +1015,7 @@ Check for deadlocks.
@retval DB_DEADLOCK if this transaction was chosen as the victim */
dberr_t
lock_rec_enqueue_waiting(
#ifdef WITH_WSREP
lock_t* c_lock, /*!< conflicting lock */
#endif
lock_t* c_lock,
unsigned type_mode,
const page_id_t id,
const page_t* page,

View File

@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2015, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2017, 2020, MariaDB Corporation.
Copyright (c) 2017, 2021, MariaDB Corporation.
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
@ -60,8 +60,8 @@ UNIV_INLINE
lock_t*
lock_rec_create(
/*============*/
#ifdef WITH_WSREP
lock_t* c_lock, /*!< conflicting lock */
#ifdef WITH_WSREP
que_thr_t* thr, /*!< thread owning trx */
#endif
unsigned type_mode,/*!< in: lock mode and wait flag */
@ -76,8 +76,9 @@ lock_rec_create(
{
btr_assert_not_corrupted(block, index);
return lock_rec_create_low(
c_lock,
#ifdef WITH_WSREP
c_lock, thr,
thr,
#endif
type_mode, block->page.id(), block->frame, heap_no,
index, trx, caller_owns_trx_mutex);

View File

@ -416,14 +416,6 @@ lock_rec_get_prev(
const lock_t* in_lock,/*!< in: record lock */
ulint heap_no);/*!< in: heap number of the record */
/*********************************************************************//**
Cancels a waiting lock request and releases possible other transactions
waiting behind it. */
void
lock_cancel_waiting_and_release(
/*============================*/
lock_t* lock); /*!< in/out: waiting lock request */
/*********************************************************************//**
Checks if some transaction has an implicit x-lock on a record in a clustered
index.

View File

@ -425,15 +425,13 @@ struct trx_lock_t
trx->mutex, by the thread that is executing the transaction.
Set to nullptr when holding lock_sys.wait_mutex. */
Atomic_relaxed<lock_t*> wait_lock;
/** Transaction being waited for; protected by lock_sys.wait_mutex */
trx_t *wait_trx;
/** condition variable for !wait_lock; used with lock_sys.wait_mutex */
pthread_cond_t cond;
/** lock wait start time, protected only by lock_sys.wait_mutex */
my_hrtime_t suspend_time;
/** DeadlockChecker::search() uses this to keep track of visited locks.
Protected by lock_sys.is_writer(). */
uint64_t deadlock_mark;
#ifdef WITH_WSREP
/** 2=high priority wsrep thread has marked this trx to abort;
1=another transaction chose this as a victim in deadlock resolution. */

File diff suppressed because it is too large Load Diff

View File

@ -463,12 +463,16 @@ lock_prdt_add_to_queue(
}
create:
lock_t* lock = lock_rec_create(
/* Note: We will not pass any conflicting lock to lock_rec_create(),
because we should be moving an existing waiting lock request. */
ut_ad(!(type_mode & LOCK_WAIT) || trx->lock.wait_trx);
lock_t* lock = lock_rec_create(nullptr,
#ifdef WITH_WSREP
NULL, NULL, /* FIXME: replicate SPATIAL INDEX locks */
nullptr,
#endif
type_mode, block, PRDT_HEAPNO, index, trx,
caller_owns_trx_mutex);
type_mode, block, PRDT_HEAPNO, index,
trx, caller_owns_trx_mutex);
if (lock->type_mode & LOCK_PREDICATE) {
lock_prdt_set_prdt(lock, prdt);
@ -529,11 +533,8 @@ lock_prdt_insert_check_and_lock(
trx->mutex_lock();
/* Allocate MBR on the lock heap */
lock_init_prdt_from_mbr(prdt, mbr, 0, trx->lock.lock_heap);
err= lock_rec_enqueue_waiting(
#ifdef WITH_WSREP
c_lock,
#endif
mode, id, block->frame, PRDT_HEAPNO, index, thr, prdt);
err= lock_rec_enqueue_waiting(c_lock, mode, id, block->frame,
PRDT_HEAPNO, index, thr, prdt);
trx->mutex_unlock();
}
}
@ -732,8 +733,9 @@ lock_prdt_lock(
if (lock == NULL) {
lock = lock_rec_create(
NULL,
#ifdef WITH_WSREP
NULL, NULL, /* FIXME: replicate SPATIAL INDEX locks */
NULL, /* FIXME: replicate SPATIAL INDEX locks */
#endif
prdt_mode, block, PRDT_HEAPNO,
index, trx, FALSE);
@ -762,10 +764,7 @@ lock_prdt_lock(
if (wait_for != NULL) {
err = lock_rec_enqueue_waiting(
#ifdef WITH_WSREP
NULL, /* FIXME: replicate
SPATIAL INDEX locks */
#endif
wait_for,
prdt_mode,
id, block->frame, PRDT_HEAPNO,
index, thr, prdt);
@ -835,8 +834,9 @@ lock_place_prdt_page_lock(
if (lock == NULL) {
lock = lock_rec_create_low(
NULL,
#ifdef WITH_WSREP
NULL, NULL, /* FIXME: replicate SPATIAL INDEX locks */
NULL, /* FIXME: replicate SPATIAL INDEX locks */
#endif
mode, page_id, NULL, PRDT_HEAPNO,
index, trx, FALSE);