mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 20:12:31 +01:00
post-review fixes
This commit is contained in:
parent
3f4aa5f707
commit
4b10971a3a
1 changed files with 43 additions and 30 deletions
|
@ -229,7 +229,7 @@ struct st_table_lock {
|
||||||
#define hash_insert my_hash_insert /* for consistency :) */
|
#define hash_insert my_hash_insert /* for consistency :) */
|
||||||
|
|
||||||
static inline
|
static inline
|
||||||
TABLE_LOCK *find_loid(LOCKED_TABLE *table, uint16 loid)
|
TABLE_LOCK *find_by_loid(LOCKED_TABLE *table, uint16 loid)
|
||||||
{
|
{
|
||||||
return (TABLE_LOCK *)hash_search(& table->latest_locks,
|
return (TABLE_LOCK *)hash_search(& table->latest_locks,
|
||||||
(byte *)& loid, sizeof(loid));
|
(byte *)& loid, sizeof(loid));
|
||||||
|
@ -286,7 +286,7 @@ tablockman_getlock(TABLOCKMAN *lm, TABLE_LOCK_OWNER *lo,
|
||||||
|
|
||||||
pthread_mutex_lock(& table->mutex);
|
pthread_mutex_lock(& table->mutex);
|
||||||
/* do we already have a lock on this resource ? */
|
/* do we already have a lock on this resource ? */
|
||||||
old= find_loid(table, lo->loid);
|
old= find_by_loid(table, lo->loid);
|
||||||
|
|
||||||
/* calculate the level of the upgraded lock, if yes */
|
/* calculate the level of the upgraded lock, if yes */
|
||||||
new_lock= old ? lock_combining_matrix[old->lock_type][lock] : lock;
|
new_lock= old ? lock_combining_matrix[old->lock_type][lock] : lock;
|
||||||
|
@ -340,37 +340,50 @@ tablockman_getlock(TABLOCKMAN *lm, TABLE_LOCK_OWNER *lo,
|
||||||
{
|
{
|
||||||
/* found! */
|
/* found! */
|
||||||
wait_for= tmp;
|
wait_for= tmp;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
/*
|
||||||
|
hmm, the lock before doesn't block us, let's look one step further.
|
||||||
|
the condition below means:
|
||||||
|
|
||||||
|
if we never waited on a condition yet
|
||||||
|
OR
|
||||||
|
the lock before ours (blocker) waits on a lock (blocker2) that is
|
||||||
|
present in the hash AND and conflicts with 'blocker'
|
||||||
|
|
||||||
|
the condition after OR may fail if 'blocker2' was removed from
|
||||||
|
the hash, its signal woke us up, but 'blocker' itself didn't see
|
||||||
|
the signal yet.
|
||||||
|
*/
|
||||||
|
if (!lo->waiting_lock ||
|
||||||
|
((blocker2= find_by_loid(table, tmp->waiting_for_loid)) &&
|
||||||
|
!lock_compatibility_matrix[blocker2->lock_type]
|
||||||
|
[blocker->lock_type]))
|
||||||
{
|
{
|
||||||
|
/* but it's waiting for a real lock. we'll wait for the same lock */
|
||||||
|
wait_for= tmp->waiting_for;
|
||||||
/*
|
/*
|
||||||
hmm, the lock before doesn't block us, let's look one step further.
|
We don't really need tmp->waiting_for, as tmp->waiting_for_loid
|
||||||
the condition below means:
|
is enough. waiting_for is just a local cache to avoid calling
|
||||||
|
loid_to_tlo().
|
||||||
if we never waited on a condition yet
|
But it's essensial that tmp->waiting_for pointer can ONLY
|
||||||
OR
|
be dereferenced if find_by_loid() above returns a non-null
|
||||||
the lock before ours (blocker) waits on a lock (blocker2) that is
|
pointer, because a TABLE_LOCK_OWNER object that it points to
|
||||||
present in the hash AND and conflicts with 'blocker'
|
may've been freed when we come here after a signal.
|
||||||
|
In particular tmp->waiting_for_loid cannot be replaced
|
||||||
the condition after OR may fail if 'blocker2' was removed from
|
with tmp->waiting_for->loid.
|
||||||
the hash, its signal woke us up, but 'blocker' itself didn't see
|
|
||||||
the signal yet.
|
|
||||||
*/
|
|
||||||
if (!lo->waiting_lock ||
|
|
||||||
((blocker2= find_loid(table, tmp->waiting_for_loid)) &&
|
|
||||||
!lock_compatibility_matrix[blocker2->lock_type]
|
|
||||||
[blocker->lock_type]))
|
|
||||||
{
|
|
||||||
/* but it's waiting for a real lock. we'll wait for the same lock */
|
|
||||||
wait_for= tmp->waiting_for;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
otherwise - a lock it's waiting for doesn't exist.
|
|
||||||
We've no choice but to scan the wait queue backwards, looking
|
|
||||||
for a conflicting lock or a lock waiting for a real lock.
|
|
||||||
QQ is there a way to avoid this scanning ?
|
|
||||||
*/
|
*/
|
||||||
|
DBUG_ASSERT(wait_for == lm->loid_to_tlo(tmp->waiting_for_loid));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
otherwise - a lock it's waiting for doesn't exist.
|
||||||
|
We've no choice but to scan the wait queue backwards, looking
|
||||||
|
for a conflicting lock or a lock waiting for a real lock.
|
||||||
|
QQ is there a way to avoid this scanning ?
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -531,8 +544,8 @@ void tablockman_release_locks(TABLOCKMAN *lm, TABLE_LOCK_OWNER *lo)
|
||||||
transactions are awaken. But if trn2 times out, trn3 must be notified
|
transactions are awaken. But if trn2 times out, trn3 must be notified
|
||||||
too (as IS and S locks are compatible). So trn2 must signal trn1->cond.
|
too (as IS and S locks are compatible). So trn2 must signal trn1->cond.
|
||||||
*/
|
*/
|
||||||
if (lock->prev &&
|
if (lock->next &&
|
||||||
lock_compatibility_matrix[lock->prev->lock_type][lock->lock_type])
|
lock_compatibility_matrix[lock->next->lock_type][lock->lock_type])
|
||||||
{
|
{
|
||||||
pthread_mutex_lock(lo->waiting_for->mutex);
|
pthread_mutex_lock(lo->waiting_for->mutex);
|
||||||
pthread_cond_broadcast(lo->waiting_for->cond);
|
pthread_cond_broadcast(lo->waiting_for->cond);
|
||||||
|
|
Loading…
Reference in a new issue