3187 Dmitry Lenev 2010-11-03
More changes to draft patch refactoring global read
lock implementation. Makes GRL yet another type of
metadata lock and thus exposes it to deadlock detector
in MDL subsystem.
Solves bugs #54673 "It takes too long to get readlock for
'FLUSH TABLES WITH READ LOCK'" and #57006 "Deadlock between
HANDLER and FLUSH TABLES WITH READ LOCK".
Work-in-progress. Introduce concept of duration in MDL
subsystem. Replace notion of transactional sentinel
with locks with explicit duration.
modified:
sql/event_db_repository.cc
sql/handler.cc
sql/lock.cc
sql/log_event.cc
sql/mdl.cc
sql/mdl.h
sql/rpl_rli.cc
sql/sp.cc
sql/sp_head.cc
sql/sql_admin.cc
sql/sql_base.cc
sql/sql_base.h
sql/sql_class.cc
sql/sql_class.h
sql/sql_db.cc
sql/sql_handler.cc
sql/sql_handler.h
sql/sql_insert.cc
sql/sql_parse.cc
sql/sql_prepare.cc
sql/sql_show.cc
sql/sql_table.cc
sql/table.cc
sql/table.h
sql/transaction.cc
3186 Konstantin Osipov 2010-10-28
Review comments.
modified:
sql/event_db_repository.cc
sql/handler.cc
sql/sp_head.cc
sql/transaction.cc
=== modified file 'sql/event_db_repository.cc'
--- a/sql/event_db_repository.cc 2010-10-28 19:35:28 +0000
+++ b/sql/event_db_repository.cc 2010-11-03 14:30:33 +0000
@@ -627,7 +627,7 @@ Event_db_repository::create_event(THD *t
table at the end but keep the global read lock and
possible other locks taken by the caller.
*/
- MDL_ticket *mdl_savepoint= thd->mdl_context.mdl_savepoint();
+ MDL_savepoint mdl_savepoint= thd->mdl_context.mdl_savepoint();
DBUG_ENTER("Event_db_repository::create_event");
@@ -745,7 +745,7 @@ Event_db_repository::update_event(THD *t
table at the end but keep the global read lock and
possible other locks taken by the caller.
*/
- MDL_ticket *mdl_savepoint= thd->mdl_context.mdl_savepoint();
+ MDL_savepoint mdl_savepoint= thd->mdl_context.mdl_savepoint();
int ret= 1;
DBUG_ENTER("Event_db_repository::update_event");
@@ -855,7 +855,7 @@ Event_db_repository::drop_event(THD *thd
table at the end but keep the global read lock and
possible other locks taken by the caller.
*/
- MDL_ticket *mdl_savepoint= thd->mdl_context.mdl_savepoint();
+ MDL_savepoint mdl_savepoint= thd->mdl_context.mdl_savepoint();
int ret= 1;
DBUG_ENTER("Event_db_repository::drop_event");
@@ -958,7 +958,7 @@ Event_db_repository::drop_schema_events(
TABLE *table= NULL;
READ_RECORD read_record_info;
enum enum_events_table_field field= ET_FIELD_DB;
- MDL_ticket *mdl_savepoint= thd->mdl_context.mdl_savepoint();
+ MDL_savepoint mdl_savepoint= thd->mdl_context.mdl_savepoint();
DBUG_ENTER("Event_db_repository::drop_schema_events");
DBUG_PRINT("enter", ("field=%d schema=%s", field, schema.str));
=== modified file 'sql/handler.cc'
--- a/sql/handler.cc 2010-10-28 19:35:28 +0000
+++ b/sql/handler.cc 2010-11-03 14:30:33 +0000
@@ -1176,7 +1176,8 @@ int ha_commit_trans(THD *thd, bool all)
We allow the owner of FTWRL to COMMIT; we assume that it knows
what it does.
*/
- mdl_request.init(MDL_key::COMMIT, "", "", MDL_INTENTION_EXCLUSIVE);
+ mdl_request.init(MDL_key::COMMIT, "", "", MDL_INTENTION_EXCLUSIVE,
+ MDL_EXPLICIT);
if (thd->mdl_context.acquire_lock(&mdl_request,
thd->variables.lock_wait_timeout))
=== modified file 'sql/lock.cc'
--- a/sql/lock.cc 2010-10-26 04:25:15 +0000
+++ b/sql/lock.cc 2010-11-03 14:30:33 +0000
@@ -790,7 +790,7 @@ bool lock_schema_name(THD *thd, const ch
thd->global_read_lock.init_protection_request(&global_request);
- mdl_request.init(MDL_key::SCHEMA, db, "", MDL_EXCLUSIVE);
+ mdl_request.init(MDL_key::SCHEMA, db, "", MDL_EXCLUSIVE, MDL_TRANSACTION);
mdl_requests.push_front(&mdl_request);
mdl_requests.push_front(&global_request);
@@ -857,8 +857,9 @@ bool lock_object_name(THD *thd, MDL_key:
DBUG_ASSERT(stmt_causes_implicit_commit(thd, CF_IMPLICIT_COMMIT_END));
thd->global_read_lock.init_protection_request(&global_request);
- schema_request.init(MDL_key::SCHEMA, db, "", MDL_INTENTION_EXCLUSIVE);
- mdl_request.init(mdl_type, db, name, MDL_EXCLUSIVE);
+ schema_request.init(MDL_key::SCHEMA, db, "", MDL_INTENTION_EXCLUSIVE,
+ MDL_TRANSACTION);
+ mdl_request.init(mdl_type, db, name, MDL_EXCLUSIVE, MDL_TRANSACTION);
mdl_requests.push_front(&mdl_request);
mdl_requests.push_front(&schema_request);
@@ -982,13 +983,12 @@ bool Global_read_lock::lock_global_read_
DBUG_ASSERT(! thd->mdl_context.is_lock_owner(MDL_key::GLOBAL, "", "",
MDL_SHARED));
- mdl_request.init(MDL_key::GLOBAL, "", "", MDL_SHARED);
+ mdl_request.init(MDL_key::GLOBAL, "", "", MDL_SHARED, MDL_EXPLICIT);
if (thd->mdl_context.acquire_lock(&mdl_request,
thd->variables.lock_wait_timeout))
DBUG_RETURN(1);
- thd->mdl_context.move_ticket_after_trans_sentinel(mdl_request.ticket);
m_mdl_global_shared_lock= mdl_request.ticket;
m_state= GRL_ACQUIRED;
}
@@ -1060,33 +1060,8 @@ bool Global_read_lock::can_acquire_prote
void Global_read_lock::init_protection_request(MDL_request *request)
{
- request->init(MDL_key::GLOBAL, "", "", MDL_INTENTION_EXCLUSIVE);
-}
-
-
-/**
- Release protection against global read lock if it is set.
-
- See also "Handling of global read locks" above.
-
- @param thd Reference to thread.
-*/
-
-void Global_read_lock::release_protection_if_set(THD *thd)
-{
- MDL_request mdl_request;
- MDL_ticket *ticket;
-
- DBUG_ENTER("release_protection_if_set");
-
- mdl_request.init(MDL_key::GLOBAL, "", "", MDL_INTENTION_EXCLUSIVE);
-
- if ((ticket= thd->mdl_context.find_ticket_at_front(&mdl_request)))
- {
- thd->mdl_context.release_lock(ticket);
- }
-
- DBUG_VOID_RETURN;
+ request->init(MDL_key::GLOBAL, "", "", MDL_INTENTION_EXCLUSIVE,
+ MDL_STATEMENT);
}
@@ -1116,13 +1091,12 @@ bool Global_read_lock::make_global_read_
if (m_state != GRL_ACQUIRED)
DBUG_RETURN(0);
- mdl_request.init(MDL_key::COMMIT, "", "", MDL_SHARED);
+ mdl_request.init(MDL_key::COMMIT, "", "", MDL_SHARED, MDL_EXPLICIT);
if (thd->mdl_context.acquire_lock(&mdl_request,
thd->variables.lock_wait_timeout))
DBUG_RETURN(TRUE);
- thd->mdl_context.move_ticket_after_trans_sentinel(mdl_request.ticket);
m_mdl_blocks_commits_lock= mdl_request.ticket;
m_state= GRL_ACQUIRED_AND_BLOCKS_COMMIT;
@@ -1131,18 +1105,17 @@ bool Global_read_lock::make_global_read_
/**
- Move tickets for metadata locks which are used to implement GRL after
- transactional sentinel.
+ Set explicit duration for metadata locks which are used to implement GRL.
@param thd Reference to thread.
*/
-void Global_read_lock::move_tickets_after_trans_sentinel(THD *thd)
+void Global_read_lock::set_explicit_lock_duration(THD *thd)
{
if (m_mdl_global_shared_lock)
- thd->mdl_context.move_ticket_after_trans_sentinel(m_mdl_global_shared_lock);
+ thd->mdl_context.set_lock_duration(m_mdl_global_shared_lock, MDL_EXPLICIT);
if (m_mdl_blocks_commits_lock)
- thd->mdl_context.move_ticket_after_trans_sentinel(m_mdl_blocks_commits_lock);
+ thd->mdl_context.set_lock_duration(m_mdl_blocks_commits_lock, MDL_EXPLICIT);
}
/**
=== modified file 'sql/log_event.cc'
--- a/sql/log_event.cc 2010-10-18 12:33:49 +0000
+++ b/sql/log_event.cc 2010-11-03 14:30:33 +0000
@@ -4960,7 +4960,7 @@ error:
if (! thd->in_multi_stmt_transaction_mode())
thd->mdl_context.release_transactional_locks();
else
- thd->global_read_lock.release_protection_if_set(thd);
+ thd->mdl_context.release_statement_locks();
DBUG_EXECUTE_IF("LOAD_DATA_INFILE_has_fatal_error",
thd->is_slave_error= 0; thd->is_fatal_error= 1;);
=== modified file 'sql/mdl.cc'
--- a/sql/mdl.cc 2010-10-27 09:55:52 +0000
+++ b/sql/mdl.cc 2010-11-03 14:30:33 +0000
@@ -731,8 +731,7 @@ void MDL_map::remove(MDL_lock *lock)
*/
MDL_context::MDL_context()
- :m_trans_sentinel(NULL),
- m_thd(NULL),
+ : m_thd(NULL),
m_needs_thr_lock_abort(FALSE),
m_waiting_for(NULL)
{
@@ -754,7 +753,9 @@ MDL_context::MDL_context()
void MDL_context::destroy()
{
- DBUG_ASSERT(m_tickets.is_empty());
+ DBUG_ASSERT(m_tickets[MDL_STATEMENT].is_empty() &&
+ m_tickets[MDL_TRANSACTION].is_empty() &&
+ m_tickets[MDL_EXPLICIT].is_empty());
mysql_prlock_destroy(&m_LOCK_waiting_for);
}
@@ -783,10 +784,12 @@ void MDL_context::destroy()
void MDL_request::init(MDL_key::enum_mdl_namespace mdl_namespace,
const char *db_arg,
const char *name_arg,
- enum enum_mdl_type mdl_type_arg)
+ enum_mdl_type mdl_type_arg,
+ enum_mdl_duration mdl_duration_arg)
{
key.mdl_key_init(mdl_namespace, db_arg, name_arg);
type= mdl_type_arg;
+ duration= mdl_duration_arg;
ticket= NULL;
}
@@ -801,49 +804,17 @@ void MDL_request::init(MDL_key::enum_mdl
*/
void MDL_request::init(const MDL_key *key_arg,
- enum enum_mdl_type mdl_type_arg)
+ enum_mdl_type mdl_type_arg,
+ enum_mdl_duration mdl_duration_arg)
{
key.mdl_key_init(key_arg);
type= mdl_type_arg;
+ duration= mdl_duration_arg;
ticket= NULL;
}
/**
- Allocate and initialize one lock request.
-
- Same as mdl_init_lock(), but allocates the lock and the key buffer
- on a memory root. Necessary to lock ad-hoc tables, e.g.
- mysql.* tables of grant and data dictionary subsystems.
-
- @param mdl_namespace Id of namespace of object to be locked
- @param db Name of database to which object belongs
- @param name Name of of object
- @param root MEM_ROOT on which object should be allocated
-
- @note The allocated lock request will have MDL_SHARED type.
-
- @retval 0 Error if out of memory
- @retval non-0 Pointer to an object representing a lock request
-*/
-
-MDL_request *
-MDL_request::create(MDL_key::enum_mdl_namespace mdl_namespace, const char *db,
- const char *name, enum_mdl_type mdl_type,
- MEM_ROOT *root)
-{
- MDL_request *mdl_request;
-
- if (!(mdl_request= (MDL_request*) alloc_root(root, sizeof(MDL_request))))
- return NULL;
-
- mdl_request->init(mdl_namespace, db, name, mdl_type);
-
- return mdl_request;
-}
-
-
-/**
Auxiliary functions needed for creation/destruction of MDL_lock objects.
@note Also chooses an MDL_lock descendant appropriate for object namespace.
@@ -880,9 +851,17 @@ void MDL_lock::destroy(MDL_lock *lock)
on memory allocation by reusing released objects.
*/
-MDL_ticket *MDL_ticket::create(MDL_context *ctx_arg, enum_mdl_type type_arg)
-{
- return new MDL_ticket(ctx_arg, type_arg);
+MDL_ticket *MDL_ticket::create(MDL_context *ctx_arg, enum_mdl_type type_arg
+#ifndef DBUG_OFF
+ , enum_mdl_duration duration_arg
+#endif
+ )
+{
+ return new MDL_ticket(ctx_arg, type_arg
+#ifndef DBUG_OFF
+ , duration_arg
+#endif
+ );
}
@@ -1451,13 +1430,11 @@ bool MDL_ticket::is_incompatible_when_wa
/**
Check whether the context already holds a compatible lock ticket
on an object.
- Start searching the transactional locks. If not
- found in the list of transactional locks, look at LOCK TABLES
- and HANDLER locks.
+ Start searching from list of locks for the same duration as lock
+ being requested. If not look at lists for other durations.
@param mdl_request Lock request object for lock to be acquired
- @param[out] is_transactional FALSE if we pass beyond m_trans_sentinel
- while searching for ticket, otherwise TRUE.
+ @param[out] result_duration Duration of lock which was found.
@note Tickets which correspond to lock types "stronger" than one
being requested are also considered compatible.
@@ -1467,48 +1444,27 @@ bool MDL_ticket::is_incompatible_when_wa
MDL_ticket *
MDL_context::find_ticket(MDL_request *mdl_request,
- bool *is_transactional)
+ enum_mdl_duration *result_duration)
{
MDL_ticket *ticket;
- Ticket_iterator it(m_tickets);
-
- *is_transactional= TRUE;
+ int i;
- while ((ticket= it++))
+ for (i= 0; i < MDL_DURATION_END; i++)
{
- if (ticket == m_trans_sentinel)
- *is_transactional= FALSE;
+ enum_mdl_duration duration= (enum_mdl_duration)((mdl_request->duration+i) %
+ MDL_DURATION_END);
+ Ticket_iterator it(m_tickets[duration]);
- if (mdl_request->key.is_equal(&ticket->m_lock->key) &&
- ticket->has_stronger_or_equal_type(mdl_request->type))
- break;
+ while ((ticket= it++))
+ {
+ if (mdl_request->key.is_equal(&ticket->m_lock->key) &&
+ ticket->has_stronger_or_equal_type(mdl_request->type))
+ {
+ *result_duration= duration;
+ return ticket;
+ }
+ }
}
-
- return ticket;
-}
-
-
-/**
- Check whether the ticket at the front of context's ticket list
- is compatible with request.
-
- @param mdl_request Lock request object for ticket to find.
-
- @note Tickets which correspond to lock types "stronger" than one
- being requested are also considered compatible.
-
- @return A pointer to the lock ticket for the object or NULL otherwise.
-*/
-
-MDL_ticket * MDL_context::find_ticket_at_front(MDL_request *mdl_request)
-{
- MDL_ticket *ticket= m_tickets.front();
-
- if (ticket &&
- mdl_request->key.is_equal(&ticket->m_lock->key) &&
- ticket->has_stronger_or_equal_type(mdl_request->type))
- return ticket;
-
return NULL;
}
@@ -1587,7 +1543,7 @@ MDL_context::try_acquire_lock_impl(MDL_r
MDL_lock *lock;
MDL_key *key= &mdl_request->key;
MDL_ticket *ticket;
- bool is_transactional;
+ enum_mdl_duration found_duration;
DBUG_ASSERT(mdl_request->type != MDL_EXCLUSIVE ||
is_lock_owner(MDL_key::GLOBAL, "", "", MDL_INTENTION_EXCLUSIVE));
@@ -1601,7 +1557,7 @@ MDL_context::try_acquire_lock_impl(MDL_r
Check whether the context already holds a shared lock on the object,
and if so, grant the request.
*/
- if ((ticket= find_ticket(mdl_request, &is_transactional)))
+ if ((ticket= find_ticket(mdl_request, &found_duration)))
{
DBUG_ASSERT(ticket->m_lock);
DBUG_ASSERT(ticket->has_stronger_or_equal_type(mdl_request->type));
@@ -1623,7 +1579,9 @@ MDL_context::try_acquire_lock_impl(MDL_r
a different alias.
*/
mdl_request->ticket= ticket;
- if (!is_transactional && clone_ticket(mdl_request))
+ if ((found_duration != mdl_request->duration ||
+ mdl_request->duration == MDL_EXPLICIT) &&
+ clone_ticket(mdl_request))
{
/* Clone failed. */
mdl_request->ticket= NULL;
@@ -1632,7 +1590,11 @@ MDL_context::try_acquire_lock_impl(MDL_r
return FALSE;
}
- if (!(ticket= MDL_ticket::create(this, mdl_request->type)))
+ if (!(ticket= MDL_ticket::create(this, mdl_request->type
+#ifndef DBUG_OFF
+ , mdl_request->duration
+#endif
+ )))
return TRUE;
/* The below call implicitly locks MDL_lock::m_rwlock on success. */
@@ -1650,7 +1612,7 @@ MDL_context::try_acquire_lock_impl(MDL_r
mysql_prlock_unlock(&lock->m_rwlock);
- m_tickets.push_front(ticket);
+ m_tickets[mdl_request->duration].push_front(ticket);
mdl_request->ticket= ticket;
}
@@ -1685,7 +1647,11 @@ MDL_context::clone_ticket(MDL_request *m
we effectively downgrade the cloned lock to the level of
the request.
*/
- if (!(ticket= MDL_ticket::create(this, mdl_request->type)))
+ if (!(ticket= MDL_ticket::create(this, mdl_request->type
+#ifndef DBUG_OFF
+ , mdl_request->duration
+#endif
+ )))
return TRUE;
/* clone() is not supposed to be used to get a stronger lock. */
@@ -1698,7 +1664,7 @@ MDL_context::clone_ticket(MDL_request *m
ticket->m_lock->m_granted.add_ticket(ticket);
mysql_prlock_unlock(&ticket->m_lock->m_rwlock);
- m_tickets.push_front(ticket);
+ m_tickets[mdl_request->duration].push_front(ticket);
return FALSE;
}
@@ -1894,7 +1860,7 @@ MDL_context::acquire_lock(MDL_request *m
*/
DBUG_ASSERT(wait_status == MDL_wait::GRANTED);
- m_tickets.push_front(ticket);
+ m_tickets[mdl_request->duration].push_front(ticket);
mdl_request->ticket= ticket;
@@ -1935,7 +1901,7 @@ bool MDL_context::acquire_locks(MDL_requ
{
MDL_request_list::Iterator it(*mdl_requests);
MDL_request **sort_buf, **p_req;
- MDL_ticket *mdl_svp= mdl_savepoint();
+ MDL_savepoint mdl_svp= mdl_savepoint();
ssize_t req_count= static_cast<ssize_t>(mdl_requests->elements());
if (req_count == 0)
@@ -2004,7 +1970,7 @@ MDL_context::upgrade_shared_lock_to_excl
ulong lock_wait_timeout)
{
MDL_request mdl_xlock_request;
- MDL_ticket *mdl_svp= mdl_savepoint();
+ MDL_savepoint mdl_svp= mdl_savepoint();
bool is_new_ticket;
DBUG_ENTER("MDL_ticket::upgrade_shared_lock_to_exclusive");
@@ -2021,7 +1987,8 @@ MDL_context::upgrade_shared_lock_to_excl
DBUG_ASSERT(mdl_ticket->m_type == MDL_SHARED_NO_WRITE ||
mdl_ticket->m_type == MDL_SHARED_NO_READ_WRITE);
- mdl_xlock_request.init(&mdl_ticket->m_lock->key, MDL_EXCLUSIVE);
+ mdl_xlock_request.init(&mdl_ticket->m_lock->key, MDL_EXCLUSIVE,
+ MDL_TRANSACTION);
if (acquire_lock(&mdl_xlock_request, lock_wait_timeout))
DBUG_RETURN(TRUE);
@@ -2045,7 +2012,7 @@ MDL_context::upgrade_shared_lock_to_excl
if (is_new_ticket)
{
- m_tickets.remove(mdl_xlock_request.ticket);
+ m_tickets[MDL_TRANSACTION].remove(mdl_xlock_request.ticket);
MDL_ticket::destroy(mdl_xlock_request.ticket);
}
@@ -2306,10 +2273,12 @@ void MDL_context::find_deadlock()
/**
Release lock.
- @param ticket Ticket for lock to be released.
+ @param duration Lock duration.
+ @param ticket Ticket for lock to be released.
+
*/
-void MDL_context::release_lock(MDL_ticket *ticket)
+void MDL_context::release_lock(enum_mdl_duration duration, MDL_ticket *ticket)
{
MDL_lock *lock= ticket->m_lock;
DBUG_ENTER("MDL_context::release_lock");
@@ -2319,12 +2288,9 @@ void MDL_context::release_lock(MDL_ticke
DBUG_ASSERT(this == ticket->get_ctx());
mysql_mutex_assert_not_owner(&LOCK_open);
- if (ticket == m_trans_sentinel)
- m_trans_sentinel= ++Ticket_list::Iterator(m_tickets, ticket);
-
lock->remove_ticket(&MDL_lock::m_granted, ticket);
- m_tickets.remove(ticket);
+ m_tickets[duration].remove(ticket);
MDL_ticket::destroy(ticket);
DBUG_VOID_RETURN;
@@ -2332,50 +2298,56 @@ void MDL_context::release_lock(MDL_ticke
/**
+ Release lock with explicit duration.
+
+ @param ticket Ticket for lock to be released.
+
+*/
+
+void MDL_context::release_lock(MDL_ticket *ticket)
+{
+ DBUG_ASSERT(ticket->m_duration == MDL_EXPLICIT);
+
+ release_lock(MDL_EXPLICIT, ticket);
+}
+
+
+/**
Release all locks associated with the context. If the sentinel
is not NULL, do not release locks stored in the list after and
including the sentinel.
- Transactional locks are added to the beginning of the list, i.e.
- stored in reverse temporal order. This allows to employ this
- function to:
+ Statement and transactional locks are added to the beginning of
+ the corresponding lists, i.e. stored in reverse temporal order.
+ This allows to employ this function to:
- back off in case of a lock conflict.
- - release all locks in the end of a transaction
+ - release all locks in the end of a statment or transaction
- rollback to a savepoint.
-
- The sentinel semantics is used to support LOCK TABLES
- mode and HANDLER statements: locks taken by these statements
- survive COMMIT, ROLLBACK, ROLLBACK TO SAVEPOINT.
*/
-void MDL_context::release_locks_stored_before(MDL_ticket *sentinel)
+void MDL_context::release_locks_stored_before(enum_mdl_duration duration,
+ MDL_ticket *sentinel)
{
MDL_ticket *ticket;
- Ticket_iterator it(m_tickets);
+ Ticket_iterator it(m_tickets[duration]);
DBUG_ENTER("MDL_context::release_locks_stored_before");
- if (m_tickets.is_empty())
+ if (m_tickets[duration].is_empty())
DBUG_VOID_RETURN;
while ((ticket= it++) && ticket != sentinel)
{
DBUG_PRINT("info", ("found lock to release ticket=%p", ticket));
- release_lock(ticket);
+ release_lock(duration, ticket);
}
- /*
- If all locks were released, then the sentinel was not present
- in the list. It must never happen because the sentinel was
- bogus, i.e. pointed to a ticket that no longer exists.
- */
- DBUG_ASSERT(! m_tickets.is_empty() || sentinel == NULL);
DBUG_VOID_RETURN;
}
/**
- Release all locks in the context which correspond to the same name/
- object as this lock request.
+ Release all explicit locks in the context which correspond to the
+ same name/object as this lock request.
@param ticket One of the locks for the name/object for which all
locks should be released.
@@ -2388,17 +2360,13 @@ void MDL_context::release_all_locks_for_
/* Remove matching lock tickets from the context. */
MDL_ticket *ticket;
- Ticket_iterator it_ticket(m_tickets);
+ Ticket_iterator it_ticket(m_tickets[MDL_EXPLICIT]);
while ((ticket= it_ticket++))
{
DBUG_ASSERT(ticket->m_lock);
- /*
- We rarely have more than one ticket in this loop,
- let's not bother saving on pthread_cond_broadcast().
- */
if (ticket->m_lock == lock)
- release_lock(ticket);
+ release_lock(MDL_EXPLICIT, ticket);
}
}
@@ -2453,9 +2421,10 @@ MDL_context::is_lock_owner(MDL_key::enum
enum_mdl_type mdl_type)
{
MDL_request mdl_request;
- bool is_transactional_unused;
- mdl_request.init(mdl_namespace, db, name, mdl_type);
- MDL_ticket *ticket= find_ticket(&mdl_request, &is_transactional_unused);
+ enum_mdl_duration not_unused;
+ /* We don't care about exact duration of lock here. */
+ mdl_request.init(mdl_namespace, db, name, mdl_type, MDL_TRANSACTION);
+ MDL_ticket *ticket= find_ticket(&mdl_request, ¬_unused);
DBUG_ASSERT(ticket == NULL || ticket->m_lock);
@@ -2484,18 +2453,15 @@ bool MDL_ticket::has_pending_conflicting
@note It's safe to iterate and unlock any locks after taken after this
savepoint because other statements that take other special locks
cause a implicit commit (ie LOCK TABLES).
-
- @param mdl_savepont The last acquired MDL lock when the
- savepoint was set.
*/
-void MDL_context::rollback_to_savepoint(MDL_ticket *mdl_savepoint)
+void MDL_context::rollback_to_savepoint(const MDL_savepoint &mdl_savepoint)
{
DBUG_ENTER("MDL_context::rollback_to_savepoint");
/* If savepoint is NULL, it is from the start of the transaction. */
- release_locks_stored_before(mdl_savepoint ?
- mdl_savepoint : m_trans_sentinel);
+ release_locks_stored_before(MDL_STATEMENT, mdl_savepoint.m_stmt_ticket);
+ release_locks_stored_before(MDL_TRANSACTION, mdl_savepoint.m_trans_ticket);
DBUG_VOID_RETURN;
}
@@ -2513,78 +2479,150 @@ void MDL_context::rollback_to_savepoint(
void MDL_context::release_transactional_locks()
{
DBUG_ENTER("MDL_context::release_transactional_locks");
- release_locks_stored_before(m_trans_sentinel);
+ release_locks_stored_before(MDL_STATEMENT, NULL);
+ release_locks_stored_before(MDL_TRANSACTION, NULL);
+ DBUG_VOID_RETURN;
+}
+
+
+void MDL_context::release_statement_locks()
+{
+ DBUG_ENTER("MDL_context::release_transactional_locks");
+ release_locks_stored_before(MDL_STATEMENT, NULL);
DBUG_VOID_RETURN;
}
/**
Does this savepoint have this lock?
-
- @retval TRUE The ticket is older than the savepoint and
- is not LT, HA or GLR ticket. Thus it belongs
- to the savepoint.
- @retval FALSE The ticket is newer than the savepoint
- or is an LT, HA or GLR ticket.
+
+ @retval TRUE The ticket is older than the savepoint or
+ is an LT, HA or GLR ticket. Thus it belongs
+ to the savepoint or has explicit duration.
+ @retval FALSE The ticket is newer than the savepoint.
+ and is not an LT, HA or GLR ticket.
*/
-bool MDL_context::has_lock(MDL_ticket *mdl_savepoint,
+bool MDL_context::has_lock(const MDL_savepoint &mdl_savepoint,
MDL_ticket *mdl_ticket)
{
MDL_ticket *ticket;
/* Start from the beginning, most likely mdl_ticket's been just acquired. */
- MDL_context::Ticket_iterator it(m_tickets);
- bool found_savepoint= FALSE;
+ MDL_context::Ticket_iterator s_it(m_tickets[MDL_STATEMENT]);
+ MDL_context::Ticket_iterator t_it(m_tickets[MDL_TRANSACTION]);
- while ((ticket= it++) && ticket != m_trans_sentinel)
+ while ((ticket= s_it++) && ticket != mdl_savepoint.m_stmt_ticket)
{
- /*
- First met the savepoint. The ticket must be
- somewhere after it.
- */
- if (ticket == mdl_savepoint)
- found_savepoint= TRUE;
- /*
- Met the ticket. If we haven't yet met the savepoint,
- the ticket is newer than the savepoint.
- */
if (ticket == mdl_ticket)
- return found_savepoint;
+ return FALSE;
}
- /* Reached m_trans_sentinel. The ticket must be LT, HA or GRL ticket. */
- return FALSE;
+
+ while ((ticket= t_it++) && ticket != mdl_savepoint.m_trans_ticket)
+ {
+ if (ticket == mdl_ticket)
+ return FALSE;
+ }
+ return TRUE;
+}
+
+
+/**
+ Change lock duration for transactional lock.
+
+ @param ticket Ticket representing lock.
+ @param duration Lock duration to be set.
+
+ @note This method only supports changing duration of
+ transactional lock to some other duration.
+*/
+
+void MDL_context::set_lock_duration(MDL_ticket *mdl_ticket,
+ enum_mdl_duration duration)
+{
+ DBUG_ASSERT(mdl_ticket->m_duration == MDL_TRANSACTION &&
+ duration != MDL_TRANSACTION);
+
+ m_tickets[MDL_TRANSACTION].remove(mdl_ticket);
+ m_tickets[duration].push_front(mdl_ticket);
+#ifndef DBUG_OFF
+ mdl_ticket->m_duration= duration;
+#endif
}
/**
- Rearrange the ticket to reside in the part of the list that's
- beyond m_trans_sentinel. This effectively changes the ticket
- life cycle, from automatic to manual: i.e. the ticket is no
- longer released by MDL_context::release_transactional_locks() or
- MDL_context::rollback_to_savepoint(), it must be released manually.
+ Set explicit duration for all locks in the context.
*/
-void MDL_context::move_ticket_after_trans_sentinel(MDL_ticket *mdl_ticket)
+void MDL_context::set_explicit_duration_for_all_locks()
{
- m_tickets.remove(mdl_ticket);
- if (m_trans_sentinel == NULL)
+ int i;
+ MDL_ticket *ticket;
+
+ /*
+ In the most common case when this function is called list
+ of transactional locks is bigger than list of locks with
+ explicit duration. So we start by swapping these two lists
+ and then move elements from new list of transactional
+ locks and list of statement locks to list of locks with
+ explicit duration.
+ */
+
+ m_tickets[MDL_EXPLICIT].swap(m_tickets[MDL_TRANSACTION]);
+
+ for (i= 0; i < MDL_EXPLICIT; i++)
{
- m_trans_sentinel= mdl_ticket;
- m_tickets.push_back(mdl_ticket);
+ Ticket_iterator it_ticket(m_tickets[i]);
+
+ while ((ticket= it_ticket++))
+ {
+ m_tickets[i].remove(ticket);
+ m_tickets[MDL_EXPLICIT].push_front(ticket);
+ }
}
- else
- m_tickets.insert_after(m_trans_sentinel, mdl_ticket);
+
+#ifndef DBUG_OFF
+ Ticket_iterator exp_it(m_tickets[MDL_EXPLICIT]);
+
+ while ((ticket= exp_it++))
+ ticket->m_duration= MDL_EXPLICIT;
+#endif
}
/**
- Move ticket to the front of the context's ticket list.
-
- @param mdl_ticket Ticket to move.
+ Set transactional duration for all locks in the context.
*/
-void MDL_context::move_ticket_to_front(MDL_ticket *mdl_ticket)
+void MDL_context::set_transaction_duration_for_all_locks()
{
- m_tickets.remove(mdl_ticket);
- m_tickets.push_front(mdl_ticket);
+ MDL_ticket *ticket;
+
+ /*
+ In the most common case when this function is called list
+ of explicit locks is bigger than two other lists (in fact,
+ list of statement locks is always empty). So we start by
+ swapping list of explicit and transactional locks and then
+ move contents of new list of explicit locks to list of
+ locks with transactional duration.
+ */
+
+ DBUG_ASSERT(m_tickets[MDL_STATEMENT].is_empty());
+
+ m_tickets[MDL_TRANSACTION].swap(m_tickets[MDL_EXPLICIT]);
+
+ Ticket_iterator it_ticket(m_tickets[MDL_EXPLICIT]);
+
+ while ((ticket= it_ticket++))
+ {
+ m_tickets[MDL_EXPLICIT].remove(ticket);
+ m_tickets[MDL_TRANSACTION].push_front(ticket);
+ }
+
+#ifndef DBUG_OFF
+ Ticket_iterator trans_it(m_tickets[MDL_TRANSACTION]);
+
+ while ((ticket= trans_it++))
+ ticket->m_duration= MDL_TRANSACTION;
+#endif
}
=== modified file 'sql/mdl.h'
--- a/sql/mdl.h 2010-10-25 15:16:12 +0000
+++ b/sql/mdl.h 2010-11-03 14:30:33 +0000
@@ -150,6 +150,15 @@ enum enum_mdl_type {
MDL_TYPE_END};
+/** Duration of metadata lock. */
+
+enum enum_mdl_duration { MDL_STATEMENT= 0,
+ MDL_TRANSACTION,
+ MDL_EXPLICIT,
+ /* This should be the last ! */
+ MDL_DURATION_END };
+
+
/** Maximal length of key for metadata locking subsystem. */
#define MAX_MDLKEY_LENGTH (1 + NAME_LEN + 1 + NAME_LEN + 1)
@@ -310,6 +319,8 @@ class MDL_request
public:
/** Type of metadata lock. */
enum enum_mdl_type type;
+ /** Duration for requested lock. */
+ enum enum_mdl_duration duration;
/**
Pointers for participating in the list of lock requests for this context.
@@ -332,17 +343,16 @@ public:
void init(MDL_key::enum_mdl_namespace namespace_arg,
const char *db_arg, const char *name_arg,
- enum_mdl_type mdl_type_arg);
- void init(const MDL_key *key_arg, enum_mdl_type mdl_type_arg);
+ enum_mdl_type mdl_type_arg,
+ enum_mdl_duration mdl_duration_arg);
+ void init(const MDL_key *key_arg, enum_mdl_type mdl_type_arg,
+ enum_mdl_duration mdl_duration_arg);
/** Set type of lock request. Can be only applied to pending locks. */
inline void set_type(enum_mdl_type type_arg)
{
DBUG_ASSERT(ticket == NULL);
type= type_arg;
}
- static MDL_request *create(MDL_key::enum_mdl_namespace mdl_namespace,
- const char *db, const char *name,
- enum_mdl_type mdl_type, MEM_ROOT *root);
/*
This is to work around the ugliness of TABLE_LIST
@@ -368,6 +378,7 @@ public:
MDL_request(const MDL_request *rhs)
:type(rhs->type),
+ duration(rhs->duration),
ticket(NULL),
key(&rhs->key)
{}
@@ -489,17 +500,35 @@ public:
private:
friend class MDL_context;
- MDL_ticket(MDL_context *ctx_arg, enum_mdl_type type_arg)
+ MDL_ticket(MDL_context *ctx_arg, enum_mdl_type type_arg
+#ifndef DBUG_OFF
+ , enum_mdl_duration duration_arg
+#endif
+ )
: m_type(type_arg),
+#ifndef DBUG_OFF
+ m_duration(duration_arg),
+#endif
m_ctx(ctx_arg),
m_lock(NULL)
{}
- static MDL_ticket *create(MDL_context *ctx_arg, enum_mdl_type type_arg);
+ static MDL_ticket *create(MDL_context *ctx_arg, enum_mdl_type type_arg
+#ifndef DBUG_OFF
+ , enum_mdl_duration duration_arg
+#endif
+ );
static void destroy(MDL_ticket *ticket);
private:
/** Type of metadata lock. Externally accessible. */
enum enum_mdl_type m_type;
+#ifndef DBUG_OFF
+ /**
+ Duration of lock represented by this ticket.
+ Context private. Debug-only.
+ */
+ enum_mdl_duration m_duration;
+#endif
/**
Context of the owner of the metadata lock ticket. Externally accessible.
*/
@@ -517,6 +546,39 @@ private:
/**
+ Savepoint for MDL context.
+
+ Doesn't include metadata locks with explicit duration as
+ they are not released during rollback to savepoint.
+*/
+
+class MDL_savepoint
+{
+public:
+ MDL_savepoint() {};
+
+private:
+ MDL_savepoint(MDL_ticket *stmt_ticket, MDL_ticket *trans_ticket)
+ : m_stmt_ticket(stmt_ticket), m_trans_ticket(trans_ticket)
+ {}
+
+ friend class MDL_context;
+
+private:
+ /**
+ Pointer to last lock with statement duration which was taken
+ before creation of savepoint.
+ */
+ MDL_ticket *m_stmt_ticket;
+ /**
+ Pointer to last lock with transaction duration which was taken
+ before creation of savepoint.
+ */
+ MDL_ticket *m_trans_ticket;
+};
+
+
+/**
A reliable way to wait on an MDL lock.
*/
@@ -564,9 +626,7 @@ public:
typedef I_P_List<MDL_ticket,
I_P_List_adapter<MDL_ticket,
&MDL_ticket::next_in_context,
- &MDL_ticket::prev_in_context>,
- I_P_List_null_counter,
- I_P_List_fast_push_back<MDL_ticket> >
+ &MDL_ticket::prev_in_context> >
Ticket_list;
typedef Ticket_list::Iterator Ticket_iterator;
@@ -589,38 +649,28 @@ public:
const char *db, const char *name,
enum_mdl_type mdl_type);
- bool has_lock(MDL_ticket *mdl_savepoint, MDL_ticket *mdl_ticket);
+ bool has_lock(const MDL_savepoint &mdl_savepoint, MDL_ticket *mdl_ticket);
inline bool has_locks() const
{
- return !m_tickets.is_empty();
+ return !(m_tickets[MDL_STATEMENT].is_empty() &&
+ m_tickets[MDL_TRANSACTION].is_empty() &&
+ m_tickets[MDL_EXPLICIT].is_empty());
}
- MDL_ticket *mdl_savepoint()
+ MDL_savepoint mdl_savepoint()
{
- /*
- NULL savepoint represents the start of the transaction.
- Checking for m_trans_sentinel also makes sure we never
- return a pointer to HANDLER ticket as a savepoint.
- */
- return m_tickets.front() == m_trans_sentinel ? NULL : m_tickets.front();
+ return MDL_savepoint(m_tickets[MDL_STATEMENT].front(),
+ m_tickets[MDL_TRANSACTION].front());
}
- void set_trans_sentinel()
- {
- m_trans_sentinel= m_tickets.front();
- }
- MDL_ticket *trans_sentinel() const { return m_trans_sentinel; }
-
- void reset_trans_sentinel(MDL_ticket *sentinel_arg)
- {
- m_trans_sentinel= sentinel_arg;
- }
- void move_ticket_after_trans_sentinel(MDL_ticket *mdl_ticket);
- void move_ticket_to_front(MDL_ticket *mdl_ticket);
+ void set_explicit_duration_for_all_locks();
+ void set_transaction_duration_for_all_locks();
+ void set_lock_duration(MDL_ticket *mdl_ticket, enum_mdl_duration duration);
+ void release_statement_locks();
void release_transactional_locks();
- void rollback_to_savepoint(MDL_ticket *mdl_savepoint);
+ void rollback_to_savepoint(const MDL_savepoint &mdl_savepoint);
inline THD *get_thd() const { return m_thd; }
@@ -661,46 +711,43 @@ public:
MDL_wait m_wait;
private:
/**
- All MDL tickets acquired by this connection.
+ Lists of all MDL tickets acquired by this connection.
- The order of tickets in m_tickets list.
- ---------------------------------------
- The entire set of locks acquired by a connection
- can be separated in two subsets: transactional and
- non-transactional locks.
-
- Transactional locks are locks with automatic scope. They
- are accumulated in the course of a transaction, and
- released only on COMMIT, ROLLBACK or ROLLBACK TO SAVEPOINT.
- They must not be (and never are) released manually,
+ Lists of MDL tickets:
+ ---------------------
+ The entire set of locks acquired by a connection can be separated
+ in three subsets according to their: locks released at the end of
+ statement, at the end of transaction and locks are released
+ explicitly.
+
+ Statement and transactional locks are locks with automatic scope.
+ They are accumulated in the course of a transaction, and released
+ either at the end of uppermost statement (for statement locks) or
+ on COMMIT, ROLLBACK or ROLLBACK TO SAVEPOINT (for transactional
+ locks). They must not be (and never are) released manually,
i.e. with release_lock() call.
- Non-transactional locks are taken for locks that span
+ Locks with explicit duration are taken for locks that span
multiple transactions or savepoints.
These are: HANDLER SQL locks (HANDLER SQL is
transaction-agnostic), LOCK TABLES locks (you can COMMIT/etc
under LOCK TABLES, and the locked tables stay locked), and
- SET GLOBAL READ_ONLY=1 global shared lock.
+ locks implementing "global read lock".
- Transactional locks are always prepended to the beginning
- of the list. In other words, they are stored in reverse
- temporal order. Thus, when we rollback to a savepoint,
- we start popping and releasing tickets from the front
- until we reach the last ticket acquired after the
- savepoint.
-
- Non-transactional locks are always stored after
- transactional ones, and among each other can be
- split into three sets:
+ Statement/transactional locks are always prepended to the
+ beginning of the appropriate list. In other words, they are
+ stored in reverse temporal order. Thus, when we rollback to
+ a savepoint, we start popping and releasing tickets from the
+ front until we reach the last ticket acquired after the savepoint.
+
+ Locks with explicit duration stored are not stored in any
+ particular order, and among each other can be split into
+ three sets:
[LOCK TABLES locks] [HANDLER locks] [GLOBAL READ LOCK locks]
The following is known about these sets:
- * we can never have both HANDLER and LOCK TABLES locks
- together -- HANDLER statements are prohibited under LOCK
- TABLES, entering LOCK TABLES implicitly closes all open
- HANDLERs.
* GLOBAL READ LOCK locks are always stored after LOCK TABLES
locks and after HANDLER locks. This is because one can't say
SET GLOBAL read_only=1 or FLUSH TABLES WITH READ LOCK
@@ -715,14 +762,9 @@ private:
However, one can open a few HANDLERs after entering the
read only mode.
* LOCK TABLES locks include intention exclusive locks on
- involved schemas.
+ involved schemas and global intention exclusive lock.
*/
- Ticket_list m_tickets;
- /**
- Separates transactional and non-transactional locks
- in m_tickets list, @sa m_tickets.
- */
- MDL_ticket *m_trans_sentinel;
+ Ticket_list m_tickets[MDL_DURATION_END];
THD *m_thd;
/**
TRUE - if for this context we will break protocol and try to
@@ -751,13 +793,11 @@ private:
readily available to the wait-for graph iterator.
*/
MDL_wait_for_subgraph *m_waiting_for;
-public:
- MDL_ticket *find_ticket(MDL_request *mdl_req,
- bool *is_transactional);
-
- MDL_ticket *find_ticket_at_front(MDL_request *mdl_req);
private:
- void release_locks_stored_before(MDL_ticket *sentinel);
+ MDL_ticket *find_ticket(MDL_request *mdl_req,
+ enum_mdl_duration *duration);
+ void release_locks_stored_before(enum_mdl_duration duration, MDL_ticket *sentinel);
+ void release_lock(enum_mdl_duration duration, MDL_ticket *ticket);
bool try_acquire_lock_impl(MDL_request *mdl_request,
MDL_ticket **out_ticket);
=== modified file 'sql/rpl_rli.cc'
--- a/sql/rpl_rli.cc 2010-10-18 12:33:49 +0000
+++ b/sql/rpl_rli.cc 2010-11-03 14:30:33 +0000
@@ -1275,7 +1275,7 @@ void Relay_log_info::slave_close_thread_
if (! thd->in_multi_stmt_transaction_mode())
thd->mdl_context.release_transactional_locks();
else
- thd->global_read_lock.release_protection_if_set(thd);
+ thd->mdl_context.release_statement_locks();
clear_tables_to_lock();
}
=== modified file 'sql/sp.cc'
--- a/sql/sp.cc 2010-10-25 15:16:12 +0000
+++ b/sql/sp.cc 2010-11-03 14:30:33 +0000
@@ -440,7 +440,7 @@ static TABLE *open_proc_table_for_update
{
TABLE_LIST table_list;
TABLE *table;
- MDL_ticket *mdl_savepoint= thd->mdl_context.mdl_savepoint();
+ MDL_savepoint mdl_savepoint= thd->mdl_context.mdl_savepoint();
DBUG_ENTER("open_proc_table_for_update");
table_list.init_one_table("mysql", 5, "proc", 4, "proc", TL_WRITE);
@@ -1370,7 +1370,7 @@ sp_drop_db_routines(THD *thd, char *db)
TABLE *table;
int ret;
uint key_len;
- MDL_ticket *mdl_savepoint= thd->mdl_context.mdl_savepoint();
+ MDL_savepoint mdl_savepoint= thd->mdl_context.mdl_savepoint();
DBUG_ENTER("sp_drop_db_routines");
DBUG_PRINT("enter", ("db: %s", db));
@@ -1694,7 +1694,7 @@ bool sp_add_used_routine(Query_tables_li
(Sroutine_hash_entry *)arena->alloc(sizeof(Sroutine_hash_entry));
if (!rn) // OOM. Error will be reported using fatal_error().
return FALSE;
- rn->mdl_request.init(key, MDL_SHARED);
+ rn->mdl_request.init(key, MDL_SHARED, MDL_TRANSACTION);
if (my_hash_insert(&prelocking_ctx->sroutines, (uchar *)rn))
return FALSE;
prelocking_ctx->sroutines_list.link_in_list(rn, &rn->next);
=== modified file 'sql/sp_head.cc'
--- a/sql/sp_head.cc 2010-10-28 19:35:28 +0000
+++ b/sql/sp_head.cc 2010-11-03 14:30:33 +0000
@@ -2129,7 +2129,7 @@ sp_head::execute_procedure(THD *thd, Lis
else if (! thd->locked_tables_mode)
{
DBUG_ASSERT(! thd->in_sub_stmt);
- thd->global_read_lock.release_protection_if_set(thd);
+ thd->mdl_context.release_statement_locks();
}
thd->rollback_item_tree_changes();
@@ -2967,7 +2967,7 @@ sp_lex_keeper::reset_lex_and_exec_core(T
if (! thd->in_sub_stmt && ! thd->in_multi_stmt_transaction_mode())
thd->mdl_context.release_transactional_locks();
else if (! thd->in_sub_stmt && !thd->locked_tables_mode)
- thd->global_read_lock.release_protection_if_set(thd);
+ thd->mdl_context.release_statement_locks();
}
if (m_lex->query_tables_own_last)
@@ -4163,7 +4163,8 @@ sp_head::add_used_tables_to_table_list(T
*/
table->mdl_request.init(MDL_key::TABLE, table->db, table->table_name,
table->lock_type >= TL_WRITE_ALLOW_WRITE ?
- MDL_SHARED_WRITE : MDL_SHARED_READ);
+ MDL_SHARED_WRITE : MDL_SHARED_READ,
+ MDL_TRANSACTION);
/* Everyting else should be zeroed */
@@ -4207,7 +4208,7 @@ sp_add_to_query_tables(THD *thd, LEX *le
table->select_lex= lex->current_select;
table->cacheable_table= 1;
table->mdl_request.init(MDL_key::TABLE, table->db, table->table_name,
- mdl_type);
+ mdl_type, MDL_TRANSACTION);
lex->add_to_query_tables(table);
return table;
=== modified file 'sql/sql_admin.cc'
--- a/sql/sql_admin.cc 2010-09-22 08:15:41 +0000
+++ b/sql/sql_admin.cc 2010-11-03 14:30:33 +0000
@@ -85,7 +85,7 @@ static int prepare_for_repair(THD *thd,
key_length= create_table_def_key(thd, key, table_list, 0);
table_list->mdl_request.init(MDL_key::TABLE,
table_list->db, table_list->table_name,
- MDL_EXCLUSIVE);
+ MDL_EXCLUSIVE, MDL_TRANSACTION);
if (lock_table_names(thd, table_list, table_list->next_global,
thd->variables.lock_wait_timeout,
=== modified file 'sql/sql_base.cc'
--- a/sql/sql_base.cc 2010-10-22 13:26:29 +0000
+++ b/sql/sql_base.cc 2010-11-03 14:30:33 +0000
@@ -2450,7 +2450,8 @@ open_table_get_mdl_lock(THD *thd, Open_t
mdl_request_shared.init(&mdl_request->key,
(flags & MYSQL_OPEN_FORCE_SHARED_MDL) ?
- MDL_SHARED : MDL_SHARED_HIGH_PRIO);
+ MDL_SHARED : MDL_SHARED_HIGH_PRIO,
+ MDL_TRANSACTION);
mdl_request= &mdl_request_shared;
}
@@ -2812,7 +2813,8 @@ bool open_table(THD *thd, TABLE_LIST *ta
MYSQL_OPEN_FORCE_SHARED_MDL |
MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL |
MYSQL_OPEN_SKIP_SCOPED_MDL_LOCK)) &&
- ! thd->locked_tables_mode)
+ ! thd->locked_tables_mode &&
+ ! ot_ctx->has_protection_against_grl())
{
MDL_request protection_request;
MDL_deadlock_handler mdl_deadlock_handler(ot_ctx);
@@ -2833,8 +2835,7 @@ bool open_table(THD *thd, TABLE_LIST *ta
if (result)
DBUG_RETURN(TRUE);
- ot_ctx->set_protection_against_grl(&thd->mdl_context,
- protection_request.ticket);
+ ot_ctx->set_has_protection_against_grl();
}
@@ -3872,7 +3873,7 @@ Open_table_context::Open_table_context(T
m_flags(flags),
m_action(OT_NO_ACTION),
m_has_locks(thd->mdl_context.has_locks()),
- m_protection_against_grl(NULL)
+ m_has_protection_against_grl(FALSE)
{}
@@ -4030,11 +4031,11 @@ recover_from_failed_open(THD *thd)
*/
m_failed_table= NULL;
/*
- Reset pointer to ticket for metadata lock protecting
- against GRL. It is no longer valid as the lock was
+ Reset flag indicating that we have already acquired protection
+ against GRL. It is no longer valid as the corresponding lock was
released by close_tables_for_reopen().
*/
- m_protection_against_grl= NULL;
+ m_has_protection_against_grl= FALSE;
/* Prepare for possible another back-off. */
m_action= OT_NO_ACTION;
return result;
@@ -4573,7 +4574,8 @@ lock_table_names(THD *thd,
if (schema_request == NULL)
return TRUE;
schema_request->init(MDL_key::SCHEMA, table->db, "",
- MDL_INTENTION_EXCLUSIVE);
+ MDL_INTENTION_EXCLUSIVE,
+ MDL_TRANSACTION);
mdl_requests.push_front(schema_request);
}
@@ -4926,16 +4928,6 @@ err:
thd_proc_info(thd, 0);
free_root(&new_frm_mem, MYF(0)); // Free pre-alloced block
- if (ot_ctx.get_protection_against_grl())
- {
- /*
- Move ticket for metadata lock which protects this statement from
- a GRL to the front of ticket list. This allows to find it quickly
- when this lock has to be released at the end of statement.
- */
- thd->mdl_context.move_ticket_to_front(ot_ctx.get_protection_against_grl());
- }
-
if (error && *table_to_open)
{
(*table_to_open)->table= NULL;
@@ -5376,16 +5368,6 @@ end:
close_thread_tables(thd);
}
- if (ot_ctx.get_protection_against_grl())
- {
- /*
- Move ticket for metadata lock which protects this statement from
- a GRL to the front of ticket list. This allows to find it quickly
- when this lock has to be released at the end of statement.
- */
- thd->mdl_context.move_ticket_to_front(ot_ctx.get_protection_against_grl());
- }
-
thd_proc_info(thd, 0);
DBUG_RETURN(table);
}
@@ -5416,7 +5398,7 @@ bool open_and_lock_tables(THD *thd, TABL
Prelocking_strategy *prelocking_strategy)
{
uint counter;
- MDL_ticket *mdl_savepoint= thd->mdl_context.mdl_savepoint();
+ MDL_savepoint mdl_savepoint= thd->mdl_context.mdl_savepoint();
DBUG_ENTER("open_and_lock_tables");
DBUG_PRINT("enter", ("derived handling: %d", derived));
@@ -5473,7 +5455,7 @@ bool open_normal_and_derived_tables(THD
{
DML_prelocking_strategy prelocking_strategy;
uint counter;
- MDL_ticket *mdl_savepoint= thd->mdl_context.mdl_savepoint();
+ MDL_savepoint mdl_savepoint= thd->mdl_context.mdl_savepoint();
DBUG_ENTER("open_normal_and_derived_tables");
DBUG_ASSERT(!thd->fill_derived_tables());
if (open_tables(thd, &tables, &counter, flags, &prelocking_strategy) ||
@@ -5730,7 +5712,7 @@ bool lock_tables(THD *thd, TABLE_LIST *t
*/
void close_tables_for_reopen(THD *thd, TABLE_LIST **tables,
- MDL_ticket *start_of_statement_svp)
+ const MDL_savepoint &start_of_statement_svp)
{
TABLE_LIST *first_not_own_table= thd->lex->first_not_own_table();
TABLE_LIST *tmp;
=== modified file 'sql/sql_base.h'
--- a/sql/sql_base.h 2010-10-18 12:33:49 +0000
+++ b/sql/sql_base.h 2010-11-03 14:30:33 +0000
@@ -159,7 +159,7 @@ thr_lock_type read_lock_type_for_table(T
my_bool mysql_rm_tmp_tables(void);
bool rm_temporary_table(handlerton *base, char *path);
void close_tables_for_reopen(THD *thd, TABLE_LIST **tables,
- MDL_ticket *start_of_statement_svp);
+ const MDL_savepoint &start_of_statement_svp);
TABLE_LIST *find_table_in_list(TABLE_LIST *table,
TABLE_LIST *TABLE_LIST::*link,
const char *db_name,
@@ -508,7 +508,7 @@ public:
the statement, so that we can rollback to it before waiting on
locks.
*/
- MDL_ticket *start_of_statement_svp() const
+ const MDL_savepoint &start_of_statement_svp() const
{
return m_start_of_statement_svp;
}
@@ -521,19 +521,17 @@ public:
uint get_flags() const { return m_flags; }
/**
- Set ticket for metadata lock which protects this statement against GRL
- if it was acquired while opening tables.
+ Set flag indicating that we have already acquired metadata lock
+ protecting this statement against GRL while opening tables.
*/
- void set_protection_against_grl(MDL_context *mdl_ctx, MDL_ticket *ticket)
+ void set_has_protection_against_grl()
{
- if (! m_protection_against_grl &&
- ! mdl_ctx->has_lock(m_start_of_statement_svp, ticket))
- m_protection_against_grl= ticket;
+ m_has_protection_against_grl= TRUE;
}
- MDL_ticket* get_protection_against_grl() const
+ bool has_protection_against_grl() const
{
- return m_protection_against_grl;
+ return m_has_protection_against_grl;
}
private:
@@ -543,7 +541,7 @@ private:
should be repaired.
*/
TABLE_LIST *m_failed_table;
- MDL_ticket *m_start_of_statement_svp;
+ MDL_savepoint m_start_of_statement_svp;
/**
Lock timeout in seconds. Initialized to LONG_TIMEOUT when opening system
tables or to the "lock_wait_timeout" system variable for regular tables.
@@ -560,12 +558,10 @@ private:
*/
bool m_has_locks;
/**
- Metadata lock which protects this statement against global read lock
- and which might needed to be individually released at the end of
- statement execution. NULL in cases when such protection is unneeded
- or when we know that this statement will release all locks at its end.
+ Indicates that in the process of opening tables we have acquired
+ protection against global read lock.
*/
- MDL_ticket *m_protection_against_grl;
+ bool m_has_protection_against_grl;
};
=== modified file 'sql/sql_class.cc'
--- a/sql/sql_class.cc 2010-10-19 13:31:53 +0000
+++ b/sql/sql_class.cc 2010-11-03 14:30:33 +0000
@@ -3458,15 +3458,15 @@ void THD::set_mysys_var(struct st_my_thr
void THD::leave_locked_tables_mode()
{
locked_tables_mode= LTM_NONE;
- mdl_context.reset_trans_sentinel(NULL);
+ mdl_context.set_transaction_duration_for_all_locks();
/*
Make sure we don't release the global read lock and commit blocker
when leaving LTM.
*/
- global_read_lock.move_tickets_after_trans_sentinel(this);
+ global_read_lock.set_explicit_lock_duration(this);
/* Also ensure that we don't release metadata locks for open HANDLERs. */
if (handler_tables_hash.records)
- mysql_ha_move_tickets_after_trans_sentinel(this);
+ mysql_ha_set_explicit_lock_duration(this);
}
void THD::get_definer(LEX_USER *definer)
=== modified file 'sql/sql_class.h'
--- a/sql/sql_class.h 2010-10-26 04:25:15 +0000
+++ b/sql/sql_class.h 2010-11-03 14:30:33 +0000
@@ -822,8 +822,8 @@ struct st_savepoint {
char *name;
uint length;
Ha_trx_info *ha_list;
- /** Last acquired lock before this savepoint was set. */
- MDL_ticket *mdl_savepoint;
+ /** State of metadata locks before this savepoint was set. */
+ MDL_savepoint mdl_savepoint;
};
enum xa_states {XA_NOTR=0, XA_ACTIVE, XA_IDLE, XA_PREPARED, XA_ROLLBACK_ONLY};
@@ -1058,12 +1058,12 @@ class Open_tables_backup: public Open_ta
public:
/**
When we backup the open tables state to open a system
- table or tables, points at the last metadata lock
- acquired before the backup. Is used to release
- metadata locks on system tables after they are
+ table or tables, we want to save state of metadata
+ locks which were acquired before the backup. It is used
+ to release metadata locks on system tables after they are
no longer used.
*/
- MDL_ticket *mdl_system_tables_svp;
+ MDL_savepoint mdl_system_tables_svp;
};
/**
@@ -1346,10 +1346,9 @@ public:
bool can_acquire_protection();
bool has_read_lock() const { return (m_state != GRL_NONE); }
void init_protection_request(MDL_request *request);
- void release_protection_if_set(THD *thd);
bool make_global_read_lock_block_commit(THD *thd);
bool is_acquired() const { return m_state != GRL_NONE; }
- void move_tickets_after_trans_sentinel(THD *thd);
+ void set_explicit_lock_duration(THD *thd);
private:
enum_grl_state m_state;
/**
@@ -2699,7 +2698,7 @@ public:
{
DBUG_ASSERT(locked_tables_mode == LTM_NONE);
- mdl_context.set_trans_sentinel();
+ mdl_context.set_explicit_duration_for_all_locks();
locked_tables_mode= mode_arg;
}
void leave_locked_tables_mode();
=== modified file 'sql/sql_db.cc'
--- a/sql/sql_db.cc 2010-07-19 08:27:53 +0000
+++ b/sql/sql_db.cc 2010-11-03 14:30:33 +0000
@@ -1054,7 +1054,8 @@ static long mysql_rm_known_files(THD *th
table_list->alias= table_list->table_name; // If lower_case_table_names=2
table_list->internal_tmp_table= is_prefix(file->name, tmp_file_prefix);
table_list->mdl_request.init(MDL_key::TABLE, table_list->db,
- table_list->table_name, MDL_EXCLUSIVE);
+ table_list->table_name, MDL_EXCLUSIVE,
+ MDL_TRANSACTION);
/* Link into list */
(*tot_list_next_local)= table_list;
(*tot_list_next_global)= table_list;
=== modified file 'sql/sql_handler.cc'
--- a/sql/sql_handler.cc 2010-10-18 12:33:49 +0000
+++ b/sql/sql_handler.cc 2010-11-03 14:30:33 +0000
@@ -179,7 +179,7 @@ bool mysql_ha_open(THD *thd, TABLE_LIST
uint dblen, namelen, aliaslen, counter;
bool error;
TABLE *backup_open_tables;
- MDL_ticket *mdl_savepoint;
+ MDL_savepoint mdl_savepoint;
DBUG_ENTER("mysql_ha_open");
DBUG_PRINT("enter",("'%s'.'%s' as '%s' reopen: %d",
tables->db, tables->table_name, tables->alias,
@@ -248,7 +248,13 @@ bool mysql_ha_open(THD *thd, TABLE_LIST
memcpy(hash_tables->db, tables->db, dblen);
memcpy(hash_tables->table_name, tables->table_name, namelen);
memcpy(hash_tables->alias, tables->alias, aliaslen);
- hash_tables->mdl_request.init(MDL_key::TABLE, db, name, MDL_SHARED);
+ /*
+ We can't request lock with explicit duration for this table
+ right from the start as open_tables() can't handle properly
+ back-off for such locks.
+ */
+ hash_tables->mdl_request.init(MDL_key::TABLE, db, name, MDL_SHARED,
+ MDL_TRANSACTION);
/* for now HANDLER can be used only for real TABLES */
hash_tables->required_type= FRMTYPE_TABLE;
@@ -328,8 +334,8 @@ bool mysql_ha_open(THD *thd, TABLE_LIST
thd->set_open_tables(backup_open_tables);
if (hash_tables->mdl_request.ticket)
{
- thd->mdl_context.
- move_ticket_after_trans_sentinel(hash_tables->mdl_request.ticket);
+ thd->mdl_context.set_lock_duration(hash_tables->mdl_request.ticket,
+ MDL_EXPLICIT);
thd->mdl_context.set_needs_thr_lock_abort(TRUE);
}
@@ -965,24 +971,23 @@ void mysql_ha_cleanup(THD *thd)
/**
- Move tickets for metadata locks corresponding to open HANDLERs
- after transaction sentinel in order to protect them from being
- released at the end of transaction.
+ Set explicit duration for metadata locks corresponding to open HANDLERs
+ to protect them from being released at the end of transaction.
@param thd Thread identifier.
*/
-void mysql_ha_move_tickets_after_trans_sentinel(THD *thd)
+void mysql_ha_set_explicit_lock_duration(THD *thd)
{
TABLE_LIST *hash_tables;
- DBUG_ENTER("mysql_ha_move_tickets_after_trans_sentinel");
+ DBUG_ENTER("mysql_ha_set_explicit_lock_duration");
for (uint i= 0; i < thd->handler_tables_hash.records; i++)
{
hash_tables= (TABLE_LIST*) my_hash_element(&thd->handler_tables_hash, i);
if (hash_tables->table && hash_tables->table->mdl_ticket)
- thd->mdl_context.
- move_ticket_after_trans_sentinel(hash_tables->table->mdl_ticket);
+ thd->mdl_context.set_lock_duration(hash_tables->table->mdl_ticket,
+ MDL_EXPLICIT);
}
DBUG_VOID_RETURN;
}
=== modified file 'sql/sql_handler.h'
--- a/sql/sql_handler.h 2010-06-09 08:39:09 +0000
+++ b/sql/sql_handler.h 2010-11-03 14:30:33 +0000
@@ -31,6 +31,6 @@ void mysql_ha_flush(THD *thd);
void mysql_ha_flush_tables(THD *thd, TABLE_LIST *all_tables);
void mysql_ha_rm_tables(THD *thd, TABLE_LIST *tables);
void mysql_ha_cleanup(THD *thd);
-void mysql_ha_move_tickets_after_trans_sentinel(THD *thd);
+void mysql_ha_set_explicit_lock_duration(THD *thd);
#endif /* SQL_HANDLER_INCLUDED */
=== modified file 'sql/sql_insert.cc'
--- a/sql/sql_insert.cc 2010-10-27 10:39:04 +0000
+++ b/sql/sql_insert.cc 2010-11-03 14:30:33 +0000
@@ -591,12 +591,7 @@ bool open_and_lock_for_insert_delayed(TH
this or another tables (updating the same table is of course illegal,
but such an attempt can be discovered only later during statement
execution).
-
- Move ticket protecting from a GRL to the front of ticket list.
- This allows to find it quickly when this lock has to be released
- at the end of statement.
*/
- thd->mdl_context.move_ticket_to_front(protection_request.ticket);
/*
Reset the ticket in case we end up having to use normal insert and
@@ -2120,7 +2115,7 @@ bool delayed_get_table(THD *thd, MDL_req
di->table_list.db= di->thd.db;
/* We need the tickets so that they can be cloned in handle_delayed_insert */
di->grl_protection.init(MDL_key::GLOBAL, "", "",
- MDL_INTENTION_EXCLUSIVE);
+ MDL_INTENTION_EXCLUSIVE, MDL_STATEMENT);
di->grl_protection.ticket= grl_protection_request->ticket;
init_mdl_requests(&di->table_list);
di->table_list.mdl_request.ticket= table_list->mdl_request.ticket;
=== modified file 'sql/sql_parse.cc'
--- a/sql/sql_parse.cc 2010-10-26 04:25:15 +0000
+++ b/sql/sql_parse.cc 2010-11-03 14:30:33 +0000
@@ -1085,7 +1085,7 @@ bool dispatch_command(enum enum_server_c
SHOW statements should not add the used tables to the list of tables
used in a transaction.
*/
- MDL_ticket *mdl_savepoint= thd->mdl_context.mdl_savepoint();
+ MDL_savepoint mdl_savepoint= thd->mdl_context.mdl_savepoint();
status_var_increment(thd->status_var.com_stat[SQLCOM_SHOW_FIELDS]);
if (thd->copy_db_to(&db.str, &db.length))
@@ -4362,7 +4362,7 @@ finish:
}
else if (! thd->in_sub_stmt && !thd->locked_tables_mode)
{
- thd->global_read_lock.release_protection_if_set(thd);
+ thd->mdl_context.release_statement_locks();
}
DBUG_RETURN(res || thd->is_error());
@@ -5826,7 +5826,8 @@ TABLE_LIST *st_select_lex::add_table_to_
ptr->next_name_resolution_table= NULL;
/* Link table in global list (all used tables) */
lex->add_to_query_tables(ptr);
- ptr->mdl_request.init(MDL_key::TABLE, ptr->db, ptr->table_name, mdl_type);
+ ptr->mdl_request.init(MDL_key::TABLE, ptr->db, ptr->table_name, mdl_type,
+ MDL_TRANSACTION);
DBUG_RETURN(ptr);
}
=== modified file 'sql/sql_prepare.cc'
--- a/sql/sql_prepare.cc 2010-08-18 09:35:41 +0000
+++ b/sql/sql_prepare.cc 2010-11-03 14:30:33 +0000
@@ -3168,7 +3168,6 @@ bool Prepared_statement::prepare(const c
bool error;
Statement stmt_backup;
Query_arena *old_stmt_arena;
- MDL_ticket *mdl_savepoint= NULL;
DBUG_ENTER("Prepared_statement::prepare");
/*
If this is an SQLCOM_PREPARE, we also increase Com_prepare_sql.
@@ -3240,7 +3239,7 @@ bool Prepared_statement::prepare(const c
Marker used to release metadata locks acquired while the prepared
statement is being checked.
*/
- mdl_savepoint= thd->mdl_context.mdl_savepoint();
+ MDL_savepoint mdl_savepoint= thd->mdl_context.mdl_savepoint();
/*
The only case where we should have items in the thd->free_list is
=== modified file 'sql/sql_show.cc'
--- a/sql/sql_show.cc 2010-10-14 16:56:56 +0000
+++ b/sql/sql_show.cc 2010-11-03 14:30:33 +0000
@@ -675,7 +675,7 @@ mysqld_show_create(THD *thd, TABLE_LIST
Metadata locks taken during SHOW CREATE should be released when
the statmement completes as it is an information statement.
*/
- MDL_ticket *mdl_savepoint= thd->mdl_context.mdl_savepoint();
+ MDL_savepoint mdl_savepoint= thd->mdl_context.mdl_savepoint();
/* We want to preserve the tree for views. */
thd->lex->view_prepare_mode= TRUE;
@@ -3190,7 +3190,7 @@ try_acquire_high_prio_shared_mdl_lock(TH
{
bool error;
table->mdl_request.init(MDL_key::TABLE, table->db, table->table_name,
- MDL_SHARED_HIGH_PRIO);
+ MDL_SHARED_HIGH_PRIO, MDL_TRANSACTION);
if (can_deadlock)
{
@@ -7749,7 +7749,7 @@ bool show_create_trigger(THD *thd, const
Metadata locks taken during SHOW CREATE TRIGGER should be released when
the statement completes as it is an information statement.
*/
- MDL_ticket *mdl_savepoint= thd->mdl_context.mdl_savepoint();
+ MDL_savepoint mdl_savepoint= thd->mdl_context.mdl_savepoint();
/*
Open the table by name in order to load Table_triggers_list object.
=== modified file 'sql/sql_table.cc'
--- a/sql/sql_table.cc 2010-10-18 12:33:49 +0000
+++ b/sql/sql_table.cc 2010-11-03 14:30:33 +0000
@@ -5579,7 +5579,6 @@ bool mysql_alter_table(THD *thd,char *ne
TABLE *table, *new_table= 0;
MDL_ticket *mdl_ticket;
MDL_request target_mdl_request;
- bool has_target_mdl_lock= FALSE;
int error= 0;
char tmp_name[80],old_name[32],new_name_buff[FN_REFLEN + 1];
char new_alias_buff[FN_REFLEN], *table_name, *db, *new_alias, *alias;
@@ -5741,7 +5740,7 @@ bool mysql_alter_table(THD *thd,char *ne
else
{
target_mdl_request.init(MDL_key::TABLE, new_db, new_name,
- MDL_EXCLUSIVE);
+ MDL_EXCLUSIVE, MDL_TRANSACTION);
/*
Global intention exclusive lock must have been already acquired when
table to be altered was open, so there is no need to do it here.
@@ -5759,7 +5758,6 @@ bool mysql_alter_table(THD *thd,char *ne
DBUG_RETURN(TRUE);
}
DEBUG_SYNC(thd, "locked_table_name");
- has_target_mdl_lock= TRUE;
/*
Table maybe does not exist, but we got an exclusive lock
on the name, now we can safely try to find out for sure.
@@ -5946,10 +5944,7 @@ bool mysql_alter_table(THD *thd,char *ne
along with the implicit commit.
*/
if (new_name != table_name || new_db != db)
- {
- thd->mdl_context.release_lock(target_mdl_request.ticket);
thd->mdl_context.release_all_locks_for_name(mdl_ticket);
- }
else
mdl_ticket->downgrade_exclusive_lock(MDL_SHARED_NO_READ_WRITE);
}
@@ -6654,10 +6649,7 @@ bool mysql_alter_table(THD *thd,char *ne
thd->locked_tables_mode == LTM_PRELOCKED_UNDER_LOCK_TABLES)
{
if ((new_name != table_name || new_db != db))
- {
- thd->mdl_context.release_lock(target_mdl_request.ticket);
thd->mdl_context.release_all_locks_for_name(mdl_ticket);
- }
else
mdl_ticket->downgrade_exclusive_lock(MDL_SHARED_NO_READ_WRITE);
}
@@ -6718,8 +6710,6 @@ err:
alter_info->datetime_field->field_name);
thd->abort_on_warning= save_abort_on_warning;
}
- if (has_target_mdl_lock)
- thd->mdl_context.release_lock(target_mdl_request.ticket);
DBUG_RETURN(TRUE);
@@ -6731,9 +6721,6 @@ err_with_mdl:
tables and release the exclusive metadata lock.
*/
thd->locked_tables_list.unlink_all_closed_tables(thd, NULL, 0);
- if (has_target_mdl_lock)
- thd->mdl_context.release_lock(target_mdl_request.ticket);
-
thd->mdl_context.release_all_locks_for_name(mdl_ticket);
DBUG_RETURN(TRUE);
}
=== modified file 'sql/table.cc'
--- a/sql/table.cc 2010-10-04 12:42:16 +0000
+++ b/sql/table.cc 2010-11-03 14:30:33 +0000
@@ -5219,7 +5219,8 @@ void init_mdl_requests(TABLE_LIST *table
table_list->mdl_request.init(MDL_key::TABLE,
table_list->db, table_list->table_name,
table_list->lock_type >= TL_WRITE_ALLOW_WRITE ?
- MDL_SHARED_WRITE : MDL_SHARED_READ);
+ MDL_SHARED_WRITE : MDL_SHARED_READ,
+ MDL_TRANSACTION);
}
=== modified file 'sql/table.h'
--- a/sql/table.h 2010-10-06 14:34:28 +0000
+++ b/sql/table.h 2010-11-03 14:30:33 +0000
@@ -1384,7 +1384,8 @@ struct TABLE_LIST
lock_type= lock_type_arg;
mdl_request.init(MDL_key::TABLE, db, table_name,
(lock_type >= TL_WRITE_ALLOW_WRITE) ?
- MDL_SHARED_WRITE : MDL_SHARED_READ);
+ MDL_SHARED_WRITE : MDL_SHARED_READ,
+ MDL_TRANSACTION);
}
/*
=== modified file 'sql/transaction.cc'
--- a/sql/transaction.cc 2010-10-28 19:35:28 +0000
+++ b/sql/transaction.cc 2010-11-03 14:30:33 +0000
@@ -392,15 +392,15 @@ bool trans_savepoint(THD *thd, LEX_STRIN
thd->transaction.savepoints= newsv;
/*
- Remember the last acquired lock before the savepoint was set.
- This is used as a marker to only release locks acquired after
+ Remember locks acquired before the savepoint was set.
+ They are used as a marker to only release locks acquired after
the setting of this savepoint.
Note: this works just fine if we're under LOCK TABLES,
since mdl_savepoint() is guaranteed to be beyond
the last locked table. This allows to release some
locks acquired during LOCK TABLES.
*/
- newsv->mdl_savepoint = thd->mdl_context.mdl_savepoint();
+ newsv->mdl_savepoint= thd->mdl_context.mdl_savepoint();
DBUG_RETURN(FALSE);
}
@@ -655,7 +655,8 @@ bool trans_xa_commit(THD *thd)
We allow FLUSHer to COMMIT; we assume FLUSHer knows what it does.
*/
- mdl_request.init(MDL_key::COMMIT, "", "", MDL_INTENTION_EXCLUSIVE);
+ mdl_request.init(MDL_key::COMMIT, "", "", MDL_INTENTION_EXCLUSIVE,
+ MDL_TRANSACTION);
if (thd->mdl_context.acquire_lock(&mdl_request,
thd->variables.lock_wait_timeout))
No bundle (reason: useless for push emails).
| Thread |
|---|
| • bzr push into mysql-5.5-runtime branch (Dmitry.Lenev:3186 to 3187) | Dmitry Lenev | 3 Nov |