[MySQL 学习]show engine innodb status中的history list length

Percona bug#1058100提到trx_purge_add_update_undo_to_history函数,不甚了解,用gdb跟踪了下

trx_commit_off_kernel->trx_write_serialisation_history->trx_undo_update_cleanup->trx_purge_add_update_undo_to_history

lsn = trx_write_serialisation_history(trx);

a.首先对当前事务的undo段进行标记,以表明事务提交。

对于update undo日志,为事务分配id(trx_serialisation_number_get->trx_sys_get_new_trx_id),标记undo状态为TRX_UNDO_TO_PURGE(trx_undo_set_state_at_finish),

对于insert undo标记undo回滚段状态为TRX_UNDO_TO_FREE

如果update undo段只占用一个Page,并且使用的字节数小于TRX_UNDO_PAGE_REUSE_LIMIT(3/4的page size)时,则将undo段标记为TRX_UNDO_CACHED,表示下次可以重用该回滚段。

b.对于update undo,还需要将undo加到history list上,并做一些清理工作

trx_undo_update_cleanup(trx, undo_hdr_page, &mtr);

(1)trx_purge_add_update_undo_to_history(trx, undo_page, mgr);

当undo 段的state不为TRX_UNDO_CACHED时,需要更新undo段的history list length,然后将undo加入到改回滚段的TRX_RSEG_HISTORY的链表上(不太了解undo这部分相关的逻辑),将事务号写入undo_header + TRX_UNDO_TRX_NO中,并在TRX_UNDO_DEL_MARKS标注是否存在标记删除记录(需要purge)

在kernel_mutex的保护下trx_sys->rseg_history_len++;

我们在show engine innodb status里看到的History list length实际上就是trx_sys->rseg_history_len值。

由于该函数总是在事务提交时才被调用到,因此我们也可以把history list lengh理解为尚未被清理update undo的事务数.在update/delete为主的工作负载中,可能会看到length明显的增大。

这里有一段被注释的代码,也是Percona bug#1058100提出的质疑

//  if (!(trx_sys->rseg_history_len % srv_purge_batch_size)) { /*should wake up always*/

        /* Inform the purge thread that there is work to do. */

        srv_wake_purge_thread_if_not_active();

//  }

也就是说,在Percona版本中,purge线程总是会被唤醒。在原版MySQL5.5中这个判断逻辑还在。

官方5.6则和Percona版本类似,去除了判断条件。但5.6会在递增rseg_history_len之后,在写入undo_header事务Id之前唤醒purge线程。不知是否有潜在风险

如果每次都无条件的唤醒,这可能破坏了innodb_purge_batch_size的定义。

(2)从事务回滚段上把update undo移除

UT_LIST_REMOVE(undo_list, rseg->update_undo_list, undo);

(3)如果undo的state为TRX_UNDO_CACHED,则将其加入到事务回滚段的rseg->update_undo_cached中,留作下次重用。

UT_LIST_ADD_FIRST(undo_list, rseg->update_undo_cached, undo);

否则直接释放undo内存结构trx_undo_mem_free(undo);

//////////////////////////////////////////////////////////////////////////////////////////

既然我们知道了history list length来自trx_sys->rseg_history_len,那么在何时,这个值会被递减呢?

有两个函数被涉及到trx_purge_truncate_rseg_history以及trx_purge_free_segment

调用栈如下:

trx_purge->que_run_threads->que_run_threads_low->row_purge_step->row_purge->trx_purge_fetch_next_rec->trx_purge_truncate_if_arr_empty->trx_purge_truncate_history->trx_purge_truncate_rseg_history->trx_purge_free_segment

当purge线程清理undo时,会遍历所有的回滚段列表(trx_purge_truncate_history, 最多1024个回滚段,在内存中用try_sys->rseg_list表示),进行undo清理。会对清理的trx_no 和undo_no做限制。

函数trx_purge_truncate_rseg_history有两个参数:

limit_trx_no,移除所有事务id小于这个值的undo log

limit_undo_no,如果事务id等于limit_trx_no,则只清理undo_no小于该值的undo 日志。

需要purge的Undo Log被记录在每个回滚段头的TRX_RSEG_HISTORY中,通过遍历列表,来回收Undo 记录。

时间: 2024-08-29 19:15:37

[MySQL 学习]show engine innodb status中的history list length的相关文章

show engine innodb status中关于锁部分内容的解释

 LOCK WAIT 2 lock struct(s), heap size 1136, 1 row lock(s) MySQL thread id 4, OS thread handle 140665176164096, query id 575 localhost root update insert into testpri values(13,10) ------- TRX HAS BEEN WAITING 9 SEC FOR THIS LOCK TO BE GRANTED: RECOR

show engine innodb status显示信息不全如何解决_Mysql

问题: 执行 show engine innodb status\G 时,显示的信息不全,DEADLOCK相关信息太多,后面的都没了 原因: 这是mysql客户端的一个bug:BUG#19825,交互式客户端限制了输出信息最大为 64KB,因此更多的信息无法显示. 解决办法: 解决方法有两种: 1. 启用 innodb_status_file 修改 my.cnf,增加类似下面一行 innodb_status_file = 1 就可以了. 2. 启用 innodb_monitor mysqld在线

mysql学习笔记 where in 条件中一些使用技巧

查询    代码如下 复制代码 SELECT * FROM table1 WHERE table1.id IN (1, 2, 3, 4, 5, -, 999999) 删除  代码如下 复制代码 DELETE FROM `table1` WHERE `id` in (835,836,837,-,999806) 子查询  代码如下 复制代码 SELECT * FROM table1 WHERE table1.id IN     (    SELECT id from table2     ) in中

[MySQL 学习] Innodb锁系统(1)之如何阅读死锁日志

前言: 最近经常碰到死锁问题,由于对这块代码不是很熟悉,而常持有对文档怀疑的观点.决定从几个死锁问题着手,好好把Innodb锁系统的代码过一遍. 以下的内容不敢保证完全正确.只是我系统学习的过程. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 最近有同学发现,走二级索引删除数据时,两条delete

[MySQL学习] Innodb锁系统(4) Insert/Delete 锁处理及死锁示例分析

A.INSERT 插入操作在函数btr_cur_optimistic_insert->btr_cur_ins_lock_and_undo->lock_rec_insert_check_and_lock这里进行锁的判断,我们简单的看看这个函数的流程: 1.首先先看看欲插入记录之后的数据上有没有锁,    next_rec = page_rec_get_next_const(rec);    next_rec_heap_no = page_rec_get_heap_no(next_rec);  

[MySQL 学习] Innodb锁系统(2)关键函数路径

前提: 以下分析基于标准的配置选项: tx_isolation = REPEATABLE-READ innodb_locks_unsafe_for_binlog = OFF lock->type_mode用来表示锁的类型,实际上lock->type_mode包含了几乎所有锁的模式信息,例如锁类型判断是X锁还是S锁 lock->type_mode &LOCK_TYPE_MASK LOCK_MODE_MASK 0xFUL 用于表示锁模式掩码 LOCK_TYPE_MASK 0xF0UL

[MySQL学习] Innodb change buffer(1)之初识篇

从MySQL5.5版本开始,Insert buffer更名为change buffer,除了缓冲对二级索引的insert操作,还包括update/delete/后台purge操作,由参数innodb_change_buffering来控制.因此这里统一称为change buffer. ////////////////////////////////////////////////////////// 当更新/插入的非聚集索引的数据所对应的页不在内存中时(对非聚集索引的更新操作通常会带来随机IO)

《MySQL技术内幕:InnoDB存储引擎第2版》——2.6 InnoDB关键特性

2.6 InnoDB关键特性 InnoDB存储引擎的关键特性包括: ?插入缓冲(Insert Buffer) ?两次写(Double Write) ?自适应哈希索引(Adaptive Hash Index) ?异步IO(Async IO) ?刷新邻接页(Flush Neighbor Page) 上述这些特性为InnoDB存储引擎带来更好的性能以及更高的可靠性.2.6.1 插入缓冲 1.?Insert Buffer Insert Buffer可能是InnoDB存储引擎关键特性中最令人激动与兴奋的一

《MySQL技术内幕:InnoDB存储引擎第2版》——2.3 InnoDB体系架构

2.3 InnoDB体系架构 通过第1章读者已经了解了MySQL数据库的体系结构,现在可能想更深入地了解InnoDB存储引擎的架构.图2-1简单显示了InnoDB的存储引擎的体系架构,从图可见,InnoDB存储引擎有多个内存块,可以认为这些内存块组成了一个大的内存池,负责如下工作: ?维护所有进程/线程需要访问的多个内部数据结构. ?缓存磁盘上的数据,方便快速地读取,同时在对磁盘文件的数据修改之前在这里缓存. ?重做日志(redo log)缓冲. -- 后台线程的主要作用是负责刷新内存池中的数据