From dac3d702f77f6d53a94cfc377342f5f2e148a8d7 Mon Sep 17 00:00:00 2001 From: Thirunarayanan Balathandayuthapani Date: Mon, 21 Apr 2025 13:45:38 +0530 Subject: [PATCH 1/3] MDEV-36649 dict_acquire_mdl_shared() aborts when table mode is DICT_TABLE_OP_OPEN_ONLY_IF_CACHED - InnoDB fails to check the table is being dropped or evicted while acquiring the MDL for the table when table open operation mode is DICT_TABLE_OP_OPEN_ONLY_IF_CACHED. This is caused by the commit 337bf8ac4bb9a89f51cd35ec867c74fbb8d23faa (MDEV-36122) Fix: === dict_acquire_mdl_shared(): If the table is evicted or dropped when table operation mode is DICT_TABLE_OP_OPEN_IF_CACHED then return nullptr --- mysql-test/suite/innodb/r/stats_persistent.result | 10 ++++++++++ mysql-test/suite/innodb/t/stats_persistent.test | 12 ++++++++++++ storage/innobase/dict/dict0dict.cc | 2 ++ 3 files changed, 24 insertions(+) diff --git a/mysql-test/suite/innodb/r/stats_persistent.result b/mysql-test/suite/innodb/r/stats_persistent.result index 7e9c038d6f7..077c4de71a0 100644 --- a/mysql-test/suite/innodb/r/stats_persistent.result +++ b/mysql-test/suite/innodb/r/stats_persistent.result @@ -17,3 +17,13 @@ test.t1 analyze status Engine-independent statistics collected test.t1 analyze status OK SET DEBUG_SYNC= 'RESET'; DROP TABLE t1; +# +# MDEV-36649 dict_acquire_mdl_shared() aborts when table +# mode is DICT_TABLE_OP_OPEN_ONLY_IF_CACHED +# +set @old_defragment_stats_accuracy= @@innodb_defragment_stats_accuracy; +SET GLOBAL innodb_defragment_stats_accuracy=1; +CREATE TABLE t (a INT ) ENGINE=INNODB; +INSERT INTO t SELECT * FROM seq_1_to_1000; +DROP TABLE t; +set global innodb_defragment_stats_accuracy= @old_defragment_stats_accuracy; diff --git a/mysql-test/suite/innodb/t/stats_persistent.test b/mysql-test/suite/innodb/t/stats_persistent.test index 8561298c4d3..4d11aef9d2d 100644 --- a/mysql-test/suite/innodb/t/stats_persistent.test +++ b/mysql-test/suite/innodb/t/stats_persistent.test @@ -1,4 +1,5 @@ --source include/have_innodb.inc +--source include/have_sequence.inc --source include/have_debug.inc --source include/have_debug_sync.inc --source include/count_sessions.inc @@ -26,3 +27,14 @@ SET DEBUG_SYNC= 'RESET'; DROP TABLE t1; --source include/wait_until_count_sessions.inc + +--echo # +--echo # MDEV-36649 dict_acquire_mdl_shared() aborts when table +--echo # mode is DICT_TABLE_OP_OPEN_ONLY_IF_CACHED +--echo # +set @old_defragment_stats_accuracy= @@innodb_defragment_stats_accuracy; +SET GLOBAL innodb_defragment_stats_accuracy=1; +CREATE TABLE t (a INT ) ENGINE=INNODB; +INSERT INTO t SELECT * FROM seq_1_to_1000; +DROP TABLE t; +set global innodb_defragment_stats_accuracy= @old_defragment_stats_accuracy; diff --git a/storage/innobase/dict/dict0dict.cc b/storage/innobase/dict/dict0dict.cc index 4f293c41854..ef4c24f6fb5 100644 --- a/storage/innobase/dict/dict0dict.cc +++ b/storage/innobase/dict/dict0dict.cc @@ -795,6 +795,8 @@ lookup: dict_sys.freeze(SRW_LOCK_CALL); goto return_without_mdl; } + else + goto return_without_mdl; if (*mdl) { From 4bedb222a807a4cc3f424e0f57b1921ab0d3e253 Mon Sep 17 00:00:00 2001 From: Thirunarayanan Balathandayuthapani Date: Tue, 22 Apr 2025 17:11:56 +0530 Subject: [PATCH 2/3] MDEV-36304 InnoDB: Missing FILE_CREATE, FILE_DELETE or FILE_MODIFY error during mariabackup --prepare Reason: ====== During --prepare of partial backup, if InnoDB encounters the redo log for the excluded tablespace then InnoDB stores the space id in dirty tablespace list during recovery, anticipates that it may encounter FILE_* redo log records in the future. Even though we encounter FILE_* record for the partial excluded tablespace then we fail to replace the name in dirty tablespace list. This lead to missing of FILE_* redo log records error. Solution: ======== fil_name_process(): Rename the file name from "" to name encountered during FILE_* record recv_init_missing_space(): Correct the condition to print the warning message of missing tablespace during mariabackup restore process. --- storage/innobase/log/log0recv.cc | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/storage/innobase/log/log0recv.cc b/storage/innobase/log/log0recv.cc index 9a71521d707..004dc65c752 100644 --- a/storage/innobase/log/log0recv.cc +++ b/storage/innobase/log/log0recv.cc @@ -1307,6 +1307,13 @@ got_deleted: } else if (p.second // the first FILE_MODIFY or FILE_RENAME || f.name != fname.name) { reload: + if (f.name.size() == 0) { + /* Augment the recv_spaces.emplace_hint() for the + FILE_MODIFY record that had been added by + recv_sys_t::parse() */ + f.name = fname.name; + } + fil_space_t* space; /* Check if the tablespace file exists and contains @@ -2577,8 +2584,8 @@ page_id_corrupted: if (i != recv_spaces.end() && i->first == space_id); else if (recovered_lsn < mlog_checkpoint_lsn) /* We have not seen all records between the checkpoint and - FILE_CHECKPOINT. There should be a FILE_DELETE for this - tablespace later. */ + FILE_CHECKPOINT. There should be a FILE_DELETE or FILE_MODIFY + for this tablespace later, to be handled in fil_name_process() */ recv_spaces.emplace_hint(i, space_id, file_name_t("", false)); else { @@ -4158,7 +4165,7 @@ recv_init_missing_space(dberr_t err, const recv_spaces_t::const_iterator& i) break; case SRV_OPERATION_RESTORE: case SRV_OPERATION_RESTORE_EXPORT: - if (i->second.name.find("/#sql") != std::string::npos) { + if (i->second.name.find("/#sql") == std::string::npos) { ib::warn() << "Tablespace " << i->first << " was not" " found at " << i->second.name << " when" " restoring a (partial?) backup. All redo log" From 47e687b109e465a31ec029969e302ca1a73208a3 Mon Sep 17 00:00:00 2001 From: Vlad Lesin Date: Tue, 22 Apr 2025 15:49:53 +0300 Subject: [PATCH 3/3] MDEV-36639 innodb_snapshot_isolation=1 gives error for not committed row changes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Set solution is to check if transaction, which modified a record, is still active in lock_clust_rec_read_check_and_lock(). if yes, then just request a lock. If no, then, depending on if the current transaction read view can see the changes, return eighter DB_RECORD_CHANGED or request a lock. We can do the check in lock_clust_rec_read_check_and_lock() because transaction tries to set a lock on the record which cursor points to after transaction resuming and cursor position restoring. If the lock already exists, then we don't request the lock again. But for the current commit it's important that lock_clust_rec_read_check_and_lock() will be invoked again for the same record, so we can do the check again after transaction, which modified a record, was committed or rolled back. MDEV-33802(4aa9291) is partially reverted. If some transaction holds implicit lock on some record and transaction with snapshot isolation level requests conflicting lock on the same record, it should be blocked instead of returning DB_RECORD_CHANGED to have ability to continue execution when implicit lock owner is rolled back. The construction -------------------------------------------------------------------------- let $wait_condition= select count(*) = 1 from information_schema.processlist where state = 'Updating' and info = 'UPDATE t SET b = 2 WHERE a'; --source include/wait_condition.inc -------------------------------------------------------------------------- is not reliable enought to make sure transaction is blocked in test case, the test failed sporadically with -------------------------------------------------------------------------- ./mtr --max-test-fail=1 --parallel=96 lock_isolation{,,,,,,,}{,,,}{,,} \ --repeat=500 -------------------------------------------------------------------------- command. That's why it was replaced with debug sync-points. Reviewed by: Marko Mäkelä --- .../suite/innodb/r/lock_isolation.result | 90 +++++++++++- mysql-test/suite/innodb/t/lock_isolation.test | 136 +++++++++++++----- storage/innobase/lock/lock0lock.cc | 63 +++----- 3 files changed, 207 insertions(+), 82 deletions(-) diff --git a/mysql-test/suite/innodb/r/lock_isolation.result b/mysql-test/suite/innodb/r/lock_isolation.result index 5975b531451..1e1625ae458 100644 --- a/mysql-test/suite/innodb/r/lock_isolation.result +++ b/mysql-test/suite/innodb/r/lock_isolation.result @@ -1,3 +1,6 @@ +connect disable_purging,localhost,root; +START TRANSACTION WITH CONSISTENT SNAPSHOT; +connection default; # # MDEV-26642 Weird SELECT view when a record is # modified to the same value by two transactions @@ -52,15 +55,17 @@ DROP TABLE t; # MDEV-26643 Inconsistent behaviors of UPDATE under # READ UNCOMMITTED and READ COMMITTED isolation level # -CREATE TABLE t(a INT, b INT) ENGINE=InnoDB; +CREATE TABLE t(a INT, b INT) ENGINE=InnoDB STATS_PERSISTENT=0; INSERT INTO t VALUES(NULL, 1), (2, 2); SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; BEGIN; UPDATE t SET a = 10; connection consistent; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; +SET DEBUG_SYNC="lock_wait_before_suspend SIGNAL select_blocked"; UPDATE t SET b = 20 WHERE a; connection default; +SET DEBUG_SYNC="now WAIT_FOR select_blocked"; COMMIT; connection consistent; SELECT * FROM t; @@ -74,8 +79,10 @@ BEGIN; UPDATE t SET a = 10; connection consistent; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; +SET DEBUG_SYNC="lock_wait_before_suspend SIGNAL select_blocked"; UPDATE t SET b = 20 WHERE a; connection default; +SET DEBUG_SYNC="now WAIT_FOR select_blocked"; COMMIT; connection consistent; SELECT * FROM t; @@ -89,8 +96,10 @@ BEGIN; UPDATE t SET a = 10; connection con_weird; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; +SET DEBUG_SYNC="lock_wait_before_suspend SIGNAL select_blocked"; UPDATE t SET b = 20 WHERE a; connection default; +SET DEBUG_SYNC="now WAIT_FOR select_blocked"; SELECT * FROM t; a b 10 1 @@ -113,8 +122,10 @@ UPDATE t SET b = 3; connection consistent; SET TRANSACTION ISOLATION LEVEL READ COMMITTED; BEGIN; +SET DEBUG_SYNC="lock_wait_before_suspend SIGNAL select_blocked"; UPDATE t SET b = 2 WHERE a; connection default; +SET DEBUG_SYNC="now WAIT_FOR select_blocked"; UPDATE t SET a = 1; COMMIT; connection consistent; @@ -128,20 +139,25 @@ DROP TABLE t; # # MDEV-33802 Weird read view after ROLLBACK of other transactions # -CREATE TABLE t(a INT PRIMARY KEY, b INT UNIQUE) ENGINE=InnoDB; -INSERT INTO t SET a=1; -BEGIN; -INSERT INTO t SET a=2; +CREATE TABLE t(a INT PRIMARY KEY, b INT UNIQUE) ENGINE=InnoDB STATS_PERSISTENT=0; connection consistent; START TRANSACTION WITH CONSISTENT SNAPSHOT; +connection default; +INSERT INTO t SET a=1; +connection consistent; SAVEPOINT sp1; SELECT * FROM t FORCE INDEX (b) FOR UPDATE; ERROR HY000: Record has changed since last read in table 't' SAVEPOINT sp1; +connection default; +BEGIN; +INSERT INTO t SET a=2; connection con_weird; START TRANSACTION WITH CONSISTENT SNAPSHOT; +SET DEBUG_SYNC="lock_wait_before_suspend SIGNAL select_blocked"; SELECT * FROM t FORCE INDEX (b) FOR UPDATE; connection default; +SET DEBUG_SYNC="now WAIT_FOR select_blocked"; ROLLBACK; connection con_weird; a b @@ -149,12 +165,74 @@ a b SELECT * FROM t FORCE INDEX (b) FOR UPDATE; a b 1 NULL +COMMIT; disconnect con_weird; connection consistent; SELECT * FROM t FORCE INDEX (b) FOR UPDATE; a b 1 NULL -disconnect consistent; +COMMIT; connection default; +TRUNCATE TABLE t; +# +# MDEV-36639 innodb_snapshot_isolation=1 gives error for not comitted row changes +# +INSERT INTO t VALUES (1,1),(2,2); +connection default; +# Case 1: Transaction A modifies a record, transaction B with snapshot +# isolation level is blocked by A, then A is committed. +# Expected behaviour: B gets ER_CHECKREAD. +BEGIN; +UPDATE t SET b=3 WHERE a = 1; +connection consistent; +SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; +BEGIN; +SELECT * FROM t; +a b +1 1 +2 2 +SET DEBUG_SYNC="lock_wait_before_suspend SIGNAL select_blocked"; +SELECT * FROM t WHERE a=1 FOR UPDATE; +connection default; +SET DEBUG_SYNC="now WAIT_FOR select_blocked"; +COMMIT; +connection consistent; +ERROR HY000: Record has changed since last read in table 't' +# Case 2: Transaction A modifies a record, transaction B with snapshot +# isolation level is blocked by A, then A is rolled back. +# Expected behaviour: B continues execution. +connection default; +BEGIN; +UPDATE t SET b=4 WHERE a=1; +connection consistent; +BEGIN; +SELECT * FROM t; +a b +2 2 +1 3 +SET DEBUG_SYNC="lock_wait_before_suspend SIGNAL select_blocked"; +SELECT * FROM t WHERE a=1 FOR UPDATE; +connection default; +SET DEBUG_SYNC="now WAIT_FOR select_blocked"; +ROLLBACK; +connection consistent; +a b +1 3 +ROLLBACK; +# Case 3: Transaction B with snapshot isolation level started with +# consistent snapshot. Transaction A modifies a record and is committed. +# Both B tries to read modified by A record. +# Expected behavior: B gets ER_CHECKREAD. +connection consistent; +START TRANSACTION WITH CONSISTENT SNAPSHOT; +connection default; +UPDATE t SET b=4 WHERE a=1; +connection consistent; +SELECT * FROM t WHERE a=1 FOR UPDATE; +ERROR HY000: Record has changed since last read in table 't' +disconnect consistent; +disconnect disable_purging; +connection default; +SET DEBUG_SYNC="RESET"; DROP TABLE t; # End of 10.6 tests diff --git a/mysql-test/suite/innodb/t/lock_isolation.test b/mysql-test/suite/innodb/t/lock_isolation.test index bac034a50e4..b332f2e867a 100644 --- a/mysql-test/suite/innodb/t/lock_isolation.test +++ b/mysql-test/suite/innodb/t/lock_isolation.test @@ -1,9 +1,16 @@ --source include/have_innodb.inc +--source include/count_sessions.inc +--source include/have_debug.inc +--source include/have_debug_sync.inc --disable_query_log call mtr.add_suppression("InnoDB: Transaction was aborted due to "); --enable_query_log +--connect disable_purging,localhost,root +START TRANSACTION WITH CONSISTENT SNAPSHOT; + +--connection default --echo # --echo # MDEV-26642 Weird SELECT view when a record is --echo # modified to the same value by two transactions @@ -41,22 +48,18 @@ DROP TABLE t; --echo # READ UNCOMMITTED and READ COMMITTED isolation level --echo # -CREATE TABLE t(a INT, b INT) ENGINE=InnoDB; +CREATE TABLE t(a INT, b INT) ENGINE=InnoDB STATS_PERSISTENT=0; INSERT INTO t VALUES(NULL, 1), (2, 2); SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; BEGIN; UPDATE t SET a = 10; --connection consistent SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; +SET DEBUG_SYNC="lock_wait_before_suspend SIGNAL select_blocked"; --send UPDATE t SET b = 20 WHERE a --connection default -let $wait_condition= - select count(*) = 1 from information_schema.processlist - where state = 'Updating' - and info = 'UPDATE t SET b = 20 WHERE a'; ---source include/wait_condition.inc - +SET DEBUG_SYNC="now WAIT_FOR select_blocked"; COMMIT; --connection consistent @@ -70,14 +73,11 @@ BEGIN; UPDATE t SET a = 10; --connection consistent SET TRANSACTION ISOLATION LEVEL READ COMMITTED; +SET DEBUG_SYNC="lock_wait_before_suspend SIGNAL select_blocked"; --send UPDATE t SET b = 20 WHERE a --connection default -let $wait_condition= - select count(*) = 1 from information_schema.processlist - where info = 'UPDATE t SET b = 20 WHERE a'; ---source include/wait_condition.inc - +SET DEBUG_SYNC="now WAIT_FOR select_blocked"; COMMIT; --connection consistent @@ -91,15 +91,11 @@ BEGIN; UPDATE t SET a = 10; --connection con_weird SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; +SET DEBUG_SYNC="lock_wait_before_suspend SIGNAL select_blocked"; send UPDATE t SET b = 20 WHERE a; --connection default -let $wait_condition= - select count(*) = 1 from information_schema.processlist - where state = 'Updating' - and info = 'UPDATE t SET b = 20 WHERE a'; ---source include/wait_condition.inc - +SET DEBUG_SYNC="now WAIT_FOR select_blocked"; SELECT * FROM t; COMMIT; @@ -123,14 +119,11 @@ SET TRANSACTION ISOLATION LEVEL READ COMMITTED; BEGIN; # As semi-consistent read is disabled for innodb_snapshot_isolation=ON, the # following UPDATE must be blocked on the first record. +SET DEBUG_SYNC="lock_wait_before_suspend SIGNAL select_blocked"; --send UPDATE t SET b = 2 WHERE a --connection default -let $wait_condition= - select count(*) = 1 from information_schema.processlist - where state = 'Updating' and info = 'UPDATE t SET b = 2 WHERE a'; ---source include/wait_condition.inc - +SET DEBUG_SYNC="now WAIT_FOR select_blocked"; UPDATE t SET a = 1; COMMIT; --connection consistent @@ -149,13 +142,15 @@ DROP TABLE t; --echo # MDEV-33802 Weird read view after ROLLBACK of other transactions --echo # -CREATE TABLE t(a INT PRIMARY KEY, b INT UNIQUE) ENGINE=InnoDB; -INSERT INTO t SET a=1; - -BEGIN; INSERT INTO t SET a=2; +CREATE TABLE t(a INT PRIMARY KEY, b INT UNIQUE) ENGINE=InnoDB STATS_PERSISTENT=0; --connection consistent START TRANSACTION WITH CONSISTENT SNAPSHOT; + +--connection default +INSERT INTO t SET a=1; + +--connection consistent SAVEPOINT sp1; --disable_ps2_protocol --error ER_CHECKREAD @@ -163,29 +158,100 @@ SELECT * FROM t FORCE INDEX (b) FOR UPDATE; --enable_ps2_protocol SAVEPOINT sp1; +--connection default +BEGIN; INSERT INTO t SET a=2; + --connection con_weird START TRANSACTION WITH CONSISTENT SNAPSHOT; -send -SELECT * FROM t FORCE INDEX (b) FOR UPDATE; +SET DEBUG_SYNC="lock_wait_before_suspend SIGNAL select_blocked"; +--send SELECT * FROM t FORCE INDEX (b) FOR UPDATE --connection default -let $wait_condition= - select count(*) = 1 from information_schema.processlist - where state = 'Sending data' - and info LIKE 'SELECT * FROM t %'; ---source include/wait_condition.inc +SET DEBUG_SYNC="now WAIT_FOR select_blocked"; ROLLBACK; --connection con_weird --reap SELECT * FROM t FORCE INDEX (b) FOR UPDATE; +COMMIT; --disconnect con_weird --connection consistent SELECT * FROM t FORCE INDEX (b) FOR UPDATE; ---disconnect consistent +COMMIT; --connection default +TRUNCATE TABLE t; + +--echo # +--echo # MDEV-36639 innodb_snapshot_isolation=1 gives error for not comitted row changes +--echo # +INSERT INTO t VALUES (1,1),(2,2); + +--connection default +--echo # Case 1: Transaction A modifies a record, transaction B with snapshot +--echo # isolation level is blocked by A, then A is committed. +--echo # Expected behaviour: B gets ER_CHECKREAD. +BEGIN; +UPDATE t SET b=3 WHERE a = 1; + +--connection consistent +SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; +BEGIN; +SELECT * FROM t; +SET DEBUG_SYNC="lock_wait_before_suspend SIGNAL select_blocked"; +--send SELECT * FROM t WHERE a=1 FOR UPDATE + +--connection default +SET DEBUG_SYNC="now WAIT_FOR select_blocked"; +COMMIT; + +--connection consistent +--error ER_CHECKREAD +--reap + +--echo # Case 2: Transaction A modifies a record, transaction B with snapshot +--echo # isolation level is blocked by A, then A is rolled back. +--echo # Expected behaviour: B continues execution. + +--connection default +BEGIN; +UPDATE t SET b=4 WHERE a=1; + +--connection consistent +BEGIN; +SELECT * FROM t; +SET DEBUG_SYNC="lock_wait_before_suspend SIGNAL select_blocked"; +--send SELECT * FROM t WHERE a=1 FOR UPDATE + +--connection default +SET DEBUG_SYNC="now WAIT_FOR select_blocked"; +ROLLBACK; + +--connection consistent +--reap +ROLLBACK; + +--echo # Case 3: Transaction B with snapshot isolation level started with +--echo # consistent snapshot. Transaction A modifies a record and is committed. +--echo # Both B tries to read modified by A record. +--echo # Expected behavior: B gets ER_CHECKREAD. + +--connection consistent +START TRANSACTION WITH CONSISTENT SNAPSHOT; + +--connection default +UPDATE t SET b=4 WHERE a=1; + +--connection consistent +--error ER_CHECKREAD +SELECT * FROM t WHERE a=1 FOR UPDATE; +--disconnect consistent +--disconnect disable_purging + +--connection default +SET DEBUG_SYNC="RESET"; DROP TABLE t; +--source include/wait_until_count_sessions.inc --echo # End of 10.6 tests diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc index 7ecdc034bbc..3e4e619b3a0 100644 --- a/storage/innobase/lock/lock0lock.cc +++ b/storage/innobase/lock/lock0lock.cc @@ -6052,17 +6052,10 @@ lock_clust_rec_modify_check_and_lock( for it */ trx_t *trx = thr_get_trx(thr); - if (const trx_t *owner = - lock_rec_convert_impl_to_expl(trx, *block, - rec, index, offsets)) { - if (owner == trx) { - /* We already hold an exclusive lock. */ - return DB_SUCCESS; - } - - if (trx->snapshot_isolation && trx->read_view.is_open()) { - return DB_RECORD_CHANGED; - } + if (lock_rec_convert_impl_to_expl(trx, *block, + rec, index, offsets) == trx) { + /* We already hold an exclusive lock. */ + return DB_SUCCESS; } err = lock_rec_lock(true, LOCK_X | LOCK_REC_NOT_GAP, @@ -6224,19 +6217,11 @@ lock_sec_rec_read_check_and_lock( return DB_SUCCESS; } - if (page_rec_is_supremum(rec)) { - } else if (const trx_t *owner = - lock_rec_convert_impl_to_expl(trx, *block, - rec, index, offsets)) { - if (owner == trx) { - if (gap_mode == LOCK_REC_NOT_GAP) { - /* We already hold an exclusive lock. */ - return DB_SUCCESS; - } - } else if (trx->snapshot_isolation - && trx->read_view.is_open()) { - return DB_RECORD_CHANGED; - } + if (!page_rec_is_supremum(rec) + && lock_rec_convert_impl_to_expl(trx, *block, rec, index, + offsets) == trx + && gap_mode == LOCK_REC_NOT_GAP) { + return DB_SUCCESS; } #ifdef WITH_WSREP @@ -6316,28 +6301,24 @@ lock_clust_rec_read_check_and_lock( trx_t *trx = thr_get_trx(thr); if (lock_table_has(trx, index->table, LOCK_X) || heap_no == PAGE_HEAP_NO_SUPREMUM) { - } else if (const trx_t *owner = - lock_rec_convert_impl_to_expl(trx, *block, - rec, index, offsets)) { - if (owner == trx) { - if (gap_mode == LOCK_REC_NOT_GAP) { - /* We already hold an exclusive lock. */ - return DB_SUCCESS; - } - } else if (trx->snapshot_isolation - && trx->read_view.is_open()) { - return DB_RECORD_CHANGED; - } + } else if (lock_rec_convert_impl_to_expl(trx, *block, rec, index, + offsets) == trx + && gap_mode == LOCK_REC_NOT_GAP) { + /* We already hold an exclusive lock. */ + return DB_SUCCESS; } if (heap_no > PAGE_HEAP_NO_SUPREMUM && gap_mode != LOCK_GAP && trx->snapshot_isolation - && trx->read_view.is_open() - && !trx->read_view.changes_visible( - trx_read_trx_id(rec + row_trx_id_offset(rec, index))) - && IF_WSREP(!(trx->is_wsrep() + && trx->read_view.is_open()) { + trx_id_t trx_id= trx_read_trx_id(rec + + row_trx_id_offset(rec, index)); + if (!trx_sys.is_registered(trx, trx_id) + && !trx->read_view.changes_visible(trx_id) + && IF_WSREP(!(trx->is_wsrep() && wsrep_thd_skip_locking(trx->mysql_thd)), true)) { - return DB_RECORD_CHANGED; + return DB_RECORD_CHANGED; + } } dberr_t err = lock_rec_lock(false, gap_mode | mode,