您的位置:首页 > 其它

InnoDB事务锁之行锁--slow lock

2018-01-28 14:06 661 查看
lock_rec_lock_slow(
/*===============*/
ibool			impl,	/*!< in: if TRUE, no lock is set
if no wait is necessary: we
assume that the caller will
set an implicit lock */
ulint			mode,	/*!< in: lock mode: LOCK_X or
LOCK_S possibly ORed to either
LOCK_GAP or LOCK_REC_NOT_GAP */
const buf_block_t*	block,	/*!< in: buffer block containing
the record */
ulint			heap_no,/*!< in: heap number of record */
dict_index_t*		index,	/*!< in: index of record */
que_thr_t*		thr)	/*!< in: query thread */
{

if (lock_rec_has_expl(mode, block, heap_no, trx)) {
//1、在这个记录上个已经有了更强的锁,不用加
//从lock_sys->rec_hash中找到给记录的所有锁,并遍历,判断是否已经有更强
//的锁已经加上,强度判断矩阵函数lock_mode_stronger_or_eq,不包括插入意向锁
} else if (lock_rec_other_has_conflicting(
static_cast<enum lock_mode>(mode),
block, heap_no, trx)) {

err = lock_rec_enqueue_waiting(
mode, block, heap_no, index, thr);

} else if (!impl) {

lock_rec_add_to_queue(
LOCK_REC | mode, block, heap_no, index, trx, TRUE);

err = DB_SUCCESS_LOCKED_REC;
}

return(err);
}

lock_rec_has_to_wait(
/*=================*/
const trx_t*	trx,	/*!< in: trx of new lock */
ulint		type_mode,/*!< in: precise mode of the new lock
to set: LOCK_S or LOCK_X, possibly
ORed to LOCK_GAP or LOCK_REC_NOT_GAP,
LOCK_INSERT_INTENTION */
const lock_t*	lock2,	/*!< in: another record lock; NOTE that
it is assumed that this has a lock bit
set on the same record as in the new
lock we are setting */
ibool lock_is_on_supremum)  /*!< in: TRUE if we are setting the
lock on the 'supremum' record of an
index page: we know then that the lock
request is really for a 'gap' type lock */
{
//锁兼容判断函数lock_mode_compatible
if (trx != lock2->trx
&& !lock_mode_compatible(static_cast<enum lock_mode>(
LOCK_MODE_MASK & type_mode),
lock_get_mode(lock2))) {
//如果是gap锁,有几项更加复杂的规则
//1、没有插入意向标签的gap锁不需要等待
//2、gap锁不需要等待LOCK_ORDINARY和LOCK_REC_NOT_GAP
//3、gap锁包括插入意向锁,不需要等待LOCK_REC_NOT_GAP
//4、任何锁都不需要等待插入意向锁
//注意,插入意向锁需要等待GAP锁
if ((lock_is_on_supremum || (type_mode & LOCK_GAP))
&& !(type_mode & LOCK_INSERT_INTENTION)) {

/* Gap type locks without LOCK_INSERT_INTENTION flag
do not need to wait for anything. This is because
different users can have conflicting lock types
on gaps. */

return(FALSE);
}

if (!(type_mode & LOCK_INSERT_INTENTION)
&& lock_rec_get_gap(lock2)) {

/* Record lock (LOCK_ORDINARY or LOCK_REC_NOT_GAP
does not need to wait for a gap type lock */

return(FALSE);
}

if ((type_mode & LOCK_GAP)
&& lock_rec_get_rec_not_gap(lock2)) {

/* Lock on gap does not need to wait for
a LOCK_REC_NOT_GAP type lock */

return(FALSE);
}

if (lock_rec_get_insert_intention(lock2)) {

/* No lock request needs to wait for an insert
intention lock to be removed. This is ok since our
rules allow conflicting locks on gaps. This eliminates
a spurious deadlock caused by a next-key lock waiting
for an insert intention lock; when the insert
intention lock was granted, the insert deadlocked on
the waiting next-key lock.

Also, insert intention locks do not disturb each
other. */

return(FALSE);
}

return(TRUE);
}

return(FALSE);
}

lock_rec_enqueue_waiting(
/*=====================*/
ulint			type_mode,/*!< in: lock mode this
transaction is requesting:
LOCK_S or LOCK_X, possibly
ORed with LOCK_GAP or
LOCK_REC_NOT_GAP, ORed with
LOCK_INSERT_INTENTION if this
waiting lock request is set
when performing an insert of
an index record */
const buf_block_t*	block,	/*!< in: buffer block containing
the record */
ulint			heap_no,/*!< in: heap number of the record */
dict_index_t*		index,	/*!< in: index of record */
que_thr_t*		thr)	/*!< in: query thread */
{

//1、创建一个LOCK_WAIT类型的锁,并将该锁插入到事务锁链表和锁系统HASH中
lock = lock_rec_create(
type_mode | LOCK_WAIT, block, heap_no, index, trx, TRUE);
//2、死锁检测
victim_trx_id = lock_deadlock_check_and_resolve(lock, trx);

//3、如果发生死锁,并且选择回滚的是本事务,则将该锁的LOCK_WAIT标签去除,并重置bitmap位
if (victim_trx_id != 0) {

lock_reset_lock_and_trx_wait(lock);
lock_rec_reset_nth_bit(lock, heap_no);

return(DB_DEADLOCK);
//4、如果发生死锁,并且选择回滚的是其他事务,则加锁成功:
//什么时候将LOCK_WAIT标签去掉?向上返回错误码,由row_mysql_handle_errors处理
} else if (trx->lock.wait_lock == NULL) {

/* If there was a deadlock but we chose another
transaction as a victim, it is possible that we
already have the lock now granted! */

return(DB_SUCCESS_LOCKED_REC);
}

trx->lock.que_state = TRX_QUE_LOCK_WAIT;
trx->lock.was_chosen_as_deadlock_victim = FALSE;
trx->lock.wait_started = ut_time();
return(DB_LOCK_WAIT);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: