mirror of
https://github.com/MariaDB/server.git
synced 2025-01-20 14:02:32 +01:00
c44665aeb1
------------------------------------------------------------ revno: 3035.4.1 committer: Davi Arnaut <Davi.Arnaut@Sun.COM> branch nick: 39897-6.0 timestamp: Thu 2009-01-15 12:17:57 -0200 message: Bug#39897: lock_multi fails in pushbuild: timeout waiting for processlist The problem is that relying on the "Table lock" thread state in its current position to detect that a thread is waiting on a lock is race prone. The "Table lock" state change happens before the thread actually tries to grab a lock on a table. The solution is to move the "Table lock" state so that its set only when a thread is actually going to wait for a lock. The state change happens after the thread fails to grab the lock (because it is owned by other thread) and proceeds to wait on a condition. This is considered part of work related to WL#4284 "Transactional DDL locking" Warning: this patch contains an incompatible change. When waiting on a lock in thr_lock.c, the server used to display "Locked" processlist state. After this patch, the state is "Table lock". The new state was actually intended to be display since year 2002, when Monty added it. But up until removal of thd->locked boolean member, this state was ignored by SHOW PROCESSLIST code.
124 lines
4.1 KiB
Text
124 lines
4.1 KiB
Text
### t/query_cache_28249.test ###
|
|
#
|
|
# Test for
|
|
# Bug#28249 Query Cache returns wrong result with concurrent insert / certain lock
|
|
#
|
|
# Last modification:
|
|
# 2008-11-27 mleich - Move this test out of query_cache.test
|
|
# - Fix Bug#40179 Test main.query_cache failing randomly on Pushbuild,
|
|
# test weakness
|
|
# - Minor improvements (comments,formatting etc.)
|
|
#
|
|
|
|
--source include/have_query_cache.inc
|
|
--source include/not_embedded.inc
|
|
|
|
SET @query_cache_type= @@global.query_cache_type;
|
|
SET @query_cache_limit= @@global.query_cache_limit;
|
|
SET @query_cache_min_res_unit= @@global.query_cache_min_res_unit;
|
|
SET @query_cache_size= @@global.query_cache_size;
|
|
|
|
--echo # Bug#28249 Query Cache returns wrong result with concurrent insert/ certain lock
|
|
--echo # Establish connections user1,user2,user3 (user=root)
|
|
connect (user1,localhost,root,,test,,);
|
|
connect (user2,localhost,root,,test,,);
|
|
connect (user3,localhost,root,,test,,);
|
|
|
|
--echo # Switch to connection user1
|
|
connection user1;
|
|
|
|
SET GLOBAL query_cache_type=1;
|
|
SET GLOBAL query_cache_limit=10000;
|
|
SET GLOBAL query_cache_min_res_unit=0;
|
|
SET GLOBAL query_cache_size= 100000;
|
|
|
|
FLUSH TABLES;
|
|
--disable_warnings
|
|
DROP TABLE IF EXISTS t1, t2;
|
|
--enable_warnings
|
|
CREATE TABLE t1 (a INT);
|
|
CREATE TABLE t2 (a INT);
|
|
INSERT INTO t1 VALUES (1),(2),(3);
|
|
|
|
--echo # Switch to connection user2
|
|
connection user2;
|
|
LOCK TABLE t2 WRITE;
|
|
|
|
--echo # Switch to connection user1
|
|
connection user1;
|
|
--echo # "send" the next select, "reap" the result later.
|
|
--echo # The select will be blocked by the write lock on the t1.
|
|
let $select_for_qc =
|
|
SELECT *, (SELECT COUNT(*) FROM t2) FROM t1;
|
|
send;
|
|
eval $select_for_qc;
|
|
|
|
--echo # Switch to connection user3
|
|
connection user3;
|
|
# Typical information_schema.processlist content after sufficient sleep time
|
|
# ID USER COMMAND TIME STATE INFO
|
|
# ....
|
|
# 2 root Query 5 Table lock SELECT *, (SELECT COUNT(*) FROM t2) FROM t1
|
|
# ....
|
|
# XXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
|
# The values marked with 'X' must be reached.
|
|
--echo # Poll till the select of connection user1 is blocked by the write lock on t1.
|
|
let $wait_condition= SELECT COUNT(*) = 1 FROM information_schema.processlist
|
|
WHERE state = 'Table lock'
|
|
AND info = '$select_for_qc';
|
|
--source include/wait_condition.inc
|
|
eval
|
|
SELECT user,command,state,info FROM information_schema.processlist
|
|
WHERE state = 'Table lock'
|
|
AND info = '$select_for_qc';
|
|
INSERT INTO t1 VALUES (4);
|
|
|
|
--echo # Switch to connection user2
|
|
connection user2;
|
|
UNLOCK TABLES;
|
|
|
|
--echo # Switch to connection user1
|
|
connection user1;
|
|
#
|
|
# Since the lock ordering rule in thr_multi_lock depends on
|
|
# pointer values, from execution to execution we might have
|
|
# different lock order, and therefore, sometimes lock t1 and block
|
|
# on t2, and sometimes block on t2 right away. In the second case,
|
|
# the following insert succeeds, and only then this select can
|
|
# proceed, and we actually test nothing, as the very first select
|
|
# returns 4 rows right away.
|
|
# It's fine to have a test case that covers the problematic area
|
|
# at least once in a while.
|
|
--echo # Collecting ("reap") the result from the previously blocked select.
|
|
--echo # The printing of the result (varies between 3 and 4 rows) set has to be suppressed.
|
|
--disable_result_log
|
|
--reap
|
|
--enable_result_log
|
|
|
|
--echo # Switch to connection user3
|
|
connection user3;
|
|
--echo # The next select enforces that effects of "concurrent_inserts" like the
|
|
--echo # record with a = 4 is missing in result sets can no more happen.
|
|
SELECT 1 FROM t1 WHERE a = 4;
|
|
|
|
--echo # Switch to connection user1
|
|
connection user1;
|
|
--echo # The next result set must contain 4 rows.
|
|
# If not, we have a regression of Bug#28249
|
|
eval $select_for_qc;
|
|
RESET QUERY CACHE;
|
|
eval $select_for_qc;
|
|
|
|
DROP TABLE t1,t2;
|
|
|
|
--echo # Switch to connection default + close connections user1,user2,user3
|
|
connection default;
|
|
disconnect user1;
|
|
disconnect user2;
|
|
disconnect user3;
|
|
|
|
SET GLOBAL query_cache_type= @query_cache_type;
|
|
SET GLOBAL query_cache_limit= @query_cache_limit;
|
|
SET GLOBAL query_cache_min_res_unit= @query_cache_min_res_unit;
|
|
SET GLOBAL query_cache_size= @query_cache_size;
|
|
|