summaryrefslogtreecommitdiff
path: root/sql/mdl.cc
diff options
context:
space:
mode:
authorSergei Golubchik <sergii@pisem.net>2012-10-16 13:04:42 +0200
committerSergei Golubchik <sergii@pisem.net>2012-10-16 13:04:42 +0200
commitee9afef27141f55165009fdbd58e54942f3a6867 (patch)
treeb5e15e62e10daa40aef3e6d33eeabf9205d1be0f /sql/mdl.cc
parentd9a8799205d160688f81362356dd2323eb8a91ea (diff)
parenta619bfad30c13207fb0453a85af5740846186900 (diff)
downloadmariadb-git-ee9afef27141f55165009fdbd58e54942f3a6867.tar.gz
mysql-5.5.28
Diffstat (limited to 'sql/mdl.cc')
-rw-r--r--sql/mdl.cc120
1 files changed, 112 insertions, 8 deletions
diff --git a/sql/mdl.cc b/sql/mdl.cc
index ca552a540b9..5e297051377 100644
--- a/sql/mdl.cc
+++ b/sql/mdl.cc
@@ -378,7 +378,8 @@ public:
bool has_pending_conflicting_lock(enum_mdl_type type);
- bool can_grant_lock(enum_mdl_type type, MDL_context *requstor_ctx) const;
+ bool can_grant_lock(enum_mdl_type type, MDL_context *requstor_ctx,
+ bool ignore_lock_priority) const;
inline static MDL_lock *create(const MDL_key *key);
@@ -392,14 +393,24 @@ public:
virtual bool needs_notification(const MDL_ticket *ticket) const = 0;
virtual void notify_conflicting_locks(MDL_context *ctx) = 0;
+ virtual bitmap_t hog_lock_types_bitmap() const = 0;
+
/** List of granted tickets for this lock. */
Ticket_list m_granted;
/** Tickets for contexts waiting to acquire a lock. */
Ticket_list m_waiting;
+
+ /**
+ Number of times high priority lock requests have been granted while
+ low priority lock requests were waiting.
+ */
+ ulong m_hog_lock_count;
+
public:
MDL_lock(const MDL_key *key_arg)
: key(key_arg),
+ m_hog_lock_count(0),
m_ref_usage(0),
m_ref_release(0),
m_is_destroyed(FALSE),
@@ -484,6 +495,15 @@ public:
}
virtual void notify_conflicting_locks(MDL_context *ctx);
+ /*
+ In scoped locks, only IX lock request would starve because of X/S. But that
+ is practically very rare case. So just return 0 from this function.
+ */
+ virtual bitmap_t hog_lock_types_bitmap() const
+ {
+ return 0;
+ }
+
private:
static const bitmap_t m_granted_incompatible[MDL_TYPE_END];
static const bitmap_t m_waiting_incompatible[MDL_TYPE_END];
@@ -536,6 +556,18 @@ public:
}
virtual void notify_conflicting_locks(MDL_context *ctx);
+ /*
+ To prevent starvation, these lock types that are only granted
+ max_write_lock_count times in a row while other lock types are
+ waiting.
+ */
+ virtual bitmap_t hog_lock_types_bitmap() const
+ {
+ return (MDL_BIT(MDL_SHARED_NO_WRITE) |
+ MDL_BIT(MDL_SHARED_NO_READ_WRITE) |
+ MDL_BIT(MDL_EXCLUSIVE));
+ }
+
private:
static const bitmap_t m_granted_incompatible[MDL_TYPE_END];
static const bitmap_t m_waiting_incompatible[MDL_TYPE_END];
@@ -1268,6 +1300,41 @@ void MDL_lock::reschedule_waiters()
{
MDL_lock::Ticket_iterator it(m_waiting);
MDL_ticket *ticket;
+ bool skip_high_priority= false;
+ bitmap_t hog_lock_types= hog_lock_types_bitmap();
+
+ if (m_hog_lock_count >= max_write_lock_count)
+ {
+ /*
+ If number of successively granted high-prio, strong locks has exceeded
+ max_write_lock_count give a way to low-prio, weak locks to avoid their
+ starvation.
+ */
+
+ if ((m_waiting.bitmap() & ~hog_lock_types) != 0)
+ {
+ /*
+ Even though normally when m_hog_lock_count is non-0 there is
+ some pending low-prio lock, we still can encounter situation
+ when m_hog_lock_count is non-0 and there are no pending low-prio
+ locks. This, for example, can happen when a ticket for pending
+ low-prio lock was removed from waiters list due to timeout,
+ and reschedule_waiters() is called after that to update the
+ waiters queue. m_hog_lock_count will be reset to 0 at the
+ end of this call in such case.
+
+ Note that it is not an issue if we fail to wake up any pending
+ waiters for weak locks in the loop below. This would mean that
+ all of them are either killed, timed out or chosen as a victim
+ by deadlock resolver, but have not managed to remove ticket
+ from the waiters list yet. After tickets will be removed from
+ the waiters queue there will be another call to
+ reschedule_waiters() with pending bitmap updated to reflect new
+ state of waiters queue.
+ */
+ skip_high_priority= true;
+ }
+ }
/*
Find the first (and hence the oldest) waiting request which
@@ -1289,7 +1356,16 @@ void MDL_lock::reschedule_waiters()
*/
while ((ticket= it++))
{
- if (can_grant_lock(ticket->get_type(), ticket->get_ctx()))
+ /*
+ Skip high-prio, strong locks if earlier we have decided to give way to
+ low-prio, weaker locks.
+ */
+ if (skip_high_priority &&
+ ((MDL_BIT(ticket->get_type()) & hog_lock_types) != 0))
+ continue;
+
+ if (can_grant_lock(ticket->get_type(), ticket->get_ctx(),
+ skip_high_priority))
{
if (! ticket->get_ctx()->m_wait.set_status(MDL_wait::GRANTED))
{
@@ -1303,6 +1379,13 @@ void MDL_lock::reschedule_waiters()
*/
m_waiting.remove_ticket(ticket);
m_granted.add_ticket(ticket);
+
+ /*
+ Increase counter of successively granted high-priority strong locks,
+ if we have granted one.
+ */
+ if ((MDL_BIT(ticket->get_type()) & hog_lock_types) != 0)
+ m_hog_lock_count++;
}
/*
If we could not update the wait slot of the waiter,
@@ -1314,6 +1397,24 @@ void MDL_lock::reschedule_waiters()
*/
}
}
+
+ if ((m_waiting.bitmap() & ~hog_lock_types) == 0)
+ {
+ /*
+ Reset number of successively granted high-prio, strong locks
+ if there are no pending low-prio, weak locks.
+ This ensures:
+ - That m_hog_lock_count is correctly reset after strong lock
+ is released and weak locks are granted (or there are no
+ other lock requests).
+ - That situation when SNW lock is granted along with some SR
+ locks, but SW locks are still blocked are handled correctly.
+ - That m_hog_lock_count is zero in most cases when there are no pending
+ weak locks (see comment at the start of this method for example of
+ exception). This allows to save on checks at the start of this method.
+ */
+ m_hog_lock_count= 0;
+ }
}
@@ -1468,8 +1569,9 @@ MDL_object_lock::m_waiting_incompatible[MDL_TYPE_END] =
Check if request for the metadata lock can be satisfied given its
current state.
- @param type_arg The requested lock type.
- @param requestor_ctx The MDL context of the requestor.
+ @param type_arg The requested lock type.
+ @param requestor_ctx The MDL context of the requestor.
+ @param ignore_lock_priority Ignore lock priority.
@retval TRUE Lock request can be satisfied
@retval FALSE There is some conflicting lock.
@@ -1481,19 +1583,21 @@ MDL_object_lock::m_waiting_incompatible[MDL_TYPE_END] =
bool
MDL_lock::can_grant_lock(enum_mdl_type type_arg,
- MDL_context *requestor_ctx) const
+ MDL_context *requestor_ctx,
+ bool ignore_lock_priority) const
{
bool can_grant= FALSE;
bitmap_t waiting_incompat_map= incompatible_waiting_types_bitmap()[type_arg];
bitmap_t granted_incompat_map= incompatible_granted_types_bitmap()[type_arg];
+
/*
New lock request can be satisfied iff:
- There are no incompatible types of satisfied requests
in other contexts
- There are no waiting requests which have higher priority
- than this request.
+ than this request when priority was not ignored.
*/
- if (! (m_waiting.bitmap() & waiting_incompat_map))
+ if (ignore_lock_priority || !(m_waiting.bitmap() & waiting_incompat_map))
{
if (! (m_granted.bitmap() & granted_incompat_map))
can_grant= TRUE;
@@ -1789,7 +1893,7 @@ MDL_context::try_acquire_lock_impl(MDL_request *mdl_request,
ticket->m_lock= lock;
- if (lock->can_grant_lock(mdl_request->type, this))
+ if (lock->can_grant_lock(mdl_request->type, this, false))
{
lock->m_granted.add_ticket(ticket);