| Bug #106953 | LOCK_grant and LOCK_open can deadlock on a gtid slave | ||
|---|---|---|---|
| Submitted: | 8 Apr 2022 6:42 | Modified: | 14 Jun 2022 8:27 |
| Reporter: | ting du | Email Updates: | |
| Status: | Verified | Impact on me: | |
| Category: | MySQL Server: Locking | Severity: | S3 (Non-critical) |
| Version: | 5.7 | OS: | Linux |
| Assigned to: | CPU Architecture: | Any | |
[8 Apr 2022 6:42]
ting du
[11 Apr 2022 2:41]
ting du
this bug is same with 91548, but different scenario. You can use the same my.cnf with it, but different SQL statement.
[7 Jun 2022 9:20]
MySQL Verification Team
Hello ting du,
Thank you for the report and feedback.
I tried to reproduce the issue on 5.7.38 using the conf from the referenced bug# and with the provided test case but I'm not seeing any locking issues despite trying multiple times. Please share exact version that you are seeing this issue along with any details which are missing here and in the referenced bug. Thank you.
## 5.7.38
-- setup gtid bases repl
-- 5.7
rm -rf master/
bin/mysqld --initialize-insecure --basedir=$PWD --datadir=$PWD/master --log-error-verbosity=3
bin/mysqld --no-defaults --basedir=$PWD --datadir=$PWD/master --core-file --socket=/tmp/mysql_master.sock --port=3306 --log-error=$PWD/master/log.err --gtid_mode=ON --log-slave-updates --enforce-gtid-consistency --log-bin=master-bin --server_id=1 2>&1 &
rm -rf slave/
bin/mysqld --initialize-insecure --basedir=$PWD --datadir=$PWD/slave --log-error-verbosity=3
bin/mysqld --no-defaults --basedir=$PWD --datadir=$PWD/slave --core-file --socket=/tmp/mysql_slave.sock --port=3307 --log-error=$PWD/slave/log.err --gtid_mode=ON --log-slave-updates --enforce-gtid-consistency --log-bin=slave-bin --server_id=2 --sync_master_info=1 --sync_relay_log=1 --sync_relay_log_info=1 --master_info_repository=TABLE --relay_log_info_repository=TABLE 2>&1 &
- master
bin/mysql -uroot -S /tmp/mysql_master.sock --prompt='Master>'
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.7.38-log MySQL Community Server (GPL)
Copyright (c) 2000, 2022, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
Master>CREATE USER 'repl'@'localhost' IDENTIFIED BY 'slavepass';
Query OK, 0 rows affected (0.00 sec)
Master>GRANT REPLICATION SLAVE ON *.* TO 'repl'@'localhost';
Query OK, 0 rows affected (0.00 sec)
Master>
Master>CREATE USER 'repl'@'127.0.0.1' IDENTIFIED BY 'slavepass';
Query OK, 0 rows affected (0.00 sec)
Master>GRANT REPLICATION SLAVE ON *.* TO 'repl'@'127.0.0.1';
Query OK, 0 rows affected (0.01 sec)
Master>FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.00 sec)
Master>create database test;
Query OK, 1 row affected (0.01 sec)
Master>create user 'root'@'%' identified by '123';
Query OK, 0 rows affected (0.00 sec)
Master>grant all on *.* to 'root'@'%' with grant option;
Query OK, 0 rows affected (0.00 sec)
- slave
bin/mysql -uroot -S /tmp/mysql_slave.sock --prompt='Slave>'
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.7.38-log MySQL Community Server (GPL)
Copyright (c) 2000, 2022, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
Slave>CHANGE MASTER TO
-> MASTER_HOST='localhost',
-> MASTER_PORT=3306,
-> MASTER_USER='repl',
-> MASTER_PASSWORD='slavepass',
-> MASTER_AUTO_POSITION = 1;
Query OK, 0 rows affected, 2 warnings (0.02 sec)
Slave>start slave; show slave status\G
Query OK, 0 rows affected (0.00 sec)
*************************** 1. row ***************************
Slave_IO_State: Checking master version
Master_Host: localhost
Master_User: repl
Master_Port: 3306
Connect_Retry: 60
Master_Log_File:
Read_Master_Log_Pos: 4
Relay_Log_File: support-cluster03-relay-bin.000001
Relay_Log_Pos: 4
Relay_Master_Log_File:
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Replicate_Do_DB:
Replicate_Ignore_DB:
Replicate_Do_Table:
Replicate_Ignore_Table:
Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table:
Last_Errno: 0
Last_Error:
Skip_Counter: 0
Exec_Master_Log_Pos: 0
Relay_Log_Space: 154
Until_Condition: None
Until_Log_File:
Until_Log_Pos: 0
Master_SSL_Allowed: No
Master_SSL_CA_File:
Master_SSL_CA_Path:
Master_SSL_Cert:
Master_SSL_Cipher:
Master_SSL_Key:
Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
Last_IO_Errno: 0
Last_IO_Error:
Last_SQL_Errno: 0
Last_SQL_Error:
Replicate_Ignore_Server_Ids:
Master_Server_Id: 0
Master_UUID:
Master_Info_File: mysql.slave_master_info
SQL_Delay: 0
SQL_Remaining_Delay: NULL
Slave_SQL_Running_State: System lock
Master_Retry_Count: 86400
Master_Bind:
Last_IO_Error_Timestamp:
Last_SQL_Error_Timestamp:
Master_SSL_Crl:
Master_SSL_Crlpath:
Retrieved_Gtid_Set:
Executed_Gtid_Set:
Auto_Position: 1
Replicate_Rewrite_DB:
Channel_Name:
Master_TLS_Version:
1 row in set (0.00 sec)
-- Follow steps from report
- master
yes "ALTER USER 'root'@'localhost' PASSWORD EXPIRE NEVER;"|bin/mysql -uroot -S /tmp/mysql_master.sock
/
while true; do bin/mysql -uroot -S /tmp/mysql_master.sock -e "ALTER USER 'root'@'%' PASSWORD EXPIRE NEVER;"; done
- slave
yes "show open tables;"|bin/mysql -uroot -S /tmp/mysql_slave.sock
/
while true; do bin/mysql -uroot -S /tmp/mysql_slave.sock -e "show open tables;"; done
select * from information_schema.columns order by table_schema,table_name;
regards,
Umesh
[9 Jun 2022 2:20]
ting du
From code analyze:
CREATE/DROP/ALTER USER sql will call function:
|-mysql_create_user()
|-Partitioned_rwlock_write_guard lock(&LOCK_grant); // require LOCK_grant
|-commit_owned_gtid_by_partial_command()
|-commit_owned_gtids()
|-Gtid_state::save()
|-Gtid_table_persistor::save
...
|-open_table()
|-check_if_table_exists()
|-mysql_mutex_lock(&LOCK_open); // require LOCK_open mutex
|-get_cached_table_share()
|-mysql_mutex_unlock(&LOCK_open);
`show open tables` sql call function:
|-fill_open_tables()
|-list_open_tables
|-table_cache_manager.lock_all_and_tdc(); // require LOCK_open mutex
...
|-mysql_mutex_lock(&LOCK_open);
|-check_table_access()
|-check_grant()
|-LOCK_grant_read_guard lock(thd); // require LOCK_grant read lock
...
|-table_cache_manager.unlock_all_and_tdc();
|-mysql_mutex_unlock(&LOCK_open);
...
From the code, the lock order is opposite in these two queries, a deadlock occurs.
[14 Jun 2022 8:27]
MySQL Verification Team
Thank you for the feedback. I could not reproduce using the earlier test case even after multiple attempts but your code analysis makes sense hence verifying so that dev's can conclude on this.
