1
0
mirror of https://github.com/MariaDB/server.git synced 2025-08-08 11:22:35 +03:00

MDEV-36330: SERIALIZABLE read inconsistency

At TRANSACTION ISOLATION LEVEL SERIALIZABLE, InnoDB would fail to flag
a write/read conflict, which would be a violation already at the more
relaxed REPEATABLE READ level when innodb_snapshot_isolation=ON.

Fix: Create a read view and start the transaction at the same time.
Thus, lock checks will be able to consult the correct read view
to flag ER_CHECKREAD if we are about to lock a record that was committed
after the start of our transaction.

innobase_start_trx_and_assign_read_view(): At any other isolation level
than READ UNCOMMITTED, do create a read view. This is needed for the
correct operation of START TRANSACTION WITH CONSISTENT SNAPSHOT.

ha_innobase::store_lock(): At SERIALIZABLE isolation level, if the
transaction was not started yet, start it and open a read view.
An alternative way to achieve this would be to make trans_begin()
treat START TRANSACTION (or BEGIN) in the same way as
START TRANSACTION WITH CONSISTENT SNAPSHOT when the isolation level
is SERIALIZABLE.

innodb_isolation_level(const THD*): A simpler version of
innobase_map_isolation_level(). Compared to earlier, we will return
READ UNCOMMITTED also if the :newraw option is set for the
InnoDB system tablespace.

Reviewed by: Vladislav Lesin
This commit is contained in:
Marko Mäkelä
2025-07-11 16:07:08 +03:00
parent f73ffd1150
commit 7fbbbc983f
6 changed files with 128 additions and 75 deletions

View File

@@ -166,7 +166,6 @@ 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
@@ -230,9 +229,58 @@ 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;
CREATE TABLE t1(a INT) ENGINE=InnoDB STATS_PERSISTENT=0;
CREATE TABLE t2(a INT) ENGINE=InnoDB STATS_PERSISTENT=0;
BEGIN;
INSERT INTO t1 SET a=1;
connection con_weird;
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN;
INSERT INTO t2 SET a=1;
connection consistent;
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN;
INSERT INTO t2 SET a=2;
connection default;
COMMIT;
connection con_weird;
SELECT * FROM t1;
a
1
COMMIT;
connection consistent;
SELECT * FROM t1;
ERROR HY000: Record has changed since last read in table 't1'
COMMIT;
connection default;
BEGIN;
INSERT INTO t1 SET a=2;
connection con_weird;
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
START TRANSACTION WITH CONSISTENT SNAPSHOT;
INSERT INTO t2 SET a=3;
connection consistent;
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
START TRANSACTION WITH CONSISTENT SNAPSHOT;
INSERT INTO t2 SET a=2;
connection default;
COMMIT;
connection con_weird;
SELECT * FROM t1;
a
1
2
COMMIT;
disconnect con_weird;
connection consistent;
SELECT * FROM t1;
ERROR HY000: Record has changed since last read in table 't1'
COMMIT;
disconnect consistent;
connection default;
DROP TABLE t1,t2;
# End of 10.6 tests