更新一条聚集索引记录,接口函数是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