summaryrefslogtreecommitdiff
path: root/sql/sql_base.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_base.cc')
-rw-r--r--sql/sql_base.cc200
1 files changed, 126 insertions, 74 deletions
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 8d3ef372842..2f891375163 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -1519,25 +1519,23 @@ void close_thread_tables(THD *thd)
if (thd->open_tables)
close_open_tables(thd);
- if (thd->state_flags & Open_tables_state::BACKUPS_AVAIL)
- {
- /* We can't have an open HANDLER in the backup open tables state. */
- DBUG_ASSERT(thd->mdl_context.lt_or_ha_sentinel() == NULL);
- /*
- Due to the above assert, this is guaranteed to release *all* locks
- in the context.
- */
- thd->mdl_context.release_transactional_locks();
- }
- else if (! thd->in_multi_stmt_transaction())
+ /*
+ - If inside a multi-statement transaction,
+ defer the release of metadata locks until the current
+ transaction is either committed or rolled back. This prevents
+ other statements from modifying the table for the entire
+ duration of this transaction. This provides commit ordering
+ and guarantees serializability across multiple transactions.
+ - If closing a system table, defer the release of metadata locks
+ to the caller. We have no sentinel in MDL subsystem to guard
+ transactional locks from system tables locks, so don't know
+ which locks are which here.
+ - If in autocommit mode, or outside a transactional context,
+ automatically release metadata locks of the current statement.
+ */
+ if (! thd->in_multi_stmt_transaction() &&
+ ! (thd->state_flags & Open_tables_state::BACKUPS_AVAIL))
{
- /*
- Defer the release of metadata locks until the current transaction
- is either committed or rolled back. This prevents other statements
- from modifying the table for the entire duration of this transaction.
- This provides commitment ordering for guaranteeing serializability
- across multiple transactions.
- */
thd->mdl_context.release_transactional_locks();
}
@@ -2336,10 +2334,9 @@ open_table_get_mdl_lock(THD *thd, TABLE_LIST *table_list,
Open_table_context *ot_ctx,
uint flags)
{
- ot_ctx->add_request(mdl_request);
-
if (table_list->lock_strategy)
{
+ MDL_request *global_request;
/*
In case of CREATE TABLE .. If NOT EXISTS .. SELECT, the table
may not yet exist. Let's acquire an exclusive lock for that
@@ -2349,10 +2346,24 @@ open_table_get_mdl_lock(THD *thd, TABLE_LIST *table_list,
shared locks. This invariant is preserved here and is also
enforced by asserts in metadata locking subsystem.
*/
+
mdl_request->set_type(MDL_EXCLUSIVE);
DBUG_ASSERT(! thd->mdl_context.has_locks() ||
- thd->handler_tables_hash.records);
+ thd->handler_tables_hash.records ||
+ thd->global_read_lock);
+
+ if (!(global_request= ot_ctx->get_global_mdl_request(thd)))
+ return 1;
+ if (! global_request->ticket)
+ {
+ ot_ctx->add_request(global_request);
+ if (thd->mdl_context.acquire_global_intention_exclusive_lock(
+ global_request))
+ return 1;
+ }
+
+ ot_ctx->add_request(mdl_request);
if (thd->mdl_context.acquire_exclusive_lock(mdl_request))
return 1;
}
@@ -2371,8 +2382,29 @@ 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 (mdl_request->type == MDL_SHARED_UPGRADABLE)
+ {
+ MDL_request *global_request;
+
+ if (!(global_request= ot_ctx->get_global_mdl_request(thd)))
+ return 1;
+ if (! global_request->ticket)
+ {
+ ot_ctx->add_request(global_request);
+ if (thd->mdl_context.try_acquire_global_intention_exclusive_lock(
+ global_request))
+ return 1;
+ if (! global_request->ticket)
+ goto failure;
+ }
+ }
+
+ ot_ctx->add_request(mdl_request);
+
if (thd->mdl_context.try_acquire_shared_lock(mdl_request))
return 1;
+
+failure:
if (mdl_request->ticket == NULL)
{
if (flags & MYSQL_OPEN_FAIL_ON_MDL_CONFLICT)
@@ -2919,8 +2951,6 @@ err_unlock:
release_table_share(share);
err_unlock2:
pthread_mutex_unlock(&LOCK_open);
- if (! (flags & MYSQL_OPEN_HAS_MDL_LOCK))
- thd->mdl_context.release_lock(mdl_ticket);
DBUG_RETURN(TRUE);
}
@@ -3713,11 +3743,34 @@ Open_table_context::Open_table_context(THD *thd)
m_start_of_statement_svp(thd->mdl_context.mdl_savepoint()),
m_has_locks((thd->in_multi_stmt_transaction() ||
thd->mdl_context.lt_or_ha_sentinel()) &&
- thd->mdl_context.has_locks())
+ thd->mdl_context.has_locks()),
+ m_global_mdl_request(NULL)
{}
/**
+ Get MDL_request object for global intention exclusive lock which
+ is acquired during opening tables for statements which take
+ upgradable shared metadata locks.
+*/
+
+MDL_request *Open_table_context::get_global_mdl_request(THD *thd)
+{
+ if (! m_global_mdl_request)
+ {
+ char *buff;
+ if ((buff= (char*)thd->alloc(sizeof(MDL_request))))
+ {
+ m_global_mdl_request= new (buff) MDL_request();
+ m_global_mdl_request->init(MDL_key::GLOBAL, "", "",
+ MDL_INTENTION_EXCLUSIVE);
+ }
+ }
+ return m_global_mdl_request;
+}
+
+
+/**
Check if we can back-off and set back off action if we can.
Otherwise report and return error.
@@ -3777,6 +3830,11 @@ recover_from_failed_open(THD *thd, MDL_request *mdl_request,
TABLE_LIST *table)
{
bool result= FALSE;
+ /*
+ Remove reference to released ticket from MDL_request.
+ */
+ if (m_global_mdl_request)
+ m_global_mdl_request->ticket= NULL;
/* Execute the action. */
switch (m_action)
{
@@ -3787,11 +3845,26 @@ recover_from_failed_open(THD *thd, MDL_request *mdl_request,
break;
case OT_DISCOVER:
{
+ MDL_request mdl_global_request;
MDL_request mdl_xlock_request(mdl_request);
+
+ mdl_global_request.init(MDL_key::GLOBAL, "", "",
+ MDL_INTENTION_EXCLUSIVE);
mdl_xlock_request.set_type(MDL_EXCLUSIVE);
+
+
+ if ((result= thd->mdl_context.acquire_global_intention_exclusive_lock(
+ &mdl_global_request)))
+ break;
+
if ((result=
thd->mdl_context.acquire_exclusive_lock(&mdl_xlock_request)))
+ {
+ /*
+ We rely on close_thread_tables() to release global lock eventually.
+ */
break;
+ }
DBUG_ASSERT(mdl_request->key.mdl_namespace() == MDL_key::TABLE);
pthread_mutex_lock(&LOCK_open);
@@ -3805,16 +3878,30 @@ recover_from_failed_open(THD *thd, MDL_request *mdl_request,
thd->warning_info->clear_warning_info(thd->query_id);
thd->clear_error(); // Clear error message
- thd->mdl_context.release_lock(mdl_xlock_request.ticket);
+ thd->mdl_context.release_transactional_locks();
break;
}
case OT_REPAIR:
{
+ MDL_request mdl_global_request;
MDL_request mdl_xlock_request(mdl_request);
+
+ mdl_global_request.init(MDL_key::GLOBAL, "", "",
+ MDL_INTENTION_EXCLUSIVE);
mdl_xlock_request.set_type(MDL_EXCLUSIVE);
+
+ if ((result= thd->mdl_context.acquire_global_intention_exclusive_lock(
+ &mdl_global_request)))
+ break;
+
if ((result=
thd->mdl_context.acquire_exclusive_lock(&mdl_xlock_request)))
+ {
+ /*
+ We rely on close_thread_tables() to release global lock eventually.
+ */
break;
+ }
DBUG_ASSERT(mdl_request->key.mdl_namespace() == MDL_key::TABLE);
pthread_mutex_lock(&LOCK_open);
@@ -3824,7 +3911,7 @@ recover_from_failed_open(THD *thd, MDL_request *mdl_request,
pthread_mutex_unlock(&LOCK_open);
result= auto_repair_table(thd, table);
- thd->mdl_context.release_lock(mdl_xlock_request.ticket);
+ thd->mdl_context.release_transactional_locks();
break;
}
default:
@@ -3921,6 +4008,13 @@ open_and_process_routine(THD *thd, Query_tables_list *prelocking_ctx,
mdl_type != MDL_key::PROCEDURE)
{
ot_ctx->add_request(&rt->mdl_request);
+
+ /*
+ Since we acquire only shared lock on routines we don't
+ need to care about global intention exclusive locks.
+ */
+ DBUG_ASSERT(rt->mdl_request.type == MDL_SHARED);
+
if (thd->mdl_context.try_acquire_shared_lock(&rt->mdl_request))
DBUG_RETURN(TRUE);
@@ -8784,7 +8878,7 @@ has_write_table_with_auto_increment(TABLE_LIST *tables)
bool
open_system_tables_for_read(THD *thd, TABLE_LIST *table_list,
- Open_tables_state *backup)
+ Open_tables_backup *backup)
{
Query_tables_list query_tables_list_backup;
LEX *lex= thd->lex;
@@ -8830,13 +8924,13 @@ error:
SYNOPSIS
close_system_tables()
thd Thread context
- backup Pointer to Open_tables_state instance which holds
+ backup Pointer to Open_tables_backup instance which holds
information about tables which were open before we
decided to access system tables.
*/
void
-close_system_tables(THD *thd, Open_tables_state *backup)
+close_system_tables(THD *thd, Open_tables_backup *backup)
{
close_thread_tables(thd);
thd->restore_backup_open_tables_state(backup);
@@ -8887,7 +8981,7 @@ open_system_table_for_update(THD *thd, TABLE_LIST *one_table)
*/
TABLE *
open_performance_schema_table(THD *thd, TABLE_LIST *one_table,
- Open_tables_state *backup)
+ Open_tables_backup *backup)
{
uint flags= ( MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK |
MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY |
@@ -8936,51 +9030,9 @@ open_performance_schema_table(THD *thd, TABLE_LIST *one_table,
@param thd The current thread
@param backup [in] the context to restore.
*/
-void close_performance_schema_table(THD *thd, Open_tables_state *backup)
+void close_performance_schema_table(THD *thd, Open_tables_backup *backup)
{
- bool found_old_table;
-
- /*
- If open_performance_schema_table() fails,
- this function should not be called.
- */
- DBUG_ASSERT(thd->lock != NULL);
-
- /*
- Note:
- We do not create explicitly a separate transaction for the
- performance table I/O, but borrow the current transaction.
- lock + unlock will autocommit the change done in the
- performance schema table: this is the expected result.
- The current transaction should not be affected by this code.
- TODO: Note that if a transactional engine is used for log tables,
- this code will need to be revised, as a separate transaction
- might be needed.
- */
- mysql_unlock_tables(thd, thd->lock);
- thd->lock= 0;
-
- pthread_mutex_lock(&LOCK_open);
-
- found_old_table= false;
- /*
- Note that we need to hold LOCK_open while changing the
- open_tables list. Another thread may work on it.
- (See: notify_thread_having_shared_lock())
- */
- while (thd->open_tables)
- found_old_table|= close_thread_table(thd, &thd->open_tables);
-
- if (found_old_table)
- broadcast_refresh();
-
- pthread_mutex_unlock(&LOCK_open);
-
- /* We can't have an open HANDLER in the backup context. */
- DBUG_ASSERT(thd->mdl_context.lt_or_ha_sentinel() == NULL);
- thd->mdl_context.release_transactional_locks();
-
- thd->restore_backup_open_tables_state(backup);
+ close_system_tables(thd, backup);
}
/**