mirror of
https://github.com/MariaDB/server.git
synced 2025-08-31 22:22:30 +03:00
without FOR UPDATE is causing a lock". SELECT statements with subqueries referencing InnoDB tables were acquiring shared locks on rows in these tables when they were executed in REPEATABLE-READ mode and with statement or mixed mode binary logging turned on. This was a regression which were introduced when fixing bug 39843. The problem was that for tables belonging to subqueries parser set TL_READ_DEFAULT as a lock type. In cases when statement/mixed binary logging at open_tables() time this type of lock was converted to TL_READ_NO_INSERT lock at open_tables() time and caused InnoDB engine to acquire shared locks on reads from these tables. Although in some cases such behavior was correct (e.g. for subqueries in DELETE) in case of SELECT it has caused unnecessary locking. This patch implements minimal version of the fix for the specific problem described in the bug-report which supposed to be not too risky for pushing into 5.1 tree. The 5.5 tree already contains a more appropriate solution which also addresses other related issues like bug 53921 "Wrong locks for SELECTs used stored functions may lead to broken SBR". This patch tries to solve the problem by ensuring that TL_READ_DEFAULT lock which is set in the parser for tables participating in subqueries at open_tables() time is interpreted as TL_READ_NO_INSERT or TL_READ. TL_READ is used only if we know that this is a SELECT and that this particular table is not used by a stored function. Test coverage is added for both InnoDB and MyISAM. This patch introduces an "incompatible" change in locking scheme for subqueries used in SELECT ... FOR UPDATE and SELECT .. IN SHARE MODE. In 4.1 (as well as in 5.0 and 5.1 before fix for bug 39843) the server would use a snapshot InnoDB read for subqueries in SELECT FOR UPDATE and SELECT .. IN SHARE MODE statements, regardless of whether the binary log is on or off. If the user required a different type of read (i.e. locking read), he/she could request so explicitly by providing FOR UPDATE/IN SHARE MODE clause for each individual subquery. The patch for bug 39843 broke this behaviour (which was not documented or tested), and started to use locking reads for all subqueries in SELECT ... FOR UPDATE/IN SHARE MODE. This patch restores 4.1 behaviour. This patch should be mostly null-merged into 5.5 tree.
115 lines
4.0 KiB
Plaintext
115 lines
4.0 KiB
Plaintext
#
|
|
# Test for bug #45143 "All connections hang on concurrent ALTER TABLE".
|
|
#
|
|
# Concurrent execution of statements which required weak write lock
|
|
# (TL_WRITE_ALLOW_WRITE) on several instances of the same table and
|
|
# statements which tried to acquire stronger write lock (TL_WRITE,
|
|
# TL_WRITE_ALLOW_READ) on this table might have led to deadlock.
|
|
drop table if exists t1;
|
|
drop view if exists v1;
|
|
# Create auxiliary connections used through the test.
|
|
# Reset DEBUG_SYNC facility before using it.
|
|
set debug_sync= 'RESET';
|
|
# Turn off logging so calls to locking subsystem performed
|
|
# for general_log table won't interfere with our test.
|
|
set @old_general_log = @@global.general_log;
|
|
set @@global.general_log= OFF;
|
|
create table t1 (i int) engine=InnoDB;
|
|
# We have to use view in order to make LOCK TABLES avoid
|
|
# acquiring SNRW metadata lock on table.
|
|
create view v1 as select * from t1;
|
|
insert into t1 values (1);
|
|
# Prepare user lock which will be used for resuming execution of
|
|
# the first statement after it acquires TL_WRITE_ALLOW_WRITE lock.
|
|
select get_lock("lock_bug45143_wait", 0);
|
|
get_lock("lock_bug45143_wait", 0)
|
|
1
|
|
# Switch to connection 'con_bug45143_1'.
|
|
# Sending:
|
|
insert into t1 values (get_lock("lock_bug45143_wait", 100));;
|
|
# Switch to connection 'con_bug45143_2'.
|
|
# Wait until the above INSERT takes TL_WRITE_ALLOW_WRITE lock on 't1'
|
|
# and then gets blocked on user lock 'lock_bug45143_wait'.
|
|
# Ensure that upcoming SELECT waits after acquiring TL_WRITE_ALLOW_WRITE
|
|
# lock for the first instance of 't1'.
|
|
set debug_sync='thr_multi_lock_after_thr_lock SIGNAL parked WAIT_FOR go';
|
|
# Sending:
|
|
select count(*) > 0 from t1 as a, t1 as b for update;;
|
|
# Switch to connection 'con_bug45143_3'.
|
|
# Wait until the above SELECT ... FOR UPDATE is blocked after
|
|
# acquiring lock for the the first instance of 't1'.
|
|
set debug_sync= 'now WAIT_FOR parked';
|
|
# Send LOCK TABLE statement which will try to get TL_WRITE lock on 't1':
|
|
lock table v1 write;;
|
|
# Switch to connection 'default'.
|
|
# Wait until this LOCK TABLES statement starts waiting for table lock.
|
|
# Allow SELECT ... FOR UPDATE to resume.
|
|
# Since it already has TL_WRITE_ALLOW_WRITE lock on the first instance
|
|
# of 't1' it should be able to get lock on the second instance without
|
|
# waiting, even although there is another thread which has such lock
|
|
# on this table and also there is a thread waiting for a TL_WRITE on it.
|
|
set debug_sync= 'now SIGNAL go';
|
|
# Switch to connection 'con_bug45143_2'.
|
|
# Reap SELECT ... FOR UPDATE
|
|
count(*) > 0
|
|
1
|
|
# Switch to connection 'default'.
|
|
# Resume execution of the INSERT statement.
|
|
select release_lock("lock_bug45143_wait");
|
|
release_lock("lock_bug45143_wait")
|
|
1
|
|
# Switch to connection 'con_bug45143_1'.
|
|
# Reap INSERT statement.
|
|
# In Statement and Mixed replication mode we get here "Unsafe
|
|
# for binlog" warnings. In row mode there are no warnings.
|
|
# Hide the discrepancy.
|
|
# Switch to connection 'con_bug45143_3'.
|
|
# Reap LOCK TABLES statement.
|
|
unlock tables;
|
|
# Switch to connection 'default'.
|
|
# Do clean-up.
|
|
set debug_sync= 'RESET';
|
|
set @@global.general_log= @old_general_log;
|
|
drop view v1;
|
|
drop table t1;
|
|
#
|
|
# Bug#50821 Deadlock between LOCK TABLES and ALTER TABLE
|
|
#
|
|
DROP TABLE IF EXISTS t1, t2;
|
|
CREATE TABLE t1(id INT);
|
|
CREATE TABLE t2(id INT);
|
|
# Connection con2
|
|
START TRANSACTION;
|
|
SELECT * FROM t1;
|
|
id
|
|
# Connection default
|
|
# Sending:
|
|
ALTER TABLE t1 ADD COLUMN j INT;
|
|
# Connection con2
|
|
# This used to cause a deadlock.
|
|
INSERT INTO t2 SELECT * FROM t1;
|
|
COMMIT;
|
|
# Connection default
|
|
# Reaping ALTER TABLE t1 ADD COLUMN j INT
|
|
DROP TABLE t1, t2;
|
|
#
|
|
# Bug#51391 Deadlock involving events during rqg_info_schema test
|
|
#
|
|
CREATE EVENT e1 ON SCHEDULE EVERY 5 HOUR DO SELECT 1;
|
|
CREATE EVENT e2 ON SCHEDULE EVERY 5 HOUR DO SELECT 2;
|
|
# Connection con1
|
|
SET DEBUG_SYNC="before_lock_tables_takes_lock SIGNAL drop WAIT_FOR query";
|
|
# Sending:
|
|
DROP EVENT e1;;
|
|
# Connection default
|
|
SET DEBUG_SYNC="now WAIT_FOR drop";
|
|
SELECT name FROM mysql.event, INFORMATION_SCHEMA.GLOBAL_VARIABLES
|
|
WHERE definer = VARIABLE_VALUE;
|
|
name
|
|
SET DEBUG_SYNC="now SIGNAL query";
|
|
# Connection con1
|
|
# Reaping: DROP EVENT t1
|
|
# Connection default
|
|
DROP EVENT e2;
|
|
SET DEBUG_SYNC="RESET";
|