mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 12:02:42 +01:00
571acc878b
locks for DML statements and changes the way MDL locks are acquired/granted in contended case. Instead of backing-off when a lock conflict is encountered and waiting for it to go away before restarting open_tables() process we now wait for lock to be released without releasing any previously acquired locks. If conflicting lock goes away we resume opening tables. If waiting leads to a deadlock we try to resolve it by backing-off and restarting open_tables() immediately. As result both waiting for possibility to acquire and acquiring of a metadata lock now always happen within the same MDL API call. This has allowed to make release of a lock and granting it to the most appropriate pending request an atomic operation. Thanks to this it became possible to wake up during release of lock only those waiters which requests can be satisfied at the moment as well as wake up only one waiter in case when granting its request would prevent all other requests from being satisfied. This solves thundering herd problem which occured in cases when we were releasing some lock and woke up many waiters for SNRW or X locks (this was the issue in bug#52289 "performance regression for MyISAM in sysbench OLTP_RW test". This also allowed to implement more fair (FIFO) scheduling among waiters with the same priority. It also opens the door for introducing new types of requests for metadata locks such as low-prio SNRW lock which is necessary in order to support LOCK TABLES LOW_PRIORITY WRITE. Notice that after this sometimes can report ER_LOCK_DEADLOCK error in cases in which it has not happened before. Particularly we will always report this error if waiting for conflicting lock has happened in the middle of transaction and resulted in a deadlock. Before this patch the error was not reported if deadlock could have been resolved by backing off all metadata locks acquired by the current statement.
95 lines
2.8 KiB
Text
95 lines
2.8 KiB
Text
Tests of syncronization of stored procedure execution.
|
|
SET DEBUG_SYNC= 'RESET';
|
|
#
|
|
# Bug #30977 Concurrent statement using stored function and
|
|
# DROP FUNCTION breaks SBR
|
|
#
|
|
# A stored routine could change after dispatch_command()
|
|
# but before a MDL lock is taken. This must be noticed and the
|
|
# sp cache flushed so the correct version can be loaded.
|
|
#
|
|
# Connection default
|
|
CREATE FUNCTION f1() RETURNS INT RETURN 1;
|
|
# Get f1 cached
|
|
SELECT f1();
|
|
f1()
|
|
1
|
|
# Then start executing it again...
|
|
SET DEBUG_SYNC= 'before_execute_sql_command SIGNAL before WAIT_FOR changed';
|
|
# Sending:
|
|
SELECT f1();
|
|
# Connection 2
|
|
SET DEBUG_SYNC= 'now WAIT_FOR before';
|
|
# ... but before f1 is locked, change it.
|
|
DROP FUNCTION f1;
|
|
CREATE FUNCTION f1() RETURNS INT RETURN 2;
|
|
SET DEBUG_SYNC= 'now SIGNAL changed';
|
|
# Connection default
|
|
# We should now get '2' and not '1'.
|
|
# Reaping: SELECT f1()
|
|
f1()
|
|
2
|
|
DROP FUNCTION f1;
|
|
SET DEBUG_SYNC= 'RESET';
|
|
#
|
|
# Field translation items must be cleared in case of back-offs
|
|
# for queries that use Information Schema tables. Otherwise
|
|
# memory allocated in fix_fields() for views may end up referring
|
|
# to freed memory.
|
|
#
|
|
DROP FUNCTION IF EXISTS f1;
|
|
# Connection default
|
|
CREATE FUNCTION f1() RETURNS INT RETURN 0;
|
|
# Connection con2
|
|
SET DEBUG_SYNC= 'after_wait_locked_pname SIGNAL locked WAIT_FOR issued';
|
|
# con2 will now have an x-lock on f1
|
|
# Sending:
|
|
ALTER FUNCTION f1 COMMENT 'comment';
|
|
# Connection default
|
|
SET DEBUG_SYNC= 'now WAIT_FOR locked';
|
|
# This query will block due to the x-lock on f1 and back-off
|
|
SHOW OPEN TABLES WHERE f1()=0;
|
|
# Connection con3
|
|
# Check that the IS query is blocked before releasing the x-lock
|
|
SET DEBUG_SYNC= 'now SIGNAL issued';
|
|
# Connection default
|
|
# Reaping: ALTER FUNCTION f1 COMMENT 'comment'
|
|
DROP FUNCTION f1;
|
|
SET DEBUG_SYNC= 'RESET';
|
|
#
|
|
# Bug #48246 assert in close_thread_table
|
|
#
|
|
CREATE TABLE t0 (b INTEGER);
|
|
CREATE TABLE t1 (a INTEGER);
|
|
CREATE FUNCTION f1(b INTEGER) RETURNS INTEGER RETURN 1;
|
|
CREATE PROCEDURE p1() SELECT COUNT(f1(a)) FROM t1, t0;
|
|
INSERT INTO t0 VALUES(1);
|
|
INSERT INTO t1 VALUES(1), (2);
|
|
# Connection 2
|
|
CALL p1();
|
|
COUNT(f1(a))
|
|
2
|
|
SET DEBUG_SYNC= 'after_open_table_mdl_shared SIGNAL locked_t1 WAIT_FOR go_for_t0';
|
|
# This call used to cause an assertion. MDL deadlock with upcoming
|
|
# LOCK TABLES statement will cause back-off and retry.
|
|
# A variable indicating if a prelocking list exists, used to be not
|
|
# reset properly causing an eventual assert.
|
|
# Sending:
|
|
CALL p1();
|
|
# Connection default
|
|
SET DEBUG_SYNC= 'now WAIT_FOR locked_t1';
|
|
# Issue LOCK TABLES statement which will enter in MDL deadlock
|
|
# with CALL statement and as result will cause it to perform
|
|
# back-off and retry.
|
|
SET DEBUG_SYNC= 'mdl_acquire_lock_wait SIGNAL go_for_t0';
|
|
LOCK TABLES t0 WRITE, t1 WRITE;
|
|
UNLOCK TABLES;
|
|
# Connection 2
|
|
# Reaping: CALL p1()
|
|
COUNT(f1(a))
|
|
2
|
|
# Connection default
|
|
DROP PROCEDURE p1;
|
|
DROP FUNCTION f1;
|
|
DROP TABLES t0, t1;
|
|
SET DEBUG_SYNC= 'RESET';
|