Innodb-行锁实现

390 阅读1分钟

信息维护

Innodb在两个维度维护行锁信息,就和文件组织Extent一样。两个维度一个是全局的、一个是事务持有的。 下图右下角Lock_sys就是全局的锁信息,左上角就是事务持有的锁信息。

image.png

全局

/** The lock system struct */
struct lock_sys_t{
	hash_table_t*	rec_hash;		/*!< hash table of the record
};

lock_sys中保存的对象为lock_t,它可以描述一个行锁或者表锁,如果是行锁,会被lock_sys维护,若是表锁,会被对应的dict_table_t维护。

事务持有

struct trx_t {
	trx_lock_t	lock;		/*!< Information about the transaction
					locks and state. Protected by
					trx->mutex or lock_sys->mutex
					or both */
};
struct trx_lock_t {

	lock_t*		wait_lock;	/*!< if trx execution state is
					TRX_QUE_LOCK_WAIT, this points to
					the lock request, otherwise this is
					NULL; set to non-NULL when holding
					both trx->mutex and lock_sys->mutex;
					set to NULL when holding
					lock_sys->mutex; readers should
					hold lock_sys->mutex, except when
					they are holding trx->mutex and
					wait_lock==NULL */

	trx_lock_list_t trx_locks;	/*!< locks requested by the transaction;
					insertions are protected by trx->mutex
					and lock_sys->mutex; removals are
					protected by lock_sys->mutex */

	ulint		n_rec_locks;	/*!< number of rec locks in this trx */

};

struct lock_t {
	trx_t*		trx;		/*!< transaction owning the
					lock */
	UT_LIST_NODE_T(lock_t)
			trx_locks;	/*!< list of the locks of the
					transaction */

	dict_index_t*	index;		/*!< index for a record lock */

	lock_t*		hash;		/*!< hash chain node for a record
					lock. The link node in a singly linked
					list, used during hashing. */

	union {
		lock_table_t	tab_lock;/*!< table lock */
		lock_rec_t	rec_lock;/*!< record lock */
	} un_member;			/*!< lock details */

	ib_uint32_t	type_mode;	/*!< lock type, mode, LOCK_GAP or
					LOCK_REC_NOT_GAP,
					LOCK_INSERT_INTENTION,
					wait flag, ORed */
};
struct lock_rec_t {
	ib_uint32_t	space;		/*!< space id */
	ib_uint32_t	page_no;	/*!< page number */
	ib_uint32_t	n_bits;		/*!< number of bits in the lock
					bitmap; NOTE: the lock bitmap is
					placed immediately after the
					lock struct */
};

行锁表示

InnoDB中一个事务中的行锁是按照page和锁类型组织,相同的锁类型,锁一行和锁这行所在page中所有行的存储代价是一样的,[space, page_no] 可以确定锁对应哪个页,数据页内部使用一个 heap_no 来表示是第几行数据。因此[space, page_no, heap_no]可以唯一确定一行。Innodb 使用位图来表示锁具体锁住了那几行,在函数 lock_rec_create 中为 lock_t 分配内存空间的时候,会在对象地址后分配一段内存空间(当前行数 + 64)用来保存位图。n_bits 表示位图大小(因为n_bits是在锁创建时就确定了,所以如果页记录增加导致锁n_bits不足以表示时,需要创建新的锁结构)

/* Make lock bitmap bigger by a safety margin */
n_bits = page_dir_get_n_heap(page) + LOCK_PAGE_BITMAP_MARGIN;
n_bytes = 1 + n_bits / 8;

lock = static_cast<lock_t*>(
    mem_heap_alloc(trx->lock.lock_heap, sizeof(lock_t) + n_bytes));

heap no参考下图:

image.png