一、准备工作
1、准备知识
参考:《InnoDB 日志 回滚段 & 崩溃恢复实现详解——修改版》by 何登成
当事务提交时,与undo相关的操作:
insert undo:释放Rollback Segment Header Page中的Undo Slot;直接释放Insert_Undo对应的所有Undo Page,回收空间。
Update undo:释放Rollback Segment Header Page中的Undo Slot;将事务在Undo Log Header Page上当前事务的Undo Log Header链接到Rollback Segment
Header Page上 ,等待Purge。
2、实例运行
本例只看update undo,在客户端使用start transaction; update nkeys set c5=1 where c1=50003; commit; 当commit后,就会发生如下的流程。
二、执行流程
dispatch_command-->mysql_execute_command---> trans_commit---> ha_commit_trans---->ha_commit_one_phase----> innobase_commit---> innobase_commit_low--->trx_commit_for_mysql--->trx_commit_off_kernel--->trx_write_serialisation_history---> trx_undo_update_cleanup---->trx_purge_add_update_undo_to_history
备注:
a. 对于trx_commit_off_kerne(),If the transaction made any updates then we need to write the UNDO logs for the updates to the assigned rollback segment, 于是调用lsn = trx_write_serialisation_history(trx)。之后trx->conc_state 由TRX_PREPARED变为TRX_COMMITTED_IN_MEMORY,再变为TRX_NOT_STARTE(可能在此之前需要写log),最后将trx从trx_sys->trx_list中移除。
b. trx_write_serialisation_history()中调用trx_serialisation_number_get(trx)获得trx->no,即max trx id when the transaction is moved to COMMITTED_IN_MEMORY state,猜测这是用于在purge线程中判断是否可以purge的。然后调用 trx_undo_update_cleanup(trx, undo_hdr_page, &mtr)。
c. trx_undo_update_cleanup() Adds the update undo log header as the first in the history list(调用trx_purge_add_update_undo_to_history(trx, undo_page, mtr)), and frees the memory object, or puts it to the list of cached update undo log segments(加入rseg->update_undo_cache)。
d. trx_purge_add_update_undo_to_history()调用flst_add_first(rseg_header + TRX_RSEG_HISTORY, undo_header + TRX_UNDO_HISTORY_NODE, mtr)将undo log header链入rseg_header中。
/** The undo log header. There can be several undo log headers on the first
page of an update undo log segment. */
/* @{ */
/*-------------------------------------------------------------*/
#define TRX_UNDO_TRX_ID 0 /*!< Transaction id */
#define TRX_UNDO_TRX_NO 8 /*!< Transaction number of the
transaction; defined only if the log
is in a history list */
#define TRX_UNDO_DEL_MARKS 16 /*!< Defined only in an update undo
log: TRUE if the transaction may have
done delete markings of records, and
thus purge is necessary */
#define TRX_UNDO_LOG_START 18 /*!< Offset of the first undo log record
of this log on the header page; purge
may remove undo log record from the
log start, and therefore this is not
necessarily the same as this log
header end offset */
#define TRX_UNDO_XID_EXISTS 20 /*!< TRUE if undo log header includes
X/Open XA transaction identification
XID */
#define TRX_UNDO_DICT_TRANS 21 /*!< TRUE if the transaction is a table
create, index create, or drop
transaction: in recovery
the transaction cannot be rolled back
in the usual way: a 'rollback' rather
means dropping the created or dropped
table, if it still exists */
#define TRX_UNDO_TABLE_ID 22 /*!< Id of the table if the preceding
field is TRUE */
#define TRX_UNDO_NEXT_LOG 30 /*!< Offset of the next undo log header
on this page, 0 if none */ //一个页中可能有多个undo log header
#define TRX_UNDO_PREV_LOG 32 /*!< Offset of the previous undo log
header on this page, 0 if none */
#define TRX_UNDO_HISTORY_NODE 34 /*!< If the log is put to the history
list, the file list node is here */
/*-------------------------------------------------------------*/
/** Size of the undo log header without XID information */
#define TRX_UNDO_LOG_OLD_HDR_SIZE (34 + FLST_NODE_SIZE
三、purge
选择系统中最老的提交事务(所有Rollback Segment中最老提交事务,这是按提交顺序来排列的,即选择trx->no最小的,而不是事务本身trx->id);正向遍历事务的Update_Undo记录,彻底删除聚簇/二级索引上对应的DEL_BIT=1的项。