/* QQ: TODO - allocate everything from dynarrays !!! (benchmark) */ /* QQ: automatically place S instead of LS if possible */ /* Copyright (C) 2006 MySQL AB
YoushouldhavereceivedacopyoftheGNUGeneralPublicLicense alongwiththisprogram;ifnot,writetotheFreeSoftware
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
OneshouldnevergetNfromit,weasserttheimpossibility
*/ staticconstenum lockman_lock_type lock_combining_matrix[10][10]=
{/* N S X IS IX SIX LS LX SLX LSIX */
{ N, N, N, N, N, N, N, N, N, N}, /* N */
{ N, S, X, S, SIX, SIX, S, SLX, SLX, SIX}, /* S */
{ N, X, X, X, X, X, X, X, X, X}, /* X */
{ N, S, X, IS, IX, SIX, LS, LX, SLX, LSIX}, /* IS */
{ N, SIX, X, IX, IX, SIX, LSIX, LX, SLX, LSIX}, /* IX */
{ N, SIX, X, SIX, SIX, SIX, SIX, SLX, SLX, SIX}, /* SIX */
{ N, S, X, LS, LSIX, SIX, LS, LX, SLX, LSIX}, /* LS */
{ N, SLX, X, LX, LX, SLX, LX, LX, SLX, LX}, /* LX */
{ N, SLX, X, SLX, SLX, SLX, SLX, SLX, SLX, SLX}, /* SLX */
{ N, SIX, X, LSIX, LSIX, SIX, LSIX, LX, SLX, LSIX} /* LSIX */
};
mysql_mutex_lock(& table->mutex); /* do we already have a lock on this resource ? */
old= find_by_loid(table, lo->loid);
/* calculate the level of the upgraded lock, if yes */
new_lock= old ? lock_combining_matrix[old->lock_type][lock] : lock;
/* and check if old lock is enough to satisfy the new request */ if (old && new_lock == old->lock_type)
{ /* yes */
res= getlock_result[old->lock_type][lock]; goto ret;
}
/* no, placing a new lock. first - take a free lock structure from the pool */
mysql_mutex_lock(& lm->pool_mutex); new= lm->pool; if (new)
{
lm->pool= new->next;
mysql_mutex_unlock(& lm->pool_mutex);
} else
{
mysql_mutex_unlock(& lm->pool_mutex); new= (TABLE_LOCK *)my_malloc(sizeof(*new), MYF(MY_WME)); if (unlikely(!new))
{
res= NO_MEMORY_FOR_LOCK; goto ret;
}
}
/* and try to place it */ for (new->prev= table->wait_queue_in;;)
{
wait_for= 0; if (!old)
{ /* not upgrading - a lock must be added to the _end_ of the wait queue */ for (blocker= new->prev; blocker && !wait_for; blocker= blocker->prev)
{
TABLE_LOCK_OWNER *tmp= lm->loid_to_tlo(blocker->loid);
/* find a blocking lock */
DBUG_ASSERT(table->wait_queue_out);
DBUG_ASSERT(table->wait_queue_in); if (!lock_compatibility_matrix[blocker->lock_type][lock])
{ /* found! */
wait_for= tmp; break;
}
if (wait_for == 0)
{ /* checking for compatibility with existing locks */ for (blocker= 0, i= 0; i < LOCK_TYPES; i++)
{ if (table->active_locks[i] && !lock_compatibility_matrix[i+1][lock])
{
blocker= table->active_locks[i]; /* if the first lock in the list is our own - skip it */ if (blocker->loid == lo->loid)
blocker= blocker->next; if (blocker) /* found a conflicting lock, need to wait */ break;
}
} if (!blocker) /* free to go */ break;
wait_for= lm->loid_to_tlo(blocker->loid);
}
/* ok, we're here - the wait is inevitable */
lo->waiting_for= wait_for;
lo->waiting_for_loid= wait_for->loid; if (!lo->waiting_lock) /* first iteration of the for() loop */
{ /* lock upgrade or new lock request ? */ if (old)
{ /* upgrade - add the lock to the _start_ of the wait queue */ new->prev= 0; if ((new->next= table->wait_queue_out)) new->next->prev= new;
table->wait_queue_out= new; if (!table->wait_queue_in)
table->wait_queue_in= table->wait_queue_out;
} else
{ /* new lock - add the lock to the _end_ of the wait queue */ new->next= 0; if ((new->prev= table->wait_queue_in)) new->prev->next= new;
table->wait_queue_in= new; if (!table->wait_queue_out)
table->wait_queue_out= table->wait_queue_in;
}
lo->waiting_lock= new;
/* now really wait */
i= mysql_cond_timedwait(wait_for->cond, wait_for->mutex, & timeout);
mysql_mutex_unlock(wait_for->mutex);
if (i == ETIMEDOUT || i == ETIME)
{ /* we rely on the caller to rollback and release all locks */
res= LOCK_TIMEOUT; goto ret2;
}
mysql_mutex_lock(& table->mutex);
/* ... and repeat from the beginning */
} /* yeah! we can place the lock now */
/* remove the lock from the wait queue, if it was there */ if (lo->waiting_lock)
{
remove_from_wait_queue(new, table);
lo->waiting_lock= 0;
lo->waiting_for= 0;
lo->waiting_for_loid= 0;
}
/* add it to the list of all locks of this lock owner */ new->next_in_lo= lo->active_locks;
lo->active_locks= new;
/* and to the list of active locks of this lock type */ new->prev= 0; if ((new->next= table->active_locks[new_lock-1])) new->next->prev= new;
table->active_locks[new_lock-1]= new;
/* update the latest_locks hash */ if (old)
my_hash_delete(& table->latest_locks, (uchar *)old);
my_hash_insert(& table->latest_locks, (uchar *)new);
/* release a waiting lock, if any */ if ((lock= lo->waiting_lock))
{
DBUG_ASSERT(lock->loid == lo->loid);
mysql_mutex_lock(& lock->table->mutex);
remove_from_wait_queue(lock, lock->table);
/* TODO ? group locks by table to reduce the number of mutex locks */
mysql_mutex_lock(mutex);
my_hash_delete(& cur->table->latest_locks, (uchar *)cur);
if (cur->prev)
cur->prev->next= cur->next; if (cur->next)
cur->next->prev= cur->prev; if (cur->table->active_locks[cur->lock_type-1] == cur)
cur->table->active_locks[cur->lock_type-1]= cur->next;
/* and push all freed locks to the lockman's pool */
mysql_mutex_lock(& lm->pool_mutex);
local_pool_end->next= lm->pool;
lm->pool= local_pool;
mysql_mutex_unlock(& lm->pool_mutex);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.