mirror of
https://github.com/MariaDB/server.git
synced 2026-01-06 05:22:24 +03:00
A post-review fix for type-aware metadata locks.
DDL no longer aborts mysql_lock_tables(), and hence we no longer need to support need_reopen flag of this call. Remove the flag, and all the code in the server that was responsible for handling the case when it was set. This allowed to simplify: open_and_lock_tables_derived(), the delayed thread, multi-update. Rename MYSQL_LOCK_IGNORE_FLUSH to MYSQL_OPEN_IGNORE_FLUSH, since we now only support this flag in open_table(). Rename MYSQL_LOCK_PERF_SCHEMA to MYSQL_LOCK_LOG_TABLE, to avoid confusion. Move the wait for the global read lock for cases when we do updates in SELECT f1() or DO (UPDATE) to open_table() from mysql_lock_tables(). When waiting for the read lock, we could raise need_reopen flag, which is no longer present in mysql_lock_tables(). Since the block responsible for waiting for GRL was moved, MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK was renamed to MYSQL_OPEN_IGNORE_GLOBAL_READ_LOCK.
This commit is contained in:
145
sql/sql_base.cc
145
sql/sql_base.cc
@@ -2421,7 +2421,7 @@ open_table_get_mdl_lock(THD *thd, TABLE_LIST *table_list,
|
||||
required to remedy problem appeared during attempt
|
||||
to open table.
|
||||
flags Bitmap of flags to modify how open works:
|
||||
MYSQL_LOCK_IGNORE_FLUSH - Open table even if
|
||||
MYSQL_OPEN_IGNORE_FLUSH - Open table even if
|
||||
someone has done a flush or there is a pending
|
||||
exclusive metadata lock requests against it
|
||||
(i.e. request high priority metadata lock).
|
||||
@@ -2479,6 +2479,31 @@ bool open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
|
||||
key_length= (create_table_def_key(thd, key, table_list, 1) -
|
||||
TMP_TABLE_KEY_EXTRA);
|
||||
|
||||
/*
|
||||
We need this to work for all tables, including temporary
|
||||
tables, for backwards compatibility. But not under LOCK
|
||||
TABLES, since under LOCK TABLES one can't use a non-prelocked
|
||||
table. This code only works for updates done inside DO/SELECT
|
||||
f1() statements, normal DML is handled by means of
|
||||
sql_command_flags.
|
||||
*/
|
||||
if (global_read_lock && table_list->lock_type >= TL_WRITE_ALLOW_WRITE &&
|
||||
! (flags & MYSQL_OPEN_IGNORE_GLOBAL_READ_LOCK) &&
|
||||
! thd->locked_tables_mode)
|
||||
{
|
||||
/*
|
||||
Someone has issued FLUSH TABLES WITH READ LOCK and we want
|
||||
a write lock. Wait until the lock is gone.
|
||||
*/
|
||||
if (thd->global_read_lock.wait_if_global_read_lock(thd, 1, 1))
|
||||
DBUG_RETURN(TRUE);
|
||||
|
||||
if (thd->version != refresh_version)
|
||||
{
|
||||
(void) ot_ctx->request_backoff_action(Open_table_context::OT_WAIT_TDC);
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
}
|
||||
/*
|
||||
Unless requested otherwise, try to resolve this table in the list
|
||||
of temporary tables of this thread. In MySQL temporary tables
|
||||
@@ -2680,7 +2705,7 @@ bool open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
|
||||
if (!thd->open_tables)
|
||||
thd->version=refresh_version;
|
||||
else if ((thd->version != refresh_version) &&
|
||||
! (flags & MYSQL_LOCK_IGNORE_FLUSH))
|
||||
! (flags & MYSQL_OPEN_IGNORE_FLUSH))
|
||||
{
|
||||
/* Someone did a refresh while thread was opening tables */
|
||||
mysql_mutex_unlock(&LOCK_open);
|
||||
@@ -2811,7 +2836,7 @@ bool open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
|
||||
|
||||
if (share->version != refresh_version)
|
||||
{
|
||||
if (!(flags & MYSQL_LOCK_IGNORE_FLUSH))
|
||||
if (!(flags & MYSQL_OPEN_IGNORE_FLUSH))
|
||||
{
|
||||
/*
|
||||
We already have an MDL lock. But we have encountered an old
|
||||
@@ -3293,7 +3318,6 @@ bool
|
||||
Locked_tables_list::reopen_tables(THD *thd)
|
||||
{
|
||||
Open_table_context ot_ctx_unused(thd, LONG_TIMEOUT);
|
||||
bool lt_refresh_unused;
|
||||
size_t reopen_count= 0;
|
||||
MYSQL_LOCK *lock;
|
||||
MYSQL_LOCK *merged_lock;
|
||||
@@ -3333,7 +3357,7 @@ Locked_tables_list::reopen_tables(THD *thd)
|
||||
break something else.
|
||||
*/
|
||||
lock= mysql_lock_tables(thd, m_reopen_array, reopen_count,
|
||||
MYSQL_OPEN_REOPEN, <_refresh_unused);
|
||||
MYSQL_OPEN_REOPEN);
|
||||
thd->in_lock_tables= 0;
|
||||
if (lock == NULL || (merged_lock=
|
||||
mysql_lock_merge(thd->lock, lock)) == NULL)
|
||||
@@ -5061,7 +5085,6 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type,
|
||||
TABLE *table;
|
||||
Open_table_context ot_ctx(thd, (lock_flags & MYSQL_LOCK_IGNORE_TIMEOUT) ?
|
||||
LONG_TIMEOUT : thd->variables.lock_wait_timeout);
|
||||
bool refresh;
|
||||
bool error;
|
||||
DBUG_ENTER("open_ltable");
|
||||
|
||||
@@ -5073,8 +5096,7 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type,
|
||||
/* open_ltable can be used only for BASIC TABLEs */
|
||||
table_list->required_type= FRMTYPE_TABLE;
|
||||
|
||||
retry:
|
||||
while ((error= open_table(thd, table_list, thd->mem_root, &ot_ctx, 0)) &&
|
||||
while ((error= open_table(thd, table_list, thd->mem_root, &ot_ctx, lock_flags)) &&
|
||||
ot_ctx.can_recover_from_failed_open())
|
||||
{
|
||||
/*
|
||||
@@ -5120,18 +5142,9 @@ retry:
|
||||
DBUG_ASSERT(thd->lock == 0); // You must lock everything at once
|
||||
if ((table->reginfo.lock_type= lock_type) != TL_UNLOCK)
|
||||
if (! (thd->lock= mysql_lock_tables(thd, &table_list->table, 1,
|
||||
lock_flags, &refresh)))
|
||||
lock_flags)))
|
||||
{
|
||||
if (refresh)
|
||||
{
|
||||
close_thread_tables(thd);
|
||||
table_list->table= NULL;
|
||||
table_list->mdl_request.ticket= NULL;
|
||||
thd->mdl_context.rollback_to_savepoint(ot_ctx.start_of_statement_svp());
|
||||
goto retry;
|
||||
}
|
||||
else
|
||||
table= 0;
|
||||
table= 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5168,42 +5181,27 @@ bool open_and_lock_tables(THD *thd, TABLE_LIST *tables,
|
||||
Prelocking_strategy *prelocking_strategy)
|
||||
{
|
||||
uint counter;
|
||||
bool need_reopen;
|
||||
/*
|
||||
Remember the set of metadata locks which this connection
|
||||
managed to acquire before the start of the current statement.
|
||||
It can be either transaction-scope locks, or HANDLER locks,
|
||||
or LOCK TABLES locks. If mysql_lock_tables() fails with
|
||||
need_reopen request, we'll use it to instruct
|
||||
close_tables_for_reopen() to release all locks of this
|
||||
statement.
|
||||
*/
|
||||
MDL_ticket *start_of_statement_svp= thd->mdl_context.mdl_savepoint();
|
||||
DBUG_ENTER("open_and_lock_tables");
|
||||
DBUG_PRINT("enter", ("derived handling: %d", derived));
|
||||
|
||||
for ( ; ; )
|
||||
{
|
||||
if (open_tables(thd, &tables, &counter, flags, prelocking_strategy))
|
||||
DBUG_RETURN(TRUE);
|
||||
DBUG_EXECUTE_IF("sleep_open_and_lock_after_open", {
|
||||
const char *old_proc_info= thd->proc_info;
|
||||
thd->proc_info= "DBUG sleep";
|
||||
my_sleep(6000000);
|
||||
thd->proc_info= old_proc_info;});
|
||||
if (open_tables(thd, &tables, &counter, flags, prelocking_strategy))
|
||||
DBUG_RETURN(TRUE);
|
||||
|
||||
DBUG_EXECUTE_IF("sleep_open_and_lock_after_open", {
|
||||
const char *old_proc_info= thd->proc_info;
|
||||
thd->proc_info= "DBUG sleep";
|
||||
my_sleep(6000000);
|
||||
thd->proc_info= old_proc_info;});
|
||||
|
||||
if (lock_tables(thd, tables, counter, flags))
|
||||
DBUG_RETURN(TRUE);
|
||||
|
||||
if (!lock_tables(thd, tables, counter, flags,
|
||||
&need_reopen))
|
||||
break;
|
||||
if (!need_reopen)
|
||||
DBUG_RETURN(TRUE);
|
||||
close_tables_for_reopen(thd, &tables, start_of_statement_svp);
|
||||
}
|
||||
if (derived &&
|
||||
(mysql_handle_derived(thd->lex, &mysql_derived_prepare) ||
|
||||
(thd->fill_derived_tables() &&
|
||||
mysql_handle_derived(thd->lex, &mysql_derived_filling))))
|
||||
DBUG_RETURN(TRUE); /* purecov: inspected */
|
||||
|
||||
DBUG_RETURN(FALSE);
|
||||
}
|
||||
|
||||
@@ -5216,7 +5214,7 @@ bool open_and_lock_tables(THD *thd, TABLE_LIST *tables,
|
||||
thd - thread handler
|
||||
tables - list of tables for open
|
||||
flags - bitmap of flags to modify how the tables will be open:
|
||||
MYSQL_LOCK_IGNORE_FLUSH - open table even if someone has
|
||||
MYSQL_OPEN_IGNORE_FLUSH - open table even if someone has
|
||||
done a flush or namelock on it.
|
||||
|
||||
RETURN
|
||||
@@ -5261,37 +5259,28 @@ static void mark_real_tables_as_free_for_reuse(TABLE_LIST *table)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Lock all tables in list
|
||||
/**
|
||||
Lock all tables in a list.
|
||||
|
||||
SYNOPSIS
|
||||
lock_tables()
|
||||
thd Thread handler
|
||||
tables Tables to lock
|
||||
count Number of opened tables
|
||||
flags Options (see mysql_lock_tables() for details)
|
||||
need_reopen Out parameter which if TRUE indicates that some
|
||||
tables were dropped or altered during this call
|
||||
and therefore invoker should reopen tables and
|
||||
try to lock them once again (in this case
|
||||
lock_tables() will also return error).
|
||||
@param thd Thread handler
|
||||
@param tables Tables to lock
|
||||
@param count Number of opened tables
|
||||
@param flags Options (see mysql_lock_tables() for details)
|
||||
|
||||
NOTES
|
||||
You can't call lock_tables twice, as this would break the dead-lock-free
|
||||
handling thr_lock gives us. You most always get all needed locks at
|
||||
once.
|
||||
You can't call lock_tables() while holding thr_lock locks, as
|
||||
this would break the dead-lock-free handling thr_lock gives us.
|
||||
You must always get all needed locks at once.
|
||||
|
||||
If query for which we are calling this function marked as requiring
|
||||
prelocking, this function will change locked_tables_mode to
|
||||
LTM_PRELOCKED.
|
||||
If the query for which we are calling this function is marked as
|
||||
requiring prelocking, this function will change
|
||||
locked_tables_mode to LTM_PRELOCKED.
|
||||
|
||||
RETURN VALUES
|
||||
0 ok
|
||||
-1 Error
|
||||
@retval FALSE Success.
|
||||
@retval TRUE A lock wait timeout, deadlock or out of memory.
|
||||
*/
|
||||
|
||||
bool lock_tables(THD *thd, TABLE_LIST *tables, uint count,
|
||||
uint flags, bool *need_reopen)
|
||||
uint flags)
|
||||
{
|
||||
TABLE_LIST *table;
|
||||
|
||||
@@ -5302,7 +5291,6 @@ bool lock_tables(THD *thd, TABLE_LIST *tables, uint count,
|
||||
*/
|
||||
DBUG_ASSERT(thd->locked_tables_mode <= LTM_LOCK_TABLES ||
|
||||
!thd->lex->requires_prelocking());
|
||||
*need_reopen= FALSE;
|
||||
|
||||
if (!tables && !thd->lex->requires_prelocking())
|
||||
DBUG_RETURN(thd->decide_logging_format(tables));
|
||||
@@ -5347,7 +5335,7 @@ bool lock_tables(THD *thd, TABLE_LIST *tables, uint count,
|
||||
DEBUG_SYNC(thd, "before_lock_tables_takes_lock");
|
||||
|
||||
if (! (thd->lock= mysql_lock_tables(thd, start, (uint) (ptr - start),
|
||||
flags, need_reopen)))
|
||||
flags)))
|
||||
DBUG_RETURN(TRUE);
|
||||
|
||||
DEBUG_SYNC(thd, "after_lock_tables_takes_lock");
|
||||
@@ -8869,7 +8857,7 @@ open_system_tables_for_read(THD *thd, TABLE_LIST *table_list,
|
||||
thd->reset_n_backup_open_tables_state(backup);
|
||||
|
||||
if (open_and_lock_tables(thd, table_list, FALSE,
|
||||
MYSQL_LOCK_IGNORE_FLUSH |
|
||||
MYSQL_OPEN_IGNORE_FLUSH |
|
||||
MYSQL_LOCK_IGNORE_TIMEOUT))
|
||||
{
|
||||
lex->restore_backup_query_tables_list(&query_tables_list_backup);
|
||||
@@ -8957,11 +8945,11 @@ open_system_table_for_update(THD *thd, TABLE_LIST *one_table)
|
||||
TABLE *
|
||||
open_log_table(THD *thd, TABLE_LIST *one_table, Open_tables_backup *backup)
|
||||
{
|
||||
uint flags= ( MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK |
|
||||
uint flags= ( MYSQL_OPEN_IGNORE_GLOBAL_READ_LOCK |
|
||||
MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY |
|
||||
MYSQL_LOCK_IGNORE_FLUSH |
|
||||
MYSQL_OPEN_IGNORE_FLUSH |
|
||||
MYSQL_LOCK_IGNORE_TIMEOUT |
|
||||
MYSQL_LOCK_PERF_SCHEMA);
|
||||
MYSQL_LOCK_LOG_TABLE);
|
||||
TABLE *table;
|
||||
/* Save value that is changed in mysql_lock_tables() */
|
||||
ulonglong save_utime_after_lock= thd->utime_after_lock;
|
||||
@@ -8989,8 +8977,7 @@ open_log_table(THD *thd, TABLE_LIST *one_table, Open_tables_backup *backup)
|
||||
open tables cannot be accepted when restoring the open tables
|
||||
state.
|
||||
*/
|
||||
if (thd->killed)
|
||||
close_thread_tables(thd);
|
||||
close_thread_tables(thd);
|
||||
thd->restore_backup_open_tables_state(backup);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user