信息维护
Innodb在两个维度维护行锁信息,就和文件组织Extent一样。两个维度一个是全局的、一个是事务持有的。 下图右下角Lock_sys就是全局的锁信息,左上角就是事务持有的锁信息。
全局
/** 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参考下图: