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); }
相关文章推荐
- InnoDB实现4种事务的隔离级别
- InnoDB---事务和并发控制相关的文件
- Innodb引擎中事务使用
- Innodb read only事务、MySQL5.7和Percona的事务改进
- Mysql事务以及四中隔离级别实例2以及InnoDB如何解决当时读的幻读问题
- 查看事务锁:innodb_trx+innodb_locks+innodb_lock_waits
- InnoDB事务锁之行锁-insert二级索引加锁原理图
- InnoDB事务锁之行锁-insert唯一二级索引-隐式锁转换案例
- InnoDB事务和锁
- InnoDB,锁,事务。
- mysql事务和innodb锁
- MySQL Innodb如何找出阻塞事务源头SQL
- MySQL InnoDB四个事务级别 与 脏读、不重复读、幻读
- MyISAM 和InnoDB 的区别.(存储,索引, 事务, 锁)
- InnoDB 事务锁系统简介
- Mysql InnoDB事务
- mysql事务和锁InnoDB
- mysql的innodb中事务日志ib_logfile
- innodb中的事务的一则应用
- InnoDB事务锁之行锁--聚集索引加锁流程