#At file:///opt/local/work/next-4284-stage/ based on revid:kostja@stripped
3068 Konstantin Osipov 2010-01-28
Bug#46272, review fixes.
modified:
sql/mdl.cc
sql/mdl.h
=== modified file 'sql/mdl.cc'
--- a/sql/mdl.cc 2010-01-27 21:44:28 +0000
+++ b/sql/mdl.cc 2010-01-28 09:35:54 +0000
@@ -630,8 +630,6 @@ void MDL_lock::destroy(MDL_lock *lock)
}
-
-
/**
Auxiliary functions needed for creation/destruction of MDL_ticket
objects.
@@ -938,6 +936,7 @@ const uchar MDL_object_lock::m_granted_i
MDL_BIT(MDL_SHARED)
};
+
const uchar MDL_object_lock::m_waiting_incompatible[MDL_TYPE_END] =
{
0,
@@ -1211,22 +1210,42 @@ MDL_context::acquire_lock(MDL_request *m
/**
Try to acquire one lock.
+ Unlike exclusive locks, shared locks are acquired one by
+ one. This is interface is chosen to simplify introduction of
+ the new locking API to the system. MDL_context::try_acquire_lock()
+ is currently used from open_table(), and there we have only one
+ table to work with.
+
+ This function may also be used to try to acquire an exclusive
+ lock on a destination table, by ALTER TABLE ... RENAME.
+
+ Returns immediately without any side effect if encounters a lock
+ conflict. Otherwise takes the lock.
+
+ FIXME: Compared to lock_table_name_if_not_cached() (from 5.1)
+ it gives slightly more false negatives.
+
@param mdl_request [in/out] Lock request object for lock to be acquired
@retval FALSE Success. The lock may have not been acquired.
Check the ticket, if it's NULL, a conflicting lock
- exists.
+ exists and another attempt should be made after releasing
+ all current locks and waiting for conflicting lock go
+ away (using MDL_context::wait_for_lock()).
@retval TRUE Out of resources, an error has been reported.
*/
bool
-MDL_context::try_acquire_lock_impl(MDL_request *mdl_request)
+MDL_context::try_acquire_lock(MDL_request *mdl_request)
{
MDL_lock *lock;
MDL_key *key= &mdl_request->key;
MDL_ticket *ticket;
bool is_transactional;
+ DBUG_ASSERT(mdl_request->type < MDL_SHARED_NO_WRITE ||
+ (is_lock_owner(MDL_key::GLOBAL, "", "", MDL_INTENTION_EXCLUSIVE)
+ && ! is_lock_owner(MDL_key::GLOBAL, "", "", MDL_SHARED)));
DBUG_ASSERT(mdl_request->ticket == NULL);
/* Don't take chances in production. */
@@ -1302,45 +1321,6 @@ MDL_context::try_acquire_lock_impl(MDL_r
/**
- Try to acquire one lock.
-
- Unlike exclusive locks, shared locks are acquired one by
- one. This is interface is chosen to simplify introduction of
- the new locking API to the system. MDL_context::try_acquire_lock()
- is currently used from open_table(), and there we have only one
- table to work with.
-
- This function may also be used to try to acquire an exclusive
- lock on a destination table, by ALTER TABLE ... RENAME.
-
- Returns immediately without any side effect if encounters a lock
- conflict. Otherwise takes the lock.
-
- FIXME: Compared to lock_table_name_if_not_cached() (from 5.1)
- it gives slightly more false negatives.
-
- @param mdl_request [in/out] Lock request object for lock to be acquired
-
- @retval FALSE Success. The lock may have not been acquired.
- Check the ticket, if it's NULL, a conflicting lock
- exists and another attempt should be made after releasing
- all current locks and waiting for conflicting lock go
- away (using MDL_context::wait_for_lock()).
- @retval TRUE Out of resources, an error has been reported.
-*/
-
-bool
-MDL_context::try_acquire_lock(MDL_request *mdl_request)
-{
- DBUG_ASSERT(mdl_request->type < MDL_SHARED_NO_WRITE ||
- (is_lock_owner(MDL_key::GLOBAL, "", "", MDL_INTENTION_EXCLUSIVE)
- && ! is_lock_owner(MDL_key::GLOBAL, "", "", MDL_SHARED)));
-
- return try_acquire_lock_impl(mdl_request);
-}
-
-
-/**
Create a copy of a granted ticket.
This is used to make sure that HANDLER ticket
is never shared with a ticket that belongs to
@@ -1382,6 +1362,7 @@ MDL_context::clone_ticket(MDL_request *m
return FALSE;
}
+
/**
Notify a thread holding a shared metadata lock which
conflicts with a pending exclusive lock.
@@ -1418,6 +1399,8 @@ void notify_shared_lock(THD *thd, MDL_ti
Auxiliary method for acquiring an exclusive lock.
@param mdl_request Request for the lock to be acqured.
+ @param is_upgrade Are we trying to upgrade a shared
+ lock to exclusive?
@note Should not be used outside of MDL subsystem. Instead one should
call acquire_exclusive_lock() or acquire_exclusive_locks() methods
@@ -1428,7 +1411,8 @@ void notify_shared_lock(THD *thd, MDL_ti
@retval TRUE Failure
*/
-bool MDL_context::acquire_exclusive_lock_impl(MDL_request *mdl_request)
+bool MDL_context::acquire_exclusive_lock_impl(MDL_request *mdl_request,
+ bool is_upgrade)
{
MDL_lock *lock;
const char *old_msg;
@@ -1477,9 +1461,9 @@ bool MDL_context::acquire_exclusive_lock
old_msg= MDL_ENTER_COND(m_thd, mysys_var, &m_ctx_wakeup_cond,
&lock->m_mutex);
- while (!lock->can_grant_lock(mdl_request->type, FALSE))
+ while (!lock->can_grant_lock(mdl_request->type, is_upgrade))
{
- if (m_trans_sentinel)
+ if (m_trans_sentinel && ! is_upgrade)
{
/*
We're about to start waiting. Don't do it if we have
@@ -1543,7 +1527,7 @@ bool MDL_context::acquire_exclusive_lock
MDL_EXIT_COND(m_thd, mysys_var, &lock->m_mutex, old_msg);
pthread_mutex_lock(&lock->m_mutex);
- /* Get rid of pending ticket. */
+ /* Get rid of the pending ticket. */
lock->remove_pending(ticket);
if (lock->is_empty())
mdl_locks.remove(lock);
@@ -1598,7 +1582,7 @@ bool MDL_context::acquire_exclusive_lock
m_tickets.front()->m_lock->key.mdl_namespace() == MDL_key::GLOBAL &&
++Ticket_list::Iterator(m_tickets) == m_trans_sentinel);
- return acquire_exclusive_lock_impl(mdl_request);
+ return acquire_exclusive_lock_impl(mdl_request, FALSE);
}
@@ -1658,7 +1642,7 @@ bool MDL_context::acquire_exclusive_lock
for (i= 0; i < mdl_requests->elements(); i++)
{
- if (acquire_exclusive_lock_impl(sort_buf[i]))
+ if (acquire_exclusive_lock_impl(sort_buf[i], FALSE))
goto err;
}
my_free(sort_buf, MYF(0));
@@ -1699,16 +1683,12 @@ err:
bool
MDL_context::upgrade_shared_lock_to_exclusive(MDL_ticket *mdl_ticket)
{
- const char *old_msg;
- st_my_thread_var *mysys_var= my_thread_var;
- THD *thd= get_thd();
- MDL_lock *mdl_lock= mdl_ticket->m_lock;
- MDL_ticket *pending_ticket;
+ MDL_request mdl_xlock_request;
+ MDL_ticket *mdl_svp= mdl_savepoint();
+ bool is_new_ticket;
DBUG_ENTER("MDL_ticket::upgrade_shared_lock_to_exclusive");
- DEBUG_SYNC(thd, "mdl_upgrade_shared_lock_to_exclusive");
-
- safe_mutex_assert_not_owner(&LOCK_open);
+ DEBUG_SYNC(get_thd(), "mdl_upgrade_shared_lock_to_exclusive");
/*
Do nothing if already upgraded. Used when we FLUSH TABLE under
@@ -1721,90 +1701,33 @@ 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);
- /*
- Since we should have already acquired an intention exclusive
- global lock this call is only enforcing asserts.
- */
- DBUG_ASSERT(is_lock_owner(MDL_key::GLOBAL, "", "", MDL_INTENTION_EXCLUSIVE)
- && ! is_lock_owner(MDL_key::GLOBAL, "", "", MDL_SHARED));
+ mdl_xlock_request.init(&mdl_ticket->m_lock->key, MDL_EXCLUSIVE);
- /*
- Create an auxiliary ticket to represent a pending exclusive
- lock and add it to the 'waiting' queue for the duration
- of upgrade. During upgrade we abort waits of connections
- that own conflicting locks. A pending request is used
- to signal such connections that upon waking up they
- must back off, rather than fall into sleep again.
- */
- if (! (pending_ticket= MDL_ticket::create(this, MDL_EXCLUSIVE)))
+ if (acquire_exclusive_lock_impl(&mdl_xlock_request, TRUE))
DBUG_RETURN(TRUE);
- pthread_mutex_lock(&mdl_lock->m_mutex);
-
- mdl_lock->add_pending(pending_ticket);
-
- old_msg= MDL_ENTER_COND(thd, mysys_var, &m_ctx_wakeup_cond,
- &mdl_lock->m_mutex);
-
- while (1)
- {
- if (mdl_lock->can_grant_lock(MDL_EXCLUSIVE, TRUE))
- break;
-
- mdl_lock->notify_shared_locks(this);
-
- /* There is a shared or exclusive lock on the object. */
- DEBUG_SYNC(thd, "mdl_upgrade_shared_lock_to_exclusive_wait");
-
- /*
- Another thread might have obtained a shared MDL lock on some table
- but has not yet opened it and/or tried to obtain data lock on it.
- Also invocation of acquire_exclusive_lock() method and consequently
- first call to notify_shared_lock() might have happened right after
- thread holding shared metadata lock in wait_for_locks() method
- checked that there are no pending conflicting locks but before
- it has started waiting.
- In both these cases we need to sleep until these threads will start
- waiting and try to abort them once again.
- */
- struct timespec abstime;
- set_timespec(abstime, 1);
- pthread_cond_timedwait(&m_ctx_wakeup_cond, &mdl_lock->m_mutex,
- &abstime);
-
- if (mysys_var->abort)
- {
- mdl_lock->remove_pending(pending_ticket);
- /*
- If there are no other pending requests for exclusive locks
- we need to wake up threads waiting for a chance to acquire
- shared lock.
- */
- mdl_lock->wake_up_waiters();
- MDL_EXIT_COND(thd, mysys_var, &mdl_lock->m_mutex, old_msg);
- MDL_ticket::destroy(pending_ticket);
- DBUG_RETURN(TRUE);
- }
- }
+ is_new_ticket= ! has_lock(mdl_svp, mdl_xlock_request.ticket);
+ /* Merge the acquired and the original lock. @todo: move to a method. */
+ pthread_mutex_lock(&mdl_ticket->m_lock->m_mutex);
+ if (is_new_ticket)
+ mdl_ticket->m_lock->remove_granted(mdl_xlock_request.ticket);
/*
- Set the new type of lock in the ticket. To update state of MDL_lock object
- correctly we need to temporarily exclude ticket from the granted queue and
- then include it back.
+ Set the new type of lock in the ticket. To update state of
+ MDL_lock object correctly we need to temporarily exclude
+ ticket from the granted queue and then include it back.
*/
- mdl_lock->remove_granted(mdl_ticket);
+ mdl_ticket->m_lock->remove_granted(mdl_ticket);
mdl_ticket->m_type= MDL_EXCLUSIVE;
- mdl_lock->add_granted(mdl_ticket);
-
- mdl_lock->remove_pending(pending_ticket);
-
- if (mdl_lock->cached_object)
- (*mdl_lock->cached_object_release_hook)(mdl_lock->cached_object);
- mdl_lock->cached_object= 0;
+ mdl_ticket->m_lock->add_granted(mdl_ticket);
- MDL_EXIT_COND(thd, mysys_var, &mdl_lock->m_mutex, old_msg);
+ pthread_mutex_unlock(&mdl_ticket->m_lock->m_mutex);
- MDL_ticket::destroy(pending_ticket);
+ if (is_new_ticket)
+ {
+ m_tickets.remove(mdl_xlock_request.ticket);
+ MDL_ticket::destroy(mdl_xlock_request.ticket);
+ }
DBUG_RETURN(FALSE);
}
@@ -2248,18 +2171,27 @@ void MDL_context::release_transactional_
bool MDL_context::has_lock(MDL_ticket *mdl_savepoint,
MDL_ticket *mdl_ticket)
{
- /* Adjust the savepoint to take into account m_trans_sentinel. */
- MDL_context::Ticket_iterator it(m_tickets, mdl_savepoint ?
- mdl_savepoint : m_trans_sentinel);
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;
- /* Start iteration from the savepoint. */
while ((ticket= it++) && ticket != m_trans_sentinel)
{
+ /*
+ 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 TRUE;
+ return found_savepoint;
}
- /* The ticket is either before the savepoint or LT, HA or GRL ticket. */
+ /* Reached m_trans_sentinel. The ticket must be LT, HA or GRL ticket. */
return FALSE;
}
=== modified file 'sql/mdl.h'
--- a/sql/mdl.h 2010-01-27 21:44:28 +0000
+++ b/sql/mdl.h 2010-01-28 09:35:54 +0000
@@ -616,9 +616,7 @@ private:
MDL_ticket *find_ticket(MDL_request *mdl_req,
bool *is_transactional);
void release_locks_stored_before(MDL_ticket *sentinel);
-
- bool try_acquire_lock_impl(MDL_request *mdl_request);
- bool acquire_exclusive_lock_impl(MDL_request *mdl_request);
+ bool acquire_exclusive_lock_impl(MDL_request *mdl_request, bool is_upgrade);
private:
MDL_context(const MDL_context &rhs); /* not implemented */
MDL_context &operator=(MDL_context &rhs); /* not implemented */
Attachment: [text/bzr-bundle] bzr/kostja@sun.com-20100128093554-nq59oqiha8gjvkb3.bundle
| Thread |
|---|
| • bzr commit into mysql-5.6-next-mr branch (kostja:3068) Bug#46272 | Konstantin Osipov | 28 Jan |