innodb purge操作

零散的记录,做备忘用

---------------------------------------------

由于每次DML操作都会生成Undo页,系统需要定期对这些undo页进行清理,也就是所谓purge操作。在5.5之前这些都是在master线程中完成,但5.5及之后的版本可以通过innodb_purge_threads来控制是否使用独立线程进行purge操作。

下面将就undolog以及purge线程如何运作做介绍


1.undo log

Undolog保存了记录修改前的镜像。其中insertundo records在事务回滚时会被丢弃,而updateundo records会被用到rollbackMVCC以及Purge操作中。

对于一次delete操作:DELETEFROM t WHERE c = 1innodb不会立刻移除相应的记录,在innodb的官方博客上是这么解释的:

  1. Itmarks the record as deleted by setting a bit in the control bits ofthe record.

  2. Storesthe before image of the modified columns to the UNDO log

  3. Updatesthe system columns DB_TRX_ID and DB_ROLL_PTR inthe clustered index record.DB_TRX_ID identifiesthe transaction that made the last change, and DB_ROLL_PTR pointsto the new UNDO log record. This UNDO log record contains the oldvalues of DB_TRX_ID andDB_ROLL_PTR,possibly pointing to an older transaction and undo log entry.

在每个记录上有两个重要的系统数据列,用于多版本的控制:

DB_TRX_ID:最近修改这个记录的事务ID

DB_ROLL_PTR:指向由于最近的更新创建的回滚段

同时在每个undorecord上也会指向旧的undo记录,从而形成了一条更新链,通过这个更新链,不同的事务可以找到其对应的版本的undo信息,组合成就版本记录。

当一个事务提交时,由于该事务生成的undolog和标记删除的记录可能被其他事务所使用。当没有事务需要这些数据时,标记删除的记录和相关的undolog records可以被purge掉。



2.purge

Purge操作会克隆最老旧的read_view,这个read_view中持有控制信息以限制哪些由其他事务引起的变化是可见的。然后以相反的方式读取从最老的到最近的undolog 记录;如果当前运行的事务都没有引用这些记录,则分析这些记录并从索引上移除被标记删除的记录。

有两个相关的控制参数:

Innodb_purge_threads:控制是否使用独立purge线程

Innodb_purge_batch_size:表示一次完成多少个undolog page;但这个值有一个有趣的副作用是会影响到undolog的释放,因为总是在128purge后释放undolog page,在5.5及之后版本,开始支持128个回滚段。


一个大致的堆栈如下:

#0 row_purge (thr=0xabd4668, node=0xabd46d0) at/home/yinfeng/Percona-Server-5.5.18-rel23.0/storage/innobase/row/row0purge.c:757

#1 row_purge_step (thr=0xabd4668) at/home/yinfeng/Percona-Server-5.5.18-rel23.0/storage/innobase/row/row0purge.c:805

#2 0x0856bb0e in que_thr_step (thr=0xabd4668) at/home/yinfeng/Percona-Server-5.5.18-rel23.0/storage/innobase/que/que0que.c:1259

#3 que_run_threads_low (thr=0xabd4668) at/home/yinfeng/Percona-Server-5.5.18-rel23.0/storage/innobase/que/que0que.c:1319

#4 que_run_threads (thr=0xabd4668) at/home/yinfeng/Percona-Server-5.5.18-rel23.0/storage/innobase/que/que0que.c:1356

#5 0x08492922 in trx_purge (limit=20) at/home/yinfeng/Percona-Server-5.5.18-rel23.0/storage/innobase/trx/trx0purge.c:1194

#6 0x0848766d in srv_purge_thread (arg=0x0) at/home/yinfeng/Percona-Server-5.5.18-rel23.0/storage/innobase/srv/srv0srv.c:3897

#7 0xb76d3d31 in start_thread (arg=0x8d907b70) at pthread_create.c:304

#8 0xb75ed0ce in clone () at../sysdeps/unix/sysv/linux/i386/clone.S:130


Purge操作的入口函数为srv_purge_thread,主要工作在一个大while循环里。主要处理函数

trx_purge

Trx_purge的参数也就是Innodb_purge_batch_size

主要流程如下:

1).rw_lock_x_lock(&purge_sys->latch);

2)判断DML操作是否需要被delay,只有当参数innodb_max_purge_lag被设置为一个大于0的值时,才会去判断。

3)获取当前最老旧的事务read_viewread_view_oldest_copy_or_open_new

4) thr =que_fork_start_command(purge_sys->query); //不是很明白,留待后续研究

5)主函数调用流程:

que_run_threads->que_run_threads_low-> que_thr_step-> row_purge_step->row_purge

之前以que开头的函数都定义在que0que.cc文件中,看起来是根据查询计划图来调度相应的模块函数。

比如对于purge操作,会在que_thr_step里调用row_purge_step,而对于commit,会在row_purge_step里调用trx_commit_step。这部分内容还不是很了解,后面会跟进分析



那么我们就来看看row_purge到底做了什么吧

1)trx_purge_fetch_next_rec,从历史undolog列表中选择一条记录

——找出拥有最小事务id的回滚段(purge_sys->rseg)

trx_purge_get_rseg_with_min_trx_id

——从回滚段中读取记录

trx_purge_read_undo_rec


这里还会对purge_sys->n_pages_handled做加1,如果已经purge的记录超过了Innodb_purge_batch_size,则设置purge_sys->state= TRX_STOP_PURGE

2)row_purge_parse_undo_rec

按照注释的说法是从undolog里解析出行引用信息和其他信息,返回值为true表明需要执行purge操作.

通过函数trx_undo_rec_get_pars获得undo记录的类型,主要包括以下几个类型:

TRX_UNDO_INSERT_REC

freshinsert into clustered index


TRX_UNDO_UPD_EXIST_REC

updateof a non-delete-marked record


TRX_UNDO_UPD_DEL_REC

updateof a delete marked record to a not delete marked record; also the

fieldsof the record can change


TRX_UNDO_DEL_MARK_REC

deletemarking of a record; fields do not change


TRX_UNDO_CMPL_INFO_MULT

compilationinfo is multiplied by this and ORed to the type above

TRX_UNDO_UPD_EXTERN

Thisbit can be ORed to type_cmpl to denote that we updated externalstorage fields: used by purge to free the external storage *


在进行一系列判断后,当需要对这一行记录执行purge操作时,需要:

row_mysql_freeze_data_dictionary(trx);

这会阻止所有的create/droptable操作,因为会对dict_operation_lockS锁,这是个全局锁。当create/drop表的时候需要X锁,一些后台操作例如Purgerollback、外键检查需要S锁,在一个事务里,我们可以通过

trx_struct::dict_operation_lock_mode来查看是否拥有该锁



trx_undo_rec_get_row_ref(从undolog中获得逻辑记录信息??)

trx_undo_update_rec_get_update(基于undolog创建updatevector??)


最后从一个updateundo log record中创建一个partialrowIt contains the

columnswhich occur as ordering in any index of the table


3)对一个标记删除的记录做purge操作

row_purge_del_mark


4)row_purge_upd_exist_or_extern()

Purgesan update of an existing record. Also purges an update of a deletemarked record if that record contained an externally stored field.


无论哪种purge,会依次查看二级索引,调用row_build_index_entry创建一个老的记录,然后调用row_purge_remove_sec_if_poss从二级索引种将旧记录删除。


最后还会调用row_purge_remove_clust_if_poss来删除主键上的记录


6)row_mysql_unfreeze_data_dictionary,释放在dict_operation_lock上的S

7)清理操作



参考资料:

1.http://blogs.innodb.com/wp/2011/07/allow-undo-logs-to-reside-in-their-own-tablespace/

2.http://blogs.innodb.com/wp/2011/04/mysql-5-6-multi-threaded-purge/

3.percona5.5.18


没有更多推荐了,返回首页