Skip to content

Commit

Permalink
FB8-98, FB8-126, FB8-127: Introducing high priority DDLs (facebook#1011
Browse files Browse the repository at this point in the history
…) (facebook#1011)

Summary:
Jira ticket: https://jira.percona.com/browse/FB8-98

Reference commit: 2b59a06
Reference commit: f816fee
Reference commit: 397fa65
Reference commit: 00323f7
Reference commit: bffb8d7
Reference commit: e9cb575
Reference commit: b145f26
Reference commit: 7e41852
Reference commit: 434d496
Reference commit: facebook@ee63260f74b

-------- 2b59a06 --------

This diff introduces high priority DDLs. If enabled, DDLs will kill the
blocking connections that hold shared metadata locks. Below are the details:

- Added high_priority_ddl system variable that will allow DDL to kill blocking
  connections which hold shared locks. High priority DDLs are only available to
  admin users. By default the functionality is turned off.
- Only the shared locks (read/write) will be affected, which are DML queries
  such as select, insert, update, etc. Any lock higher than upgradable MDL
  (i.e. from conflicting DDL) will not be affected.
- When killing the blocking connections, their transactions will automatically
  be rolled back. This is the same behavior as `kill processlist_id` command.
- The DDL will kill blocking connections at the end of the timeout instead of
  instantly. Admin can control the waiting period by setting the session
  lock_wait_timeout before issuing the DDL.

-------- 397fa65 --------

This feature has been dropped.

Adding high_priority syntax in DDL commands

This diff introduces `HIGH_PRIORITY` syntax in some DDL commands and optimize
command. The purpose is the same as the system variable `high_priority_ddl`
which is described in D4784076 (facebook@2b59a06).

The list of commands that support `HIGH_PRIORITY` syntax is:
- create/drop/alter/truncate table
- create/drop index
- create/drop trigger
- optimize table

With this diff, there are two ways of issuing high priority DDLs:
  e.g. `CREATE HIGH_PRIORITY INDEX ...`

Recap of the high_priority ddl feature:

- Only the shared locks (read/write) will be affected, which are DML queries
  such as select, insert, update, etc. Any lock higher than upgradable MDL
  (i.e. from conflicting DDL) will not be affected.
- When killing the blocking connections, their transactions will automatically
  be rolled back. This is the same behavior as `kill processlist_id` command.
- The DDL will kill blocking connections at the end of the timeout instead of
  instantly. Admin can control the waiting period by setting the session
  lock_wait_timeout before issuing the DDL.

-------- b145f26 --------

Add LOCK TABLES as a supported command for high priority ddl

Although LOCK TABLES is not a ddl command, it is useful to have it support taking mdl locks with high priority, via the high_priority_ddl session variable.

-------- 7e41852 --------

Add high_priority_lock_wait_timeout system variable

The original lock_wait_timeout is used for all queries and also the long
running slave threads. It'll be better that high_priority commands (DDLs) use
a separate system variable for timeout, which can be used across the
master/slaves without messing with lock_wait_timeout.

This diff introduces a new system variable high_priority_lock_wait_timeout that
can be set for high_priority command's lock wait timeout, after which the
command's thread will kill shared locks that are blocking the command.

The new variable doesn't apply to regular queries.
Pull Request resolved: facebook#1011

Differential Revision: D14884073

Pulled By: hermanlee
  • Loading branch information
dutow authored and inikep committed May 10, 2024
1 parent 9a3a9d6 commit f8faaf6
Show file tree
Hide file tree
Showing 28 changed files with 1,863 additions and 344 deletions.
166 changes: 166 additions & 0 deletions mysql-test/include/ddl_high_priority.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
###############################################################################
# Common test file for high priority DDL
###############################################################################


create user test_user1@localhost;
grant all on test to test_user1@localhost;
create user test_user2@localhost;
grant all on test to test_user2@localhost;

# Default values
--let $con_block = con1
--let $con_kill = default
--let $should_kill = 1
--let $recreate_table = 1
--let $throw_error = 1

##
## killing conflicting shared locks by alter table
##

--let $blocking_sql = lock tables t1 read;
--let $cmd = alter table t1 modify i bigint;

--source include/ddl_high_priority_module.inc

##
## killing conflicting shared lock in a transaction
## transaction will rollback
##

--let $blocking_sql = begin; insert into t1 values (4); select i from t1;
--let $cmd = alter table t1 rename t1_new;

--source include/ddl_high_priority_module.inc

select * from t1_new;
drop table t1_new;

##
## simulate conflicting DDL which will not be killed
##

# Simulate conflicting DDL
# This will hold MDL_SHARED_NO_READ_WRITE, which may be upgraded to exclusive
# locks to run DDLs like ALTER TABLE
# the upgradable/exclusive lock should not be killed

--let $should_kill = 0
--let $blocking_sql = lock tables t1 write;
--let $cmd = drop table t1;

--source include/ddl_high_priority_module.inc

# restore $should_kill
--let $should_kill = 1

##
## killing conflicting transaction by drop table DDL
##

--let $blocking_sql = lock tables t1 read; begin; insert into t1 values (4);
--let $cmd = drop table t1;

--source include/ddl_high_priority_module.inc

##
## no effect for regular users
##

let $count_sessions = 1;

connect (con2,localhost,test_user2,,test,,);
# $con_kill is regular user
--let $con_kill = con2
--let $should_kill = 0

--let $blocking_sql = lock tables t1 read;
--let $cmd = alter table t1 modify i bigint;

--source include/ddl_high_priority_module.inc

disconnect con2;

# Ensure con2 is closed
--source include/wait_until_count_sessions.inc

# restore $con_kill
--let $con_kill = default
# restore $should_kill
--let $should_kill = 1

##
## create/drop index
##

# create index

--let $blocking_sql = lock tables t1 read;
--let $cmd = create index idx1 on t1 (i);

--source include/ddl_high_priority_module.inc

# drop index (use the previously created table)
--let $recreate_table = 0

--let $cmd = drop index idx1 on t1;

--source include/ddl_high_priority_module.inc

# restore $recreate_table
--let $recreate_table = 1

##
## high_priority truncate table
##

--let $blocking_sql = lock tables t1 read;
--let $cmd = truncate t1;

--source include/ddl_high_priority_module.inc

####high_priority create/drop trigger##

--let $blocking_sql = lock tables t1 read;
let $cmd = create trigger ins_sum before insert on t1
for each row set @sum = @sum + new.i;
--source include/ddl_high_priority_module.inc

# drop trigger (use the previously created table)
--let $recreate_table = 0
--let $cmd = drop trigger ins_sum;
--source include/ddl_high_priority_module.inc

# restore $recreate_table
--let $recreate_table = 1

##
## high_priority optimize table
##
## "optimize table" doesn't throw errors. It catches all errors, and
## returns a result set in a table
##

--let $throw_error = 0

--let $blocking_sql = lock tables t1 read;
--let $cmd = optimize table t1;

--source include/ddl_high_priority_module.inc

# restore throw_error
--let $throw_error = 1
--let $blocking_sql = lock tables t1 read;
--let $cmd = lock tables t1 write;

--source include/ddl_high_priority_module.inc
unlock tables;

##
## clean up
##

drop user test_user1@localhost;
drop user test_user2@localhost;
drop table t1;
125 changes: 125 additions & 0 deletions mysql-test/include/ddl_high_priority_module.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
###############################################################################
# This file plays as a function/module for ddl_high_priority test
#
# Usage: set the following variables before including
#
# $con_block: a blocking connection
# value: con1/con2/default
#
# $con_kill: a connection that will attempt to kill $con_blocking
# value: con1/con2/default
#
# $cmd: a regular command to evaluate (to use with sys var)
# value: sql command
#
# $should_kill: Expect the con_block to be killed or not
# value: 0/1
#
# $recreate_table: Should recreate the test table or not
# value: 0/1
#
# $throw_error: whether a command will throw lock_wait_timeout error.
# Note, optimize table catches all errors.
# value: 0/1
###############################################################################

##
## Print out the parameters of the test set
## (useful for debugging)
##
--echo
--echo ## Test parameters:
--echo ## con_block = $con_block
--echo ## con_kill = $con_kill
--echo ## cmd = $cmd
--echo ## should_kill = $should_kill
--echo ## recreate_table = $recreate_table
--echo ## throw_error = $throw_error
--echo


##
## Setup
##


# Save the initial number of concurrent sessions
--source include/count_sessions.inc

connection default;

# create con1
connect (con1,localhost,test_user1,,test,,);

if ($recreate_table) {
# create t1
--disable_warnings
drop table if exists t1;
--enable_warnings
create table t1 (i int);
show create table t1;
insert into t1 values (1), (2), (3);
}

##
## Testing
##

--echo connection: $con_block
--connection $con_block
--eval $blocking_sql

--echo connection: $con_kill
--connection $con_kill
set lock_wait_timeout = 0.02;
set high_priority_lock_wait_timeout = 0.02;

describe t1;

--echo connection: default (for show processlist)
connection default;
--echo # both $con_block and $con_kill exists
--replace_column 1 # 3 # 5 # 6 # 7 # 8 # 9 # 10 # 11 #
show processlist;

--echo connection: $con_kill
--connection $con_kill

# command will fail without high_priority
if ($throw_error) {
--error ER_LOCK_WAIT_TIMEOUT
--eval $cmd
}

if (!$throw_error) {
--eval $cmd
}

set high_priority_ddl = 1;
select @@high_priority_ddl;

#non - supported command will timeout
--error ER_LOCK_WAIT_TIMEOUT
rename table t1 to t2;

if (!$should_kill) {
#regular user ddl will fail regardless of high_priority_ddl being on
--error ER_LOCK_WAIT_TIMEOUT
--eval $cmd
}

if ($should_kill) {
--eval $cmd
}

#reset high_priority_ddl
set high_priority_ddl = 0;

--echo connection: default (for show processlist)
connection default;
--replace_column 1 # 3 # 5 # 6 # 7 # 8 # 9 # 10 # 11 #
show processlist;

disconnect con1;

--source include/wait_until_count_sessions.inc
Loading

0 comments on commit f8faaf6

Please sign in to comment.