1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-30 16:24:05 +03:00

MDEV-16675 Unnecessary explicit lock acquisition during UPDATE or DELETE

In InnoDB, an INSERT will not create an explicit lock object. Instead,
the inserted record is initially implicitly locked by the transaction
that wrote its trx_t::id to the hidden system column DB_TRX_ID.
(Other transactions would check if DB_TRX_ID is referring to a
transaction that has not been committed.)

If a record was inserted in the current transaction, it would be
implicitly locked by that transaction. Only if some other transaction
is requesting access to the record, the implicit lock should be
converted to an explicit one, so that the waits-for graph can be
constructed for detecting deadlocks and lock wait timeouts.

Before this fix, InnoDB would convert implicit locks to
explicit ones, even if no conflict exists.

lock_rec_convert_impl_to_expl(): Return whether caller_trx
already holds an explicit lock that covers the record.

row_vers_impl_x_locked_low(): Avoid a lookup if the record matches
caller_trx->id.

lock_trx_has_expl_x_lock(): Renamed from lock_trx_has_rec_x_lock().

row_upd_clust_step(): In a debug assertion, check for implicit lock
before invoking lock_trx_has_expl_x_lock().

rw_trx_hash_t::find(): Make do_ref_count a mandatory parameter.
Assert that trx_id is not 0 (the caller should check it).

trx_sys_t::is_registered(): Only invoke find() if id != 0.

trx_sys_t::find(): Add the optional parameter do_ref_count.

lock_rec_queue_validate(): Avoid lookup for trx_id == 0.
This commit is contained in:
Marko Mäkelä
2018-07-03 15:10:06 +03:00
parent 186a998b5b
commit 1748a31ae8
11 changed files with 157 additions and 82 deletions

View File

@ -393,33 +393,30 @@ DROP TABLE t1;
--echo # FAILED
--echo #
--disable_warnings
DROP TABLE IF EXISTS t1, t2;
--enable_warnings
CREATE TABLE t1 (a INT) ENGINE=InnoDB;
CREATE TABLE t2 (a INT) ENGINE=InnoDB;
START TRANSACTION;
INSERT INTO t1 VALUES (1);
INSERT INTO t2 VALUES (1); COMMIT;
BEGIN;
INSERT INTO t2 VALUES (2);
UPDATE t2 SET a=a+1;
--connect (con2,localhost,root)
XA START 'xid1';
INSERT INTO t1 VALUES (1);
--echo # Sending:
--send INSERT INTO t2 SELECT a FROM t1
--send DELETE FROM t2
--connection default
let $wait_condition=
SELECT COUNT(*) = 1 FROM information_schema.processlist
WHERE state = "Sending data"
AND info = "INSERT INTO t2 SELECT a FROM t1";
--echo # Waiting until INSERT ... is blocked
WHERE state = "Updating"
AND info = "DELETE FROM t2";
--source include/wait_condition.inc
--sleep 0.1
DELETE FROM t1;
--send DELETE FROM t1
--connection con2
--echo # Reaping: INSERT INTO t2 SELECT a FROM t1
--error ER_LOCK_DEADLOCK
--reap
--error ER_XA_RBDEADLOCK
@ -427,6 +424,7 @@ XA COMMIT 'xid1';
connection default;
reap;
COMMIT;
connection con2;