InnoDB事务系统负责InnoDB层事务管理,快照管理,MVCC等。
事务对象
InnoDB层事务对象为 struct trx_t 类型。
1 | // 部分字段 |
InnoDB的事务开启序,每个读写事务启动时获取一个id,事务结束时获取no作为提交序。
事务状态包含:
- TRX_STATE_NOT_STARTED
- TRX_STATE_FORCED_ROLLBACK
- TRX_STATE_ACTIVE
- TRX_STATE_PREPARED
- TRX_STATE_COMMITTED_IN_MEMORY(COMMITTED)
常规的事务状态变换:NOT_STARTED -> ACTIVE -> COMMITTED -> NOT_STARTED。
TRX_STATE_PREPARED是针对XA事务的prepare状态。
所有的事务都会存放在mysql_trx_list链表中,这是一个双向链表,本身不支持并发,需要trx_sys->mutex保护。
read_view是该事务的快照,我们后面会详细描述这块。
commit_lsn跟redo提交有关,我们在InnoDB log sys中介绍。
事务对象管理
事务对象管理分为两块,一块是活跃的读写事务集合,一块是所有活跃事务集合(包括读写事务和只读事务)。
所有活跃事务集合以链表形式存储,也就是mysql_trx_list。
活跃的读写事务集合非常重要,存放在trx_sys->rw_trx_ids,它跟快照关系密切,实际上也只是为了快照才维护了这个数据结构。
快照
如前所说,InnoDB是开启序,写事务开启后申请到一个id,事务修改了某一行,会在行头写入对应的事务id,以后该行可能被其他并发事务读取,至于能不能看到该行的这个新版本,取决于读事务的快照是否认为写事务已经提交。可能存在id小的写事务一直没提交,但id大的事务先提交了,所以对快照来说,创建快照时刻的活跃事务列表就成了数据版本可见性的依据,也就是快照的一部分。
快照的定义如下:
1 | struct ReadView |
申请一个快照的过程:
- 获取一个view对象,可以从free view list拿一个复用,或者分配一个新的
- 将活跃读写事务列表复制到view->m_ids
- m_low_limit_id为当前已经分配出去的最大trx id
- m_low_limit_no为已经分配了提交序no的事务中最小的(遍历serialisation_list列表),如果列表为空,则与m_low_limit_id相等。
- m_up_limit_id为view->m_ids中最小值,如果view->m_ids为空,m_up_limit_id也等于m_low_limit_id
上述过程在trx_sys->mutex保护下进行。
快照对象的管理
所有已经open的快照都在 MVCC::m_views列表中保存,该列表也由trx_sys->mutex保护。
为了避免反复分配释放快照对象,如果快照对象close时,先还到MVCC::m_free这个free list中。
purge等地方需要用到当前系统中最老的快照。获取最老快照实现方式 MVCC::get_oldest_view 是在MVCC::m_views中找第一个已经open的快照,这个过程也是在trx_sys->mutex保护进行。
之所以可以直接取列表第一个open的read view,是因为在trx_sys->mutex锁的同步下,快照的创建完全是串行化的,时间上越早创建的快照越在MVCC::m_views前面。
扫描二维码,分享此文章