Merge 10.6 into 10.11

This commit is contained in:
Marko Mäkelä
2025-04-23 08:53:53 +03:00
7 changed files with 241 additions and 85 deletions

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -738,6 +738,8 @@ lookup:
dict_sys.freeze(SRW_LOCK_CALL);
goto return_without_mdl;
}
else
goto return_without_mdl;
if (*mdl)
{

View File

@ -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<true>(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<true>(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<false>(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<false>(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<true>(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<true>(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,

View File

@ -1266,6 +1266,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
@ -2715,8 +2722,8 @@ restart:
if (i != recv_spaces.end() && i->first == space_id);
else if (lsn < file_checkpoint)
/* 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
{
@ -4288,7 +4295,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) {
sql_print_warning("InnoDB: Tablespace " UINT32PF
" was not found at %.*s when"
" restoring a (partial?) backup."