mirror of
https://github.com/MariaDB/server.git
synced 2025-07-26 07:02:12 +03:00
Moved early check for table existance to mysql_execute_command()
MDEV-17772 - 3 way lock : ALTER, MDL, BACKUP STAGE BLOCK_DDL While waiting for a (potentially long) RO transaction or SELECT, DDL and LOCK TABLES ... WRITE hold protection against FTWRL and BACKUP STAGE. This effectively makes FTWRL/BACKUP STAGE indirectly wait for this RO transaction or SELECT to finish. Which is not great, as otherwise we could do something useful meanwhile. With this patch BACKUP lock is attempted to be acquired after TABLE/SCHEMA locks. If this attempt fails, TABLE/SCHEMA locks gets released and we start waiting for BACKUP lock. When wait finishes, BACKUP lock is released (to avoid deadlocks) and we attempt to acquire all locks once again. Other changes: - Take MDL lock before testing if table exists as part of CREATE TABLE ... IF EXISTS. This change was an effect of changes in lock_table_name and removes an inconsistency where one could get different error messages from CREATE TABLE .. IF EXISTS depending on active mdl locks. One effect of this change is that we don't binary log CREATE TABLE IF EXISTS if the table exists. This was done because old code was sometimes behaving inconsistenly (it was logged some time and not other times) and sending the query to the slave could make the slave even more inconsistent as there is not guarantee that the new table will have the same definition as the old table on the master.
This commit is contained in:
@ -107,12 +107,10 @@ backup stage start;
|
||||
backup stage flush;
|
||||
SET STATEMENT lock_wait_timeout=0 FOR SELECT * FROM t1;
|
||||
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
|
||||
SET STATEMENT lock_wait_timeout=0 FOR backup stage block_ddl;
|
||||
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
|
||||
backup stage block_ddl;
|
||||
SELECT LOCK_MODE, LOCK_TYPE, TABLE_SCHEMA, TABLE_NAME FROM information_schema.metadata_lock_info;
|
||||
LOCK_MODE LOCK_TYPE TABLE_SCHEMA TABLE_NAME
|
||||
MDL_BACKUP_DDL Backup lock
|
||||
MDL_BACKUP_FLUSH Backup lock
|
||||
MDL_BACKUP_WAIT_DDL Backup lock
|
||||
MDL_SHARED_WRITE Table metadata lock test t1
|
||||
MDL_INTENTION_EXCLUSIVE Schema metadata lock test
|
||||
backup stage end;
|
||||
|
@ -142,8 +142,7 @@ let $wait_condition=
|
||||
--error ER_LOCK_WAIT_TIMEOUT
|
||||
SET STATEMENT lock_wait_timeout=0 FOR SELECT * FROM t1;
|
||||
|
||||
--error ER_LOCK_WAIT_TIMEOUT
|
||||
SET STATEMENT lock_wait_timeout=0 FOR backup stage block_ddl;
|
||||
backup stage block_ddl;
|
||||
SELECT LOCK_MODE, LOCK_TYPE, TABLE_SCHEMA, TABLE_NAME FROM information_schema.metadata_lock_info;
|
||||
backup stage end;
|
||||
|
||||
@ -195,15 +194,10 @@ SET STATEMENT lock_wait_timeout=0 FOR DROP TABLE t1;
|
||||
connection con2;
|
||||
backup stage start;
|
||||
backup stage flush;
|
||||
--send backup stage block_ddl
|
||||
backup stage block_ddl;
|
||||
connection default;
|
||||
let $wait_condition=
|
||||
select count(*) = 1 from information_schema.processlist
|
||||
where state = "Waiting for backup lock";
|
||||
--source include/wait_condition.inc
|
||||
commit;
|
||||
connection con2;
|
||||
--reap
|
||||
backup stage end;
|
||||
connection con1;
|
||||
--reap # DROP TABLE
|
||||
|
28
mysql-test/main/backup_lock_debug.result
Normal file
28
mysql-test/main/backup_lock_debug.result
Normal file
@ -0,0 +1,28 @@
|
||||
#
|
||||
# Make sure pending LOCK TABLES doesn't block BACKUP STAGE
|
||||
#
|
||||
CREATE TABLE t1(a INT);
|
||||
LOCK TABLE t1 READ;
|
||||
#
|
||||
connect con1,localhost,root,,;
|
||||
SET DEBUG_SYNC= 'mdl_acquire_lock_wait SIGNAL ready';
|
||||
LOCK TABLE t1 WRITE;
|
||||
#
|
||||
connect con2,localhost,root,,;
|
||||
SET DEBUG_SYNC= 'now WAIT_FOR ready';
|
||||
BACKUP STAGE START;
|
||||
BACKUP STAGE FLUSH;
|
||||
BACKUP STAGE BLOCK_DDL;
|
||||
BACKUP STAGE END;
|
||||
disconnect con2;
|
||||
#
|
||||
connection default;
|
||||
UNLOCK TABLES;
|
||||
#
|
||||
connection con1;
|
||||
UNLOCK TABLES;
|
||||
disconnect con1;
|
||||
#
|
||||
connection default;
|
||||
DROP TABLE t1;
|
||||
SET DEBUG_SYNC= 'RESET';
|
40
mysql-test/main/backup_lock_debug.test
Normal file
40
mysql-test/main/backup_lock_debug.test
Normal file
@ -0,0 +1,40 @@
|
||||
########################################################################
|
||||
# Tests for BACKUP STAGE locking that requires debug.
|
||||
########################################################################
|
||||
|
||||
--source include/have_debug_sync.inc
|
||||
|
||||
--echo #
|
||||
--echo # Make sure pending LOCK TABLES doesn't block BACKUP STAGE
|
||||
--echo #
|
||||
CREATE TABLE t1(a INT);
|
||||
LOCK TABLE t1 READ;
|
||||
|
||||
--echo #
|
||||
connect (con1,localhost,root,,);
|
||||
SET DEBUG_SYNC= 'mdl_acquire_lock_wait SIGNAL ready';
|
||||
--send LOCK TABLE t1 WRITE
|
||||
|
||||
--echo #
|
||||
connect (con2,localhost,root,,);
|
||||
SET DEBUG_SYNC= 'now WAIT_FOR ready';
|
||||
BACKUP STAGE START;
|
||||
BACKUP STAGE FLUSH;
|
||||
BACKUP STAGE BLOCK_DDL;
|
||||
BACKUP STAGE END;
|
||||
disconnect con2;
|
||||
|
||||
--echo #
|
||||
connection default;
|
||||
UNLOCK TABLES;
|
||||
|
||||
--echo #
|
||||
connection con1;
|
||||
reap;
|
||||
UNLOCK TABLES;
|
||||
disconnect con1;
|
||||
|
||||
--echo #
|
||||
connection default;
|
||||
DROP TABLE t1;
|
||||
SET DEBUG_SYNC= 'RESET';
|
@ -322,8 +322,6 @@ Log_name Pos Event_type Server_id End_log_pos Info
|
||||
# # Gtid 1 # GTID #-#-#
|
||||
# # Query 1 # use `test`; CREATE TABLE t1(a INT, b INT)
|
||||
# # Gtid 1 # GTID #-#-#
|
||||
# # Query 1 # use `test`; CREATE TABLE IF NOT EXISTS t1(a INT, b INT)
|
||||
# # Gtid 1 # GTID #-#-#
|
||||
# # Query 1 # use `test`; CREATE OR REPLACE INDEX i1 ON t1(a)
|
||||
# # Gtid 1 # GTID #-#-#
|
||||
# # Query 1 # use `test`; CREATE OR REPLACE INDEX i1 ON t1(a)
|
||||
@ -377,8 +375,6 @@ Log_name Pos Event_type Server_id End_log_pos Info
|
||||
# # Gtid 1 # GTID #-#-#
|
||||
# # Query 1 # use `test`; CREATE TABLE t1(a INT, b INT)
|
||||
# # Gtid 1 # GTID #-#-#
|
||||
# # Query 1 # use `test`; CREATE TABLE IF NOT EXISTS t1(a INT, b INT)
|
||||
# # Gtid 1 # GTID #-#-#
|
||||
# # Query 1 # use `test`; CREATE INDEX IF NOT EXISTS i1 ON t1(a)
|
||||
# # Gtid 1 # GTID #-#-#
|
||||
# # Query 1 # use `test`; CREATE INDEX IF NOT EXISTS i1 ON t1(a)
|
||||
|
@ -1693,13 +1693,39 @@ disconnect con2;
|
||||
#
|
||||
connection default;
|
||||
FLUSH TABLES WITH READ LOCK;
|
||||
UNLOCK TABLES;
|
||||
HANDLER t1 CLOSE;
|
||||
#
|
||||
connection con1;
|
||||
UNLOCK TABLES;
|
||||
disconnect con1;
|
||||
#
|
||||
connection default;
|
||||
DROP TABLE t1;
|
||||
SET DEBUG_SYNC= 'RESET';
|
||||
#
|
||||
# Make sure pending LOCK TABLES doesn't block FTWRL
|
||||
#
|
||||
CREATE TABLE t1(a INT);
|
||||
LOCK TABLE t1 READ;
|
||||
#
|
||||
connect con1,localhost,root,,;
|
||||
SET DEBUG_SYNC= 'mdl_acquire_lock_wait SIGNAL ready';
|
||||
LOCK TABLE t1 WRITE;
|
||||
#
|
||||
connect con2,localhost,root,,;
|
||||
SET DEBUG_SYNC= 'now WAIT_FOR ready';
|
||||
FLUSH TABLES WITH READ LOCK;
|
||||
UNLOCK TABLES;
|
||||
disconnect con2;
|
||||
#
|
||||
connection default;
|
||||
UNLOCK TABLES;
|
||||
#
|
||||
connection con1;
|
||||
UNLOCK TABLES;
|
||||
disconnect con1;
|
||||
#
|
||||
connection default;
|
||||
UNLOCK TABLES;
|
||||
HANDLER t1 CLOSE;
|
||||
DROP TABLE t1;
|
||||
SET DEBUG_SYNC= 'RESET';
|
||||
|
@ -2037,7 +2037,43 @@ disconnect con2;
|
||||
|
||||
--echo #
|
||||
connection default;
|
||||
--send FLUSH TABLES WITH READ LOCK
|
||||
FLUSH TABLES WITH READ LOCK;
|
||||
UNLOCK TABLES;
|
||||
HANDLER t1 CLOSE;
|
||||
|
||||
--echo #
|
||||
connection con1;
|
||||
reap;
|
||||
UNLOCK TABLES;
|
||||
disconnect con1;
|
||||
|
||||
--echo #
|
||||
connection default;
|
||||
DROP TABLE t1;
|
||||
SET DEBUG_SYNC= 'RESET';
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # Make sure pending LOCK TABLES doesn't block FTWRL
|
||||
--echo #
|
||||
CREATE TABLE t1(a INT);
|
||||
LOCK TABLE t1 READ;
|
||||
|
||||
--echo #
|
||||
connect (con1,localhost,root,,);
|
||||
SET DEBUG_SYNC= 'mdl_acquire_lock_wait SIGNAL ready';
|
||||
--send LOCK TABLE t1 WRITE
|
||||
|
||||
--echo #
|
||||
connect (con2,localhost,root,,);
|
||||
SET DEBUG_SYNC= 'now WAIT_FOR ready';
|
||||
FLUSH TABLES WITH READ LOCK;
|
||||
UNLOCK TABLES;
|
||||
disconnect con2;
|
||||
|
||||
--echo #
|
||||
connection default;
|
||||
UNLOCK TABLES;
|
||||
|
||||
--echo #
|
||||
connection con1;
|
||||
@ -2047,8 +2083,5 @@ disconnect con1;
|
||||
|
||||
--echo #
|
||||
connection default;
|
||||
reap;
|
||||
UNLOCK TABLES;
|
||||
HANDLER t1 CLOSE;
|
||||
DROP TABLE t1;
|
||||
SET DEBUG_SYNC= 'RESET';
|
||||
|
@ -3124,72 +3124,3 @@ connection default;
|
||||
SET debug_sync='RESET';
|
||||
DROP TABLE t1;
|
||||
disconnect con1;
|
||||
#
|
||||
# MDEV-5336 - Implement LOCK FOR BACKUP
|
||||
#
|
||||
# Make sure deadlock detector prefers FTWRL connection as a victim
|
||||
# and FTWRL retries lock attempt. This deadlock was present before
|
||||
# MDEV-5336.
|
||||
CREATE TABLE t1(a INT) ENGINE=InnoDB;
|
||||
CREATE TABLE t2(a INT) ENGINE=InnoDB;
|
||||
BEGIN;
|
||||
SELECT * FROM t2;
|
||||
a
|
||||
#
|
||||
connect con1,localhost,root,,;
|
||||
SET DEBUG_SYNC='mdl_acquire_lock_wait SIGNAL waiting';
|
||||
LOCK TABLES t2 WRITE;
|
||||
#
|
||||
connect con2,localhost,root,,;
|
||||
SET DEBUG_SYNC='now WAIT_FOR waiting';
|
||||
SET DEBUG_SYNC='mdl_acquire_lock_wait SIGNAL waiting';
|
||||
FLUSH TABLES WITH READ LOCK;
|
||||
#
|
||||
connection default;
|
||||
SET DEBUG_SYNC='now WAIT_FOR waiting';
|
||||
INSERT INTO t1 VALUES(1);
|
||||
COMMIT;
|
||||
connection con1;
|
||||
UNLOCK TABLES;
|
||||
connection con2;
|
||||
UNLOCK TABLES;
|
||||
connection default;
|
||||
DROP TABLE t1, t2;
|
||||
SET DEBUG_SYNC='RESET';
|
||||
disconnect con1;
|
||||
disconnect con2;
|
||||
# Make sure deadlock detector prefers FTWRL connection as a victim
|
||||
# and FTWRL retries lock attempt. This deadlock was found during
|
||||
# MDEV-5336 review.
|
||||
CREATE TABLE t1(a INT) ENGINE=InnoDB;
|
||||
CREATE TABLE t2(a INT) ENGINE=InnoDB;
|
||||
BEGIN;
|
||||
INSERT INTO t2 VALUES(1);
|
||||
SET DEBUG_SYNC='after_open_table_mdl_shared SIGNAL table_opened WAIT_FOR go';
|
||||
INSERT INTO t1 VALUES(1);
|
||||
#
|
||||
connect con1,localhost,root,,;
|
||||
SET DEBUG_SYNC='now WAIT_FOR table_opened';
|
||||
SET DEBUG_SYNC='mdl_acquire_lock_wait SIGNAL waiting';
|
||||
LOCK TABLES t1 WRITE;
|
||||
#
|
||||
connect con2,localhost,root,,;
|
||||
SET DEBUG_SYNC='now WAIT_FOR waiting';
|
||||
SET DEBUG_SYNC='mdl_acquire_lock_wait SIGNAL waiting';
|
||||
FLUSH TABLES WITH READ LOCK;
|
||||
#
|
||||
connect con3,localhost,root,,;
|
||||
SET DEBUG_SYNC='now WAIT_FOR waiting';
|
||||
SET DEBUG_SYNC='now SIGNAL go';
|
||||
connection default;
|
||||
COMMIT;
|
||||
connection con1;
|
||||
UNLOCK TABLES;
|
||||
connection con2;
|
||||
UNLOCK TABLES;
|
||||
connection default;
|
||||
DROP TABLE t1, t2;
|
||||
SET DEBUG_SYNC='RESET';
|
||||
disconnect con1;
|
||||
disconnect con2;
|
||||
disconnect con3;
|
||||
|
@ -4168,91 +4168,6 @@ DROP TABLE t1;
|
||||
|
||||
disconnect con1;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # MDEV-5336 - Implement LOCK FOR BACKUP
|
||||
--echo #
|
||||
|
||||
--echo # Make sure deadlock detector prefers FTWRL connection as a victim
|
||||
--echo # and FTWRL retries lock attempt. This deadlock was present before
|
||||
--echo # MDEV-5336.
|
||||
CREATE TABLE t1(a INT) ENGINE=InnoDB;
|
||||
CREATE TABLE t2(a INT) ENGINE=InnoDB;
|
||||
BEGIN;
|
||||
SELECT * FROM t2;
|
||||
|
||||
--echo #
|
||||
connect(con1,localhost,root,,);
|
||||
SET DEBUG_SYNC='mdl_acquire_lock_wait SIGNAL waiting';
|
||||
send LOCK TABLES t2 WRITE;
|
||||
|
||||
--echo #
|
||||
connect(con2,localhost,root,,);
|
||||
SET DEBUG_SYNC='now WAIT_FOR waiting';
|
||||
SET DEBUG_SYNC='mdl_acquire_lock_wait SIGNAL waiting';
|
||||
send FLUSH TABLES WITH READ LOCK;
|
||||
|
||||
--echo #
|
||||
connection default;
|
||||
SET DEBUG_SYNC='now WAIT_FOR waiting';
|
||||
INSERT INTO t1 VALUES(1);
|
||||
COMMIT;
|
||||
|
||||
connection con1;
|
||||
reap;
|
||||
UNLOCK TABLES;
|
||||
connection con2;
|
||||
reap;
|
||||
UNLOCK TABLES;
|
||||
connection default;
|
||||
DROP TABLE t1, t2;
|
||||
SET DEBUG_SYNC='RESET';
|
||||
disconnect con1;
|
||||
disconnect con2;
|
||||
|
||||
--echo # Make sure deadlock detector prefers FTWRL connection as a victim
|
||||
--echo # and FTWRL retries lock attempt. This deadlock was found during
|
||||
--echo # MDEV-5336 review.
|
||||
CREATE TABLE t1(a INT) ENGINE=InnoDB;
|
||||
CREATE TABLE t2(a INT) ENGINE=InnoDB;
|
||||
BEGIN;
|
||||
INSERT INTO t2 VALUES(1);
|
||||
SET DEBUG_SYNC='after_open_table_mdl_shared SIGNAL table_opened WAIT_FOR go';
|
||||
send INSERT INTO t1 VALUES(1);
|
||||
|
||||
--echo #
|
||||
connect(con1,localhost,root,,);
|
||||
SET DEBUG_SYNC='now WAIT_FOR table_opened';
|
||||
SET DEBUG_SYNC='mdl_acquire_lock_wait SIGNAL waiting';
|
||||
send LOCK TABLES t1 WRITE;
|
||||
|
||||
--echo #
|
||||
connect(con2,localhost,root,,);
|
||||
SET DEBUG_SYNC='now WAIT_FOR waiting';
|
||||
SET DEBUG_SYNC='mdl_acquire_lock_wait SIGNAL waiting';
|
||||
send FLUSH TABLES WITH READ LOCK;
|
||||
|
||||
--echo #
|
||||
connect(con3,localhost,root,,);
|
||||
SET DEBUG_SYNC='now WAIT_FOR waiting';
|
||||
SET DEBUG_SYNC='now SIGNAL go';
|
||||
|
||||
connection default;
|
||||
reap;
|
||||
COMMIT;
|
||||
connection con1;
|
||||
reap;
|
||||
UNLOCK TABLES;
|
||||
connection con2;
|
||||
reap;
|
||||
UNLOCK TABLES;
|
||||
connection default;
|
||||
DROP TABLE t1, t2;
|
||||
SET DEBUG_SYNC='RESET';
|
||||
disconnect con1;
|
||||
disconnect con2;
|
||||
disconnect con3;
|
||||
|
||||
# Check that all connections opened by test cases in this file are really
|
||||
# gone so execution of other tests won't be affected by their presence.
|
||||
--source include/wait_until_count_sessions.inc
|
||||
|
@ -25,8 +25,6 @@ connection slave;
|
||||
connection slave;
|
||||
SHOW TABLES in mysqltest;
|
||||
Tables_in_mysqltest
|
||||
t
|
||||
t1
|
||||
SHOW EVENTS in mysqltest;
|
||||
Db Name Definer Time zone Type Execute at Interval value Interval field Starts Ends Status Originator character_set_client collation_connection Database Collation
|
||||
mysqltest e root@localhost SYSTEM ONE TIME # NULL NULL NULL NULL SLAVESIDE_DISABLED 1 latin1 latin1_swedish_ci latin1_swedish_ci
|
||||
|
131
sql/sql_base.cc
131
sql/sql_base.cc
@ -3883,6 +3883,39 @@ end:
|
||||
}
|
||||
|
||||
|
||||
static bool upgrade_lock_if_not_exists(THD *thd,
|
||||
const DDL_options_st &create_info,
|
||||
TABLE_LIST *create_table,
|
||||
ulong lock_wait_timeout)
|
||||
{
|
||||
DBUG_ENTER("upgrade_lock_if_not_exists");
|
||||
|
||||
if (thd->lex->sql_command == SQLCOM_CREATE_TABLE ||
|
||||
thd->lex->sql_command == SQLCOM_CREATE_SEQUENCE)
|
||||
{
|
||||
if (!create_info.or_replace() &&
|
||||
ha_table_exists(thd, &create_table->db, &create_table->table_name))
|
||||
{
|
||||
if (create_info.if_not_exists())
|
||||
{
|
||||
push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
|
||||
ER_TABLE_EXISTS_ERROR,
|
||||
ER_THD(thd, ER_TABLE_EXISTS_ERROR),
|
||||
create_table->table_name.str);
|
||||
}
|
||||
else
|
||||
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), create_table->table_name.str);
|
||||
DBUG_RETURN(true);
|
||||
}
|
||||
DBUG_RETURN(thd->mdl_context.upgrade_shared_lock(
|
||||
create_table->mdl_request.ticket,
|
||||
MDL_EXCLUSIVE,
|
||||
lock_wait_timeout));
|
||||
}
|
||||
DBUG_RETURN(false);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Acquire upgradable (SNW, SNRW) metadata locks on tables used by
|
||||
LOCK TABLES or by a DDL statement. Under LOCK TABLES, we can't take
|
||||
@ -3920,10 +3953,7 @@ lock_table_names(THD *thd, const DDL_options_st &options,
|
||||
MDL_request_list mdl_requests;
|
||||
TABLE_LIST *table;
|
||||
MDL_request global_request;
|
||||
ulong org_lock_wait_timeout= lock_wait_timeout;
|
||||
/* Check if we are using CREATE TABLE ... IF NOT EXISTS */
|
||||
bool create_table;
|
||||
Dummy_error_handler error_handler;
|
||||
MDL_savepoint mdl_savepoint;
|
||||
DBUG_ENTER("lock_table_names");
|
||||
|
||||
DBUG_ASSERT(!thd->locked_tables_mode);
|
||||
@ -3966,75 +3996,48 @@ lock_table_names(THD *thd, const DDL_options_st &options,
|
||||
if (mdl_requests.is_empty())
|
||||
DBUG_RETURN(FALSE);
|
||||
|
||||
/* Check if CREATE TABLE without REPLACE was used */
|
||||
create_table= ((thd->lex->sql_command == SQLCOM_CREATE_TABLE ||
|
||||
thd->lex->sql_command == SQLCOM_CREATE_SEQUENCE) &&
|
||||
!options.or_replace());
|
||||
|
||||
if (!(flags & MYSQL_OPEN_SKIP_SCOPED_MDL_LOCK))
|
||||
if (flags & MYSQL_OPEN_SKIP_SCOPED_MDL_LOCK)
|
||||
{
|
||||
/*
|
||||
Protect this statement against concurrent global read lock
|
||||
by acquiring global intention exclusive lock with statement
|
||||
duration.
|
||||
*/
|
||||
if (thd->has_read_only_protection())
|
||||
DBUG_RETURN(TRUE);
|
||||
global_request.init(MDL_key::BACKUP, "", "", MDL_BACKUP_DDL,
|
||||
MDL_STATEMENT);
|
||||
mdl_requests.push_front(&global_request);
|
||||
|
||||
if (create_table)
|
||||
#ifdef WITH_WSREP
|
||||
if (thd->lex->sql_command != SQLCOM_CREATE_TABLE &&
|
||||
thd->wsrep_exec_mode != REPL_RECV)
|
||||
#endif
|
||||
lock_wait_timeout= 0; // Don't wait for timeout
|
||||
DBUG_RETURN(thd->mdl_context.acquire_locks(&mdl_requests,
|
||||
lock_wait_timeout) ||
|
||||
upgrade_lock_if_not_exists(thd, options, tables_start,
|
||||
lock_wait_timeout));
|
||||
}
|
||||
|
||||
for (;;)
|
||||
/* Protect this statement against concurrent BACKUP STAGE or FTWRL. */
|
||||
if (thd->has_read_only_protection())
|
||||
DBUG_RETURN(true);
|
||||
|
||||
global_request.init(MDL_key::BACKUP, "", "", MDL_BACKUP_DDL, MDL_STATEMENT);
|
||||
mdl_savepoint= thd->mdl_context.mdl_savepoint();
|
||||
|
||||
while (!thd->mdl_context.acquire_locks(&mdl_requests, lock_wait_timeout) &&
|
||||
!upgrade_lock_if_not_exists(thd, options, tables_start,
|
||||
lock_wait_timeout) &&
|
||||
!thd->mdl_context.try_acquire_lock(&global_request))
|
||||
{
|
||||
if (create_table)
|
||||
thd->push_internal_handler(&error_handler); // Avoid warnings & errors
|
||||
bool res= thd->mdl_context.acquire_locks(&mdl_requests, lock_wait_timeout);
|
||||
if (!(flags & MYSQL_OPEN_SKIP_SCOPED_MDL_LOCK))
|
||||
thd->mdl_backup_ticket= global_request.ticket;
|
||||
if (create_table)
|
||||
thd->pop_internal_handler();
|
||||
if (!res)
|
||||
DBUG_RETURN(FALSE); // Got locks
|
||||
|
||||
if (!create_table)
|
||||
DBUG_RETURN(TRUE); // Return original error
|
||||
|
||||
/*
|
||||
We come here in the case of lock timeout when executing CREATE TABLE.
|
||||
Verify that table does exist (it usually does, as we got a lock conflict)
|
||||
*/
|
||||
if (ha_table_exists(thd, &tables_start->db, &tables_start->table_name))
|
||||
if (global_request.ticket)
|
||||
{
|
||||
if (options.if_not_exists())
|
||||
{
|
||||
push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
|
||||
ER_TABLE_EXISTS_ERROR,
|
||||
ER_THD(thd, ER_TABLE_EXISTS_ERROR),
|
||||
tables_start->table_name.str);
|
||||
}
|
||||
else
|
||||
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), tables_start->table_name.str);
|
||||
DBUG_RETURN(TRUE);
|
||||
thd->mdl_backup_ticket= global_request.ticket;
|
||||
DBUG_RETURN(false);
|
||||
}
|
||||
|
||||
/*
|
||||
We got error from acquire_locks, but the table didn't exists.
|
||||
This could happen if another connection runs a statement
|
||||
involving this non-existent table, and this statement took the mdl,
|
||||
but didn't error out with ER_NO_SUCH_TABLE yet (yes, a race condition).
|
||||
We play safe and restart the original acquire_locks with the
|
||||
original timeout.
|
||||
There is ongoing or pending BACKUP STAGE or FTWRL.
|
||||
Wait until it finishes and re-try.
|
||||
*/
|
||||
create_table= 0;
|
||||
lock_wait_timeout= org_lock_wait_timeout;
|
||||
thd->mdl_context.rollback_to_savepoint(mdl_savepoint);
|
||||
if (thd->mdl_context.acquire_lock(&global_request, lock_wait_timeout))
|
||||
break;
|
||||
thd->mdl_context.rollback_to_savepoint(mdl_savepoint);
|
||||
|
||||
/* Reset tickets for all acquired locks */
|
||||
global_request.ticket= 0;
|
||||
MDL_request_list::Iterator it(mdl_requests);
|
||||
while (auto mdl_request= it++)
|
||||
mdl_request->ticket= 0;
|
||||
}
|
||||
DBUG_RETURN(true);
|
||||
}
|
||||
|
||||
|
||||
|
@ -2648,7 +2648,7 @@ create:
|
||||
LEX *lex= thd->lex;
|
||||
if (!lex->first_select_lex()->
|
||||
add_table_to_list(thd, $6, NULL, TL_OPTION_UPDATING,
|
||||
TL_WRITE, MDL_EXCLUSIVE))
|
||||
TL_WRITE, MDL_SHARED_UPGRADABLE))
|
||||
MYSQL_YYABORT;
|
||||
lex->alter_info.reset();
|
||||
/*
|
||||
|
@ -2165,7 +2165,7 @@ create:
|
||||
LEX *lex= thd->lex;
|
||||
if (!lex->first_select_lex()->
|
||||
add_table_to_list(thd, $6, NULL, TL_OPTION_UPDATING,
|
||||
TL_WRITE, MDL_EXCLUSIVE))
|
||||
TL_WRITE, MDL_SHARED_UPGRADABLE))
|
||||
MYSQL_YYABORT;
|
||||
lex->alter_info.reset();
|
||||
/*
|
||||
|
Reference in New Issue
Block a user