[MySQL 学习] Innodb Optimistic Update流程

更新一条聚集索引记录,接口函数是btr_cur_optimistic_update,这里的更新不涉及到标记删除/插入(二级索引更新或更新主键值,row_upd->row_upd_clust_rec_by_insert->btr_cur_del_mark_set_clust_rec->btr_rec_set_deleted_flag)

a.首先判断记录更新是否改变了大小或者需要外部存储,调用函数row_upd_changes_field_size_or_external

b.如果a返回的是false,则调用btr_cur_update_in_place进行in-place更新,然后返回, in-place更新的流程如下:

1.调用btr_cur_update_alloc_zip检查压缩page的mlog空间是否足够进行in-place 更新

(1)调用page_zip_available检查是否空间足够,如果有足够空间,直接返回TRUE

(2)当page_zip->m_nonempty为false时,直接返回FALSE,表明刚刚可能做过一次压缩,无需再进行下面的流程

(3)调用page_zip_compress进行压缩,如果压缩失败,返回FALSE

(4)再次调用page_zip_available检查压缩页的空闲空间

2.如果有足够的空间,则继续往下,调用btr_cur_upd_lock_and_undo检查锁并记录undo信息

(1)如果是非聚集索引,则直接调用lock_sec_rec_modify_check_and_lock,检查并对二级索引加锁,并更新该page的最大事务ID(page_update_max_trx_id), 然后从btr_cur_upd_lock_and_undo返回

(2)如果是聚集索引,调用lock_clust_rec_modify_check_and_lock检查记录锁

(3)调用trx_undo_report_row_operation记录undo

3.向记录中写入trx_id和roll_ptr信息(row_upd_rec_sys_fields)

4.对于聚集索引,如果当前block使用了adaptive hash index(block->index != NULL),则调用row_upd_changes_ord_field_binary//Checks if an update vector changes an ordering field of an index record,不是很明白,待分析,然后再调用btr_search_update_hash_on_delete从adaptive hash index中删除该记录

5.更新记录row_upd_rec_in_place

直接In-place更新记录,并调用page_zip_write_rec向压缩页的mlog中写入记录

//如果进行了多次In-place update,是否会产生多条mlog?? 这可能加大re-compress/re-orgnize的概率

6.对于非聚集索引的压缩page,更新insert buffer的空闲空间信息

    if (page_zip && !dict_index_is_clust(index)

        && page_is_leaf(buf_block_get_frame(block))) {

        /* Update the free bits in the insert buffer. */

        ibuf_update_free_bits_zip(block, mtr);

    }

7.写一条redo日志(btr_cur_update_in_place_log)

c.如果存在外部存储的列,则直接返回NULL,因为外部存储的更新当做pessimistic update来处理

d.将upd_struct中的记录更新到dtuple_t中,row_upd_index_replace_new_col_vals_index_pos

e.如果是压缩表,调用btr_cur_update_alloc_zip查看有没有空闲mlog空间,如果没有,则返回DB_OVERFLOW错误

f.新记录大于非压缩页空闲空间的一半,返回DB_OVERFLOW

g.更新后非压缩Page上的数据小于BTR_CUR_PAGE_COMPRESS_LIMIT,也就是8k时,返回DB_UNDERFLOW错误,表明该page太空了,随后上层逻辑会尝试将其中的数据转移到邻居节点

h.max_size=老的记录大小+Page重组织后最大插入记录大小,满足如下条件时,返回DB_OVERFLOW错误

    if (!(((max_size >= BTR_CUR_PAGE_REORGANIZE_LIMIT)

           && (max_size >= new_rec_size))

          || (page_get_n_recs(page) <= 1))) 

i.调用btr_cur_upd_lock_and_undo检查锁并记录undo,不赘述

j.lock_rec_store_on_page_infimum(block, rec); //Stores on the page infimum record the explicit locks of another record

锁管理子系统不是很清楚,后面再系统分析

k.从adaptive hash index中删除记录 btr_search_update_hash_on_delete(cursor);

l.删除当前记录(page_cur_delete_rec)并移动page_cursor到前一个记录(page_cur_move_to_prev)

m.更新记录的roll_ptr及trx_id

n.如果空间足够的话,则插入记录btr_cur_insert_if_possible

1.插入记录page_cur_tuple_insert->page_cur_insert_rec_zip,前面已经描述过,不赘述

2.如果插入失败,调用btr_page_reorganize重新组织page,再调用page_cur_tuple_insert尝试插入一次

o.对于压缩表的非聚集索引leaf page,还需要更新insert buffer的free bits.(ibuf_update_free_bits_zip)

p.lock_rec_restore_from_page_infimum(block, rec, block); //Restore the old explicit lock state on the record

q.page_cur_move_to_next(page_cursor) and return DB_SUCCESS

时间: 2024-12-29 06:25:28

[MySQL 学习] Innodb Optimistic Update流程的相关文章

[MySQL 学习] Innodb Optimistic Insert流程

通常情况下,插入一条数据的接口函数为btr_cur_optimistic_insert,这时候不需要进行索引树分裂,先来看看这里怎么处理压缩表数据吧 btr_cur_optimistic_insert a. 计算该Page上还能写入的最大空闲空间大小 max_size = page_get_max_insert_size_after_reorganize(page, 1); 以及这条逻辑记录(dtuple_struct)转换成物理记录的大小 rec_size = rec_get_converte

[MySQL 学习] Innodb Optimistic Delete 简述

接口函数是btr_cur_optimistic_delete Innodb的Optimistic Delete操作主要是由purge线程来进行的,用户线程仅仅做了删除标记(包括删除记录,更新二级索引以及更新主键), 另外如果插入/更新操作回滚了,用户也会调用到函数btr_cur_optimistic_delete 例如回滚insert操作的调用栈为 trx_general_rollback_for_mysql–>-..->row_undo->row_undo_ins->row_un

[MySQL学习] Innodb崩溃恢复流程

简要记录跟踪代码,很多代码流程没有细细的跟进去,只是了解了个大概,杂七杂八,还有太多不了解的地方. 不过,一知半解总比一无所知要好点-sign- //////////////////////////////////////////// 一.innobase_init 1.初始化存储引擎接口函数.检查指定的page大小(innodb_page_size,Percona版本支持16k以下的page size定义).innodb_log_block_size. 2.检查是否通过记录在innodb层的r

[MySQL学习] Innodb change buffer(2) 相关函数及流程

简单的代码跟踪,顺便弄清了之前一直困惑的bp->watch的用途.... //////////////////////////////// A.相关结构体 在介绍ibuf在Innodb中的使用前,我们先介绍下相关的结构体及全局变量. 我们知道通过Ibuf可以缓冲多种操作类型,每种操作类型,在内部都有一个宏与之对应: IBUF_OP_INSERT IBUF_OP_DELETE_MARK IBUF_OP_DELETE 至于对update操作的缓冲,由于二级索引记录的更新是先delete-mark,再

[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锁系统(1)之如何阅读死锁日志

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

[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锁系统(3)关键结构体及函数

1.锁对象的定义: 关键结构体: UNIV_INTERN lock_sys_t* lock_sys = NULL; lock_sys是一个全局变量,用于控制整个Innodb锁系统的全部锁结构,其对应的结构体为lock_sys_t,该结构体只包含两个成员: struct lock_sys_struct{     hash_table_t* rec_hash;     ulint rec_num; }; 从函数lock_rec_create可以很容易看出这两个变量的作用: quoted code: