mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
Backport of:
---------------------------------------------------------- revno: 2617.69.20 committer: Konstantin Osipov <kostja@sun.com> branch nick: 5.4-4284-1-assert timestamp: Thu 2009-08-13 18:29:55 +0400 message: WL#4284 "Transactional DDL locking" A review fix. Since WL#4284 implementation separated MDL_request and MDL_ticket, MDL_request becamse a utility object necessary only to get a ticket. Store it by-value in TABLE_LIST with the intent to merge MDL_request::key with table_list->table_name and table_list->db in future. Change the MDL subsystem to not require MDL_requests to stay around till close_thread_tables(). Remove the list of requests from the MDL context. Requests for shared metadata locks acquired in open_tables() are only used as a list in recover_from_failed_open_table_attempt(), which calls mdl_context.wait_for_locks() for this list. To keep such list for recover_from_failed_open_table_attempt(), introduce a context class (Open_table_context), that collects all requests. A lot of minor cleanups and simplications that became possible with this change.
This commit is contained in:
283
sql/sql_base.cc
283
sql/sql_base.cc
@ -125,7 +125,8 @@ static bool open_new_frm(THD *thd, TABLE_SHARE *share, const char *alias,
|
||||
uint db_stat, uint prgflag,
|
||||
uint ha_open_flags, TABLE *outparam,
|
||||
TABLE_LIST *table_desc, MEM_ROOT *mem_root);
|
||||
static bool tdc_wait_for_old_versions(THD *thd, MDL_context *context);
|
||||
static bool tdc_wait_for_old_versions(THD *thd,
|
||||
MDL_request_list *mdl_requests);
|
||||
static bool
|
||||
has_write_table_with_auto_increment(TABLE_LIST *tables);
|
||||
|
||||
@ -1360,8 +1361,7 @@ close_all_tables_for_name(THD *thd, TABLE_SHARE *share,
|
||||
leave prelocked mode if needed.
|
||||
*/
|
||||
|
||||
void close_thread_tables(THD *thd,
|
||||
bool is_back_off)
|
||||
void close_thread_tables(THD *thd)
|
||||
{
|
||||
TABLE *table;
|
||||
DBUG_ENTER("close_thread_tables");
|
||||
@ -1471,10 +1471,6 @@ void close_thread_tables(THD *thd,
|
||||
|
||||
thd->locked_tables_mode= LTM_NONE;
|
||||
|
||||
/*
|
||||
Note that we are leaving prelocked mode so we don't need
|
||||
to care about THD::locked_tables_root.
|
||||
*/
|
||||
/* Fallthrough */
|
||||
}
|
||||
|
||||
@ -1503,11 +1499,6 @@ void close_thread_tables(THD *thd,
|
||||
if (thd->open_tables)
|
||||
close_open_tables(thd);
|
||||
|
||||
if (!is_back_off)
|
||||
{
|
||||
thd->mdl_context.remove_all_requests();
|
||||
}
|
||||
|
||||
/*
|
||||
Defer the release of metadata locks until the current transaction
|
||||
is either committed or rolled back. This prevents other statements
|
||||
@ -2316,10 +2307,10 @@ void table_share_release_hook(void *share)
|
||||
static bool
|
||||
open_table_get_mdl_lock(THD *thd, TABLE_LIST *table_list,
|
||||
MDL_request *mdl_request,
|
||||
uint flags,
|
||||
enum_open_table_action *action)
|
||||
Open_table_context *ot_ctx,
|
||||
uint flags)
|
||||
{
|
||||
thd->mdl_context.add_request(mdl_request);
|
||||
ot_ctx->add_request(mdl_request);
|
||||
|
||||
if (table_list->lock_strategy)
|
||||
{
|
||||
@ -2333,16 +2324,13 @@ open_table_get_mdl_lock(THD *thd, TABLE_LIST *table_list,
|
||||
enforced by asserts in metadata locking subsystem.
|
||||
*/
|
||||
mdl_request->set_type(MDL_EXCLUSIVE);
|
||||
if (thd->mdl_context.acquire_exclusive_locks())
|
||||
{
|
||||
thd->mdl_context.remove_request(mdl_request);
|
||||
DBUG_ASSERT(! thd->mdl_context.has_locks());
|
||||
|
||||
if (thd->mdl_context.acquire_exclusive_lock(mdl_request))
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bool retry;
|
||||
|
||||
/*
|
||||
There is no MDL_SHARED_UPGRADABLE_HIGH_PRIO type of metadata lock so we
|
||||
want to be sure that caller doesn't pass us both flags simultaneously.
|
||||
@ -2356,12 +2344,11 @@ open_table_get_mdl_lock(THD *thd, TABLE_LIST *table_list,
|
||||
if (flags & MYSQL_LOCK_IGNORE_FLUSH)
|
||||
mdl_request->set_type(MDL_SHARED_HIGH_PRIO);
|
||||
|
||||
if (thd->mdl_context.acquire_shared_lock(mdl_request, &retry))
|
||||
if (thd->mdl_context.try_acquire_shared_lock(mdl_request))
|
||||
return 1;
|
||||
if (mdl_request->ticket == NULL)
|
||||
{
|
||||
if (retry)
|
||||
*action= OT_BACK_OFF_AND_RETRY;
|
||||
else
|
||||
thd->mdl_context.remove_request(mdl_request);
|
||||
(void) ot_ctx->request_backoff_action(Open_table_context::OT_WAIT);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@ -2416,7 +2403,7 @@ open_table_get_mdl_lock(THD *thd, TABLE_LIST *table_list,
|
||||
|
||||
|
||||
bool open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
|
||||
enum_open_table_action *action, uint flags)
|
||||
Open_table_context *ot_ctx, uint flags)
|
||||
{
|
||||
reg1 TABLE *table;
|
||||
char key[MAX_DBKEY_LENGTH];
|
||||
@ -2428,11 +2415,6 @@ bool open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
|
||||
TABLE_SHARE *share;
|
||||
DBUG_ENTER("open_table");
|
||||
|
||||
/* Parsing of partitioning information from .frm needs thd->lex set up. */
|
||||
DBUG_ASSERT(thd->lex->is_lex_started);
|
||||
|
||||
*action= OT_NO_ACTION;
|
||||
|
||||
/* an open table operation needs a lot of the stack space */
|
||||
if (check_stack_overrun(thd, STACK_MIN_SIZE_FOR_OPEN, (uchar *)&alias))
|
||||
DBUG_RETURN(TRUE);
|
||||
@ -2602,12 +2584,15 @@ bool open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
|
||||
This is the normal use case.
|
||||
*/
|
||||
|
||||
mdl_request= table_list->mdl_request;
|
||||
mdl_request= &table_list->mdl_request;
|
||||
if (! (flags & MYSQL_OPEN_HAS_MDL_LOCK))
|
||||
{
|
||||
if (open_table_get_mdl_lock(thd, table_list, mdl_request, flags,
|
||||
action))
|
||||
if (open_table_get_mdl_lock(thd, table_list, mdl_request, ot_ctx, flags))
|
||||
{
|
||||
DEBUG_SYNC(thd, "before_open_table_wait_refresh");
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
DEBUG_SYNC(thd, "after_open_table_mdl_shared");
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2633,8 +2618,8 @@ bool open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
|
||||
! (flags & MYSQL_LOCK_IGNORE_FLUSH))
|
||||
{
|
||||
/* Someone did a refresh while thread was opening tables */
|
||||
*action= OT_BACK_OFF_AND_RETRY;
|
||||
pthread_mutex_unlock(&LOCK_open);
|
||||
(void) ot_ctx->request_backoff_action(Open_table_context::OT_WAIT);
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
|
||||
@ -2766,9 +2751,9 @@ bool open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
|
||||
separately in the caller for old table versions to go away
|
||||
(see tdc_wait_for_old_versions()).
|
||||
*/
|
||||
*action= OT_BACK_OFF_AND_RETRY;
|
||||
release_table_share(share);
|
||||
pthread_mutex_unlock(&LOCK_open);
|
||||
(void) ot_ctx->request_backoff_action(Open_table_context::OT_WAIT);
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
/* Force close at once after usage */
|
||||
@ -2808,12 +2793,12 @@ bool open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
|
||||
if (error == 7)
|
||||
{
|
||||
share->version= 0;
|
||||
*action= OT_DISCOVER;
|
||||
(void) ot_ctx->request_backoff_action(Open_table_context::OT_DISCOVER);
|
||||
}
|
||||
else if (share->crashed)
|
||||
{
|
||||
share->version= 0;
|
||||
*action= OT_REPAIR;
|
||||
(void) ot_ctx->request_backoff_action(Open_table_context::OT_REPAIR);
|
||||
}
|
||||
|
||||
goto err_unlock;
|
||||
@ -2891,10 +2876,8 @@ err_unlock:
|
||||
err_unlock2:
|
||||
pthread_mutex_unlock(&LOCK_open);
|
||||
if (! (flags & MYSQL_OPEN_HAS_MDL_LOCK))
|
||||
{
|
||||
thd->mdl_context.release_lock(mdl_ticket);
|
||||
thd->mdl_context.remove_request(mdl_request);
|
||||
}
|
||||
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
|
||||
@ -3004,6 +2987,9 @@ Locked_tables_list::init_locked_tables(THD *thd)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
memcpy(db, src_table_list->db, db_len + 1);
|
||||
memcpy(table_name, src_table_list->table_name, table_name_len + 1);
|
||||
memcpy(alias, src_table_list->alias, alias_len + 1);
|
||||
/**
|
||||
Sic: remember the *actual* table level lock type taken, to
|
||||
acquire the exact same type in reopen_tables().
|
||||
@ -3014,11 +3000,9 @@ Locked_tables_list::init_locked_tables(THD *thd)
|
||||
dst_table_list->init_one_table(db, db_len, table_name, table_name_len,
|
||||
alias,
|
||||
src_table_list->table->reginfo.lock_type);
|
||||
dst_table_list->mdl_request= src_table_list->mdl_request;
|
||||
dst_table_list->table= table;
|
||||
memcpy(db, src_table_list->db, db_len + 1);
|
||||
memcpy(table_name, src_table_list->table_name, table_name_len + 1);
|
||||
memcpy(alias, src_table_list->alias, alias_len + 1);
|
||||
dst_table_list->mdl_request.ticket= src_table_list->mdl_request.ticket;
|
||||
|
||||
/* Link last into the list of tables */
|
||||
*(dst_table_list->prev_global= m_locked_tables_last)= dst_table_list;
|
||||
m_locked_tables_last= &dst_table_list->next_global;
|
||||
@ -3227,7 +3211,7 @@ unlink_all_closed_tables(THD *thd, MYSQL_LOCK *lock, size_t reopen_count)
|
||||
bool
|
||||
Locked_tables_list::reopen_tables(THD *thd)
|
||||
{
|
||||
enum enum_open_table_action ot_action_unused;
|
||||
Open_table_context ot_ctx_unused(thd);
|
||||
bool lt_refresh_unused;
|
||||
size_t reopen_count= 0;
|
||||
MYSQL_LOCK *lock;
|
||||
@ -3240,7 +3224,7 @@ Locked_tables_list::reopen_tables(THD *thd)
|
||||
continue;
|
||||
|
||||
/* Links into thd->open_tables upon success */
|
||||
if (open_table(thd, table_list, thd->mem_root, &ot_action_unused,
|
||||
if (open_table(thd, table_list, thd->mem_root, &ot_ctx_unused,
|
||||
MYSQL_OPEN_REOPEN))
|
||||
{
|
||||
unlink_all_closed_tables(thd, 0, reopen_count);
|
||||
@ -3591,6 +3575,43 @@ end_with_lock_open:
|
||||
}
|
||||
|
||||
|
||||
/** Open_table_context */
|
||||
|
||||
Open_table_context::Open_table_context(THD *thd)
|
||||
:m_action(OT_NO_ACTION),
|
||||
m_can_deadlock(thd->in_multi_stmt_transaction() &&
|
||||
thd->mdl_context.has_locks())
|
||||
{}
|
||||
|
||||
|
||||
/**
|
||||
Check if we can back-off and set back off action if we can.
|
||||
Otherwise report and return error.
|
||||
|
||||
@retval TRUE if back-off is impossible.
|
||||
@retval FALSE if we can back off. Back off action has been set.
|
||||
*/
|
||||
|
||||
bool
|
||||
Open_table_context::
|
||||
request_backoff_action(enum_open_table_action action_arg)
|
||||
{
|
||||
/*
|
||||
We have met a exclusive metadata lock or a old version of
|
||||
table and we are inside a transaction that already hold locks.
|
||||
We can't follow the locking protocol in this scenario as it
|
||||
might lead to deadlocks.
|
||||
*/
|
||||
if (m_can_deadlock)
|
||||
{
|
||||
my_error(ER_LOCK_DEADLOCK, MYF(0));
|
||||
return TRUE;
|
||||
}
|
||||
m_action= action_arg;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Recover from failed attempt ot open table by performing requested action.
|
||||
|
||||
@ -3604,57 +3625,58 @@ end_with_lock_open:
|
||||
@retval TRUE - Error
|
||||
*/
|
||||
|
||||
static bool
|
||||
recover_from_failed_open_table_attempt(THD *thd, TABLE_LIST *table,
|
||||
enum_open_table_action action)
|
||||
bool
|
||||
Open_table_context::
|
||||
recover_from_failed_open_table_attempt(THD *thd, TABLE_LIST *table)
|
||||
{
|
||||
bool result= FALSE;
|
||||
MDL_request *mdl_request= table->mdl_request;
|
||||
|
||||
switch (action)
|
||||
/* Execute the action. */
|
||||
switch (m_action)
|
||||
{
|
||||
case OT_BACK_OFF_AND_RETRY:
|
||||
result= (thd->mdl_context.wait_for_locks() ||
|
||||
tdc_wait_for_old_versions(thd, &thd->mdl_context));
|
||||
thd->mdl_context.remove_all_requests();
|
||||
case OT_WAIT:
|
||||
result= (thd->mdl_context.wait_for_locks(&m_mdl_requests) ||
|
||||
tdc_wait_for_old_versions(thd, &m_mdl_requests));
|
||||
break;
|
||||
case OT_DISCOVER:
|
||||
mdl_request->set_type(MDL_EXCLUSIVE);
|
||||
thd->mdl_context.add_request(mdl_request);
|
||||
if (thd->mdl_context.acquire_exclusive_locks())
|
||||
{
|
||||
thd->mdl_context.remove_request(mdl_request);
|
||||
return TRUE;
|
||||
}
|
||||
pthread_mutex_lock(&LOCK_open);
|
||||
tdc_remove_table(thd, TDC_RT_REMOVE_ALL, table->db, table->table_name);
|
||||
ha_create_table_from_engine(thd, table->db, table->table_name);
|
||||
pthread_mutex_unlock(&LOCK_open);
|
||||
MDL_request mdl_xlock_request(&table->mdl_request);
|
||||
mdl_xlock_request.set_type(MDL_EXCLUSIVE);
|
||||
if ((result=
|
||||
thd->mdl_context.acquire_exclusive_lock(&mdl_xlock_request)))
|
||||
break;
|
||||
pthread_mutex_lock(&LOCK_open);
|
||||
tdc_remove_table(thd, TDC_RT_REMOVE_ALL, table->db, table->table_name);
|
||||
ha_create_table_from_engine(thd, table->db, table->table_name);
|
||||
pthread_mutex_unlock(&LOCK_open);
|
||||
|
||||
thd->warning_info->clear_warning_info(thd->query_id);
|
||||
thd->clear_error(); // Clear error message
|
||||
thd->mdl_context.release_lock(mdl_request->ticket);
|
||||
thd->mdl_context.remove_request(mdl_request);
|
||||
break;
|
||||
thd->warning_info->clear_warning_info(thd->query_id);
|
||||
thd->clear_error(); // Clear error message
|
||||
thd->mdl_context.release_lock(mdl_xlock_request.ticket);
|
||||
break;
|
||||
}
|
||||
case OT_REPAIR:
|
||||
mdl_request->set_type(MDL_EXCLUSIVE);
|
||||
thd->mdl_context.add_request(mdl_request);
|
||||
if (thd->mdl_context.acquire_exclusive_locks())
|
||||
{
|
||||
thd->mdl_context.remove_request(mdl_request);
|
||||
return TRUE;
|
||||
}
|
||||
pthread_mutex_lock(&LOCK_open);
|
||||
tdc_remove_table(thd, TDC_RT_REMOVE_ALL, table->db, table->table_name);
|
||||
pthread_mutex_unlock(&LOCK_open);
|
||||
MDL_request mdl_xlock_request(&table->mdl_request);
|
||||
mdl_xlock_request.set_type(MDL_EXCLUSIVE);
|
||||
if ((result=
|
||||
thd->mdl_context.acquire_exclusive_lock(&mdl_xlock_request)))
|
||||
break;
|
||||
|
||||
result= auto_repair_table(thd, table);
|
||||
thd->mdl_context.release_lock(mdl_request->ticket);
|
||||
thd->mdl_context.remove_request(mdl_request);
|
||||
break;
|
||||
pthread_mutex_lock(&LOCK_open);
|
||||
tdc_remove_table(thd, TDC_RT_REMOVE_ALL, table->db, table->table_name);
|
||||
pthread_mutex_unlock(&LOCK_open);
|
||||
|
||||
result= auto_repair_table(thd, table);
|
||||
thd->mdl_context.release_lock(mdl_xlock_request.ticket);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
DBUG_ASSERT(0);
|
||||
}
|
||||
/* Remove all old requests, they will be re-added. */
|
||||
m_mdl_requests.empty();
|
||||
/* Prepare for possible another back-off. */
|
||||
m_action= OT_NO_ACTION;
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -3722,14 +3744,13 @@ thr_lock_type read_lock_type_for_table(THD *thd, TABLE *table)
|
||||
int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags)
|
||||
{
|
||||
TABLE_LIST *tables= NULL;
|
||||
enum_open_table_action action;
|
||||
Open_table_context ot_ctx(thd);
|
||||
int result=0;
|
||||
bool error;
|
||||
MEM_ROOT new_frm_mem;
|
||||
/* Also used for indicating that prelocking is need */
|
||||
TABLE_LIST **query_tables_last_own;
|
||||
bool safe_to_ignore_table;
|
||||
bool has_locks= thd->mdl_context.has_locks();
|
||||
DBUG_ENTER("open_tables");
|
||||
/*
|
||||
temporary mem_root for new .frm parsing.
|
||||
@ -3856,31 +3877,19 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags)
|
||||
*/
|
||||
Prelock_error_handler prelock_handler;
|
||||
thd->push_internal_handler(& prelock_handler);
|
||||
error= open_table(thd, tables, &new_frm_mem, &action, flags);
|
||||
error= open_table(thd, tables, &new_frm_mem, &ot_ctx, flags);
|
||||
thd->pop_internal_handler();
|
||||
safe_to_ignore_table= prelock_handler.safely_trapped_errors();
|
||||
}
|
||||
else
|
||||
error= open_table(thd, tables, &new_frm_mem, &action, flags);
|
||||
error= open_table(thd, tables, &new_frm_mem, &ot_ctx, flags);
|
||||
|
||||
free_root(&new_frm_mem, MYF(MY_KEEP_PREALLOC));
|
||||
|
||||
if (error)
|
||||
{
|
||||
if (action)
|
||||
if (ot_ctx.can_recover_from_failed_open_table())
|
||||
{
|
||||
/*
|
||||
We have met a exclusive metadata lock or a old version of table and
|
||||
we are inside a transaction that already hold locks. We can't follow
|
||||
the locking protocol in this scenario as it might lead to deadlocks.
|
||||
*/
|
||||
if (thd->in_multi_stmt_transaction() && has_locks)
|
||||
{
|
||||
my_error(ER_LOCK_DEADLOCK, MYF(0));
|
||||
result= -1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/*
|
||||
We have met exclusive metadata lock or old version of table. Now we
|
||||
have to close all tables which are not up to date/release metadata
|
||||
@ -3897,13 +3906,13 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags)
|
||||
*/
|
||||
if (query_tables_last_own)
|
||||
thd->lex->mark_as_requiring_prelocking(query_tables_last_own);
|
||||
close_tables_for_reopen(thd, start, (action == OT_BACK_OFF_AND_RETRY));
|
||||
close_tables_for_reopen(thd, start);
|
||||
/*
|
||||
Here we rely on the fact that 'tables' still points to the valid
|
||||
TABLE_LIST element. Altough currently this assumption is valid
|
||||
it may change in future.
|
||||
*/
|
||||
if (recover_from_failed_open_table_attempt(thd, tables, action))
|
||||
if (ot_ctx.recover_from_failed_open_table_attempt(thd, tables))
|
||||
{
|
||||
result= -1;
|
||||
goto err;
|
||||
@ -4210,7 +4219,7 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type,
|
||||
uint lock_flags)
|
||||
{
|
||||
TABLE *table;
|
||||
enum_open_table_action action;
|
||||
Open_table_context ot_ctx(thd);
|
||||
bool refresh;
|
||||
bool error;
|
||||
DBUG_ENTER("open_ltable");
|
||||
@ -4224,16 +4233,18 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type,
|
||||
table_list->required_type= FRMTYPE_TABLE;
|
||||
|
||||
retry:
|
||||
while ((error= open_table(thd, table_list, thd->mem_root, &action, 0)) &&
|
||||
action)
|
||||
while ((error= open_table(thd, table_list, thd->mem_root, &ot_ctx, 0)) &&
|
||||
ot_ctx.can_recover_from_failed_open_table())
|
||||
{
|
||||
/*
|
||||
Even altough we have failed to open table we still need to
|
||||
call close_thread_tables() to release metadata locks which
|
||||
Even though we have failed to open table we still need to
|
||||
call release_all_locks() to release metadata locks which
|
||||
might have been acquired successfully.
|
||||
*/
|
||||
close_thread_tables(thd, (action == OT_BACK_OFF_AND_RETRY));
|
||||
if (recover_from_failed_open_table_attempt(thd, table_list, action))
|
||||
if (! thd->locked_tables_mode)
|
||||
thd->mdl_context.release_all_locks();
|
||||
table_list->mdl_request.ticket= 0;
|
||||
if (ot_ctx.recover_from_failed_open_table_attempt(thd, table_list))
|
||||
break;
|
||||
}
|
||||
|
||||
@ -4272,8 +4283,20 @@ retry:
|
||||
{
|
||||
if (refresh)
|
||||
{
|
||||
close_thread_tables(thd);
|
||||
goto retry;
|
||||
if (ot_ctx.can_deadlock())
|
||||
{
|
||||
my_error(ER_LOCK_DEADLOCK, MYF(0));
|
||||
table= 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
close_thread_tables(thd);
|
||||
table_list->table= NULL;
|
||||
table_list->mdl_request.ticket= NULL;
|
||||
if (! thd->locked_tables_mode)
|
||||
thd->mdl_context.release_all_locks();
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
else
|
||||
table= 0;
|
||||
@ -4283,7 +4306,7 @@ retry:
|
||||
else
|
||||
table= 0;
|
||||
|
||||
end:
|
||||
end:
|
||||
thd_proc_info(thd, 0);
|
||||
DBUG_RETURN(table);
|
||||
}
|
||||
@ -4320,6 +4343,7 @@ int open_and_lock_tables_derived(THD *thd, TABLE_LIST *tables, bool derived,
|
||||
{
|
||||
uint counter;
|
||||
bool need_reopen;
|
||||
bool has_locks= thd->mdl_context.has_locks();
|
||||
DBUG_ENTER("open_and_lock_tables_derived");
|
||||
DBUG_PRINT("enter", ("derived handling: %d", derived));
|
||||
|
||||
@ -4339,7 +4363,12 @@ int open_and_lock_tables_derived(THD *thd, TABLE_LIST *tables, bool derived,
|
||||
break;
|
||||
if (!need_reopen)
|
||||
DBUG_RETURN(-1);
|
||||
close_tables_for_reopen(thd, &tables, FALSE);
|
||||
if (thd->in_multi_stmt_transaction() && has_locks)
|
||||
{
|
||||
my_error(ER_LOCK_DEADLOCK, MYF(0));
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
close_tables_for_reopen(thd, &tables);
|
||||
}
|
||||
if (derived &&
|
||||
(mysql_handle_derived(thd->lex, &mysql_derived_prepare) ||
|
||||
@ -4677,10 +4706,6 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count,
|
||||
table->table->query_id= thd->query_id;
|
||||
if (check_lock_and_start_stmt(thd, table->table, table->lock_type))
|
||||
{
|
||||
/*
|
||||
This was an attempt to enter prelocked mode so there is no
|
||||
need to care about THD::locked_tables_root here.
|
||||
*/
|
||||
mysql_unlock_tables(thd, thd->lock);
|
||||
thd->lock= 0;
|
||||
DBUG_RETURN(-1);
|
||||
@ -4767,7 +4792,7 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count,
|
||||
|
||||
*/
|
||||
|
||||
void close_tables_for_reopen(THD *thd, TABLE_LIST **tables, bool is_back_off)
|
||||
void close_tables_for_reopen(THD *thd, TABLE_LIST **tables)
|
||||
{
|
||||
/*
|
||||
If table list consists only from tables from prelocking set, table list
|
||||
@ -4778,8 +4803,11 @@ void close_tables_for_reopen(THD *thd, TABLE_LIST **tables, bool is_back_off)
|
||||
thd->lex->chop_off_not_own_tables();
|
||||
sp_remove_not_own_routines(thd->lex);
|
||||
for (TABLE_LIST *tmp= *tables; tmp; tmp= tmp->next_global)
|
||||
{
|
||||
tmp->table= 0;
|
||||
close_thread_tables(thd, is_back_off);
|
||||
tmp->mdl_request.ticket= NULL;
|
||||
}
|
||||
close_thread_tables(thd);
|
||||
if (!thd->locked_tables_mode)
|
||||
thd->mdl_context.release_all_locks();
|
||||
}
|
||||
@ -7855,7 +7883,8 @@ void tdc_remove_table(THD *thd, enum_tdc_remove_table_type remove_type,
|
||||
@param context Metadata locking context with locks.
|
||||
*/
|
||||
|
||||
static bool tdc_wait_for_old_versions(THD *thd, MDL_context *mdl_context)
|
||||
static bool
|
||||
tdc_wait_for_old_versions(THD *thd, MDL_request_list *mdl_requests)
|
||||
{
|
||||
TABLE_SHARE *share;
|
||||
const char *old_msg;
|
||||
@ -7872,7 +7901,7 @@ static bool tdc_wait_for_old_versions(THD *thd, MDL_context *mdl_context)
|
||||
mysql_ha_flush(thd);
|
||||
pthread_mutex_lock(&LOCK_open);
|
||||
|
||||
MDL_context::Request_iterator it= mdl_context->get_requests();
|
||||
MDL_request_list::Iterator it(*mdl_requests);
|
||||
while ((mdl_request= it++))
|
||||
{
|
||||
if ((share= get_cached_table_share(mdl_request->key.db_name(),
|
||||
@ -8095,8 +8124,6 @@ open_system_tables_for_read(THD *thd, TABLE_LIST *table_list,
|
||||
|
||||
DBUG_ENTER("open_system_tables_for_read");
|
||||
|
||||
alloc_mdl_requests(table_list, thd->mem_root);
|
||||
|
||||
/*
|
||||
Besides using new Open_tables_state for opening system tables,
|
||||
we also have to backup and reset/and then restore part of LEX
|
||||
@ -8170,8 +8197,6 @@ open_system_table_for_update(THD *thd, TABLE_LIST *one_table)
|
||||
{
|
||||
DBUG_ENTER("open_system_table_for_update");
|
||||
|
||||
alloc_mdl_requests(one_table, thd->mem_root);
|
||||
|
||||
TABLE *table= open_ltable(thd, one_table, one_table->lock_type, 0);
|
||||
if (table)
|
||||
{
|
||||
@ -8208,7 +8233,6 @@ open_performance_schema_table(THD *thd, TABLE_LIST *one_table,
|
||||
|
||||
thd->reset_n_backup_open_tables_state(backup);
|
||||
|
||||
alloc_mdl_requests(one_table, thd->mem_root);
|
||||
if ((table= open_ltable(thd, one_table, one_table->lock_type, flags)))
|
||||
{
|
||||
DBUG_ASSERT(table->s->table_category == TABLE_CATEGORY_PERFORMANCE);
|
||||
@ -8286,7 +8310,6 @@ void close_performance_schema_table(THD *thd, Open_tables_state *backup)
|
||||
pthread_mutex_unlock(&LOCK_open);
|
||||
|
||||
thd->mdl_context.release_all_locks();
|
||||
thd->mdl_context.remove_all_requests();
|
||||
|
||||
thd->restore_backup_open_tables_state(backup);
|
||||
}
|
||||
|
Reference in New Issue
Block a user