October 2012

[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_undo_ins_remove_clust_rec->btr_cur_optimistic_delete 当我们正常删除记录时,一般仅仅是做一个标记,例如更新主键值的update函数栈 row_update_for_mysql->row_upd_step->row_upd->row_upd_clust_step->row_upd_clust_rec_by_insert->btr_cur_del_mark_set_clust_rec->btr_rec_set_deleted_flag 随后的purge线程调用栈为: trx_purge->….->row_purge_step->row_purge->row_purge_del_mark->row_purge_remove_clust_if_poss->row_purge_remove_clust_if_poss_low->btr_cur_optimistic_delete 事实上btr_cur_optimistic_delete的流程也很简单,如果无需重组织btree(btr_cur_can_delete_without_compress),直接调用 a.lock_update_delete(block, rec);  //移除记录锁 b.btr_search_update_hash_on_delete(cursor)//更新adaptive hash index c.page_cur_delete_rec删除记录 d.更新insett buffer 的free bits (压缩表调用ibuf_update_free_bits_zip,非压缩表调用ibuf_update_free_bits_low) 显然,在这里并没有对压缩页的mlog写入数据,实际上写入mlog是由用户线程执行的,对应函数为page_zip_rec_set_deleted.(;例如:row_upd->row_upd_clust_step->row_upd_del_mark_clust_rec->btr_cur_del_mark_set_clust_rec->page_zip_rec_set_deleted) 他的实现也很简单,只是将记录对应的slot设置一个删除标记位。 原创文章,转载请注明: 转载自Simple Life 本文链接地址: [MySQL 学习] Innodb Optimistic Delete 简述 Post Footer automatically generated by wp-posturl plugin for wordpress.

[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))) { […]

[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_converted_size(index, entry, n_ext) b.判断该记录是否需要外部存储 if (page_zip_rec_needs_ext(rec_size, page_is_comp(page), 1320                    dtuple_get_n_fields(entry), zip_size)) 如果需要外部存储的话,返回DB_TOO_BIG_RECORD,由上层继续处理 当为压缩表时,在每个压缩Page上的dense page directory中为每条记录记录预留两个byte。但没有record header。在一个空的leaf page上,至少要有一条记录。另外还要减去一个Byte来存储heap number. 同样的该记录也不能大于非压缩page最大可用空间的一半 所以判断条件为:         (rec_size – (REC_N_NEW_EXTRA_BYTES – 2)               […]

[MySQL 调试] 编译mysqld缺少gb2312的问题

最近在安装Percona5.5.18版本MySQL时,发现字符集不全,编译参数如下 CFLAGS=”-O3 -g -fno-exceptions -static-libgcc -fno-omit-frame-pointer -fno-strict-aliasing” CXX=gcc CXXFLAGS=”-O3 -g -fno-exceptions -fno-rtti -static-libgcc -fno-omit-frame-pointer -fno-strict-aliasing” export CFLAGS CXX CXXFLAGS cmake . \ -DCMAKE_BUILD_TYPE:STRING=Release             \ -DSYSCONFDIR:PATH=%{_prefix}            \ -DCMAKE_INSTALL_PREFIX:PATH=%{_prefix}  \ -DENABLED_PROFILING:BOOL=ON                   \ -DENABLE_DEBUG_SYNC:BOOL=OFF                  \ -DMYSQL_DATADIR:PATH=%{_prefix}/data    \ -DMYSQL_MAINTAINER_MODE:BOOL=OFF              \ -DWITH_EXTRA_CHARSETS:STRING=all  \ -DWITH_BIG_TABLES:BOOL=ON \ -DWITH_FAST_MUTEXES:BOOL=ON \ -DENABLE-PROFILING:BOOL=ON \ -DWITH_SSL:STRING=bundled                     \ -DWITH_UNIT_TESTS:BOOL=OFF                    \ -DWITH_ZLIB:STRING=bundled                    \ -DWITH_PARTITION_STORAGE_ENGINE:BOOL=ON       \ -DWITH_PLUGINS=heap,csv,partition,innodb_plugin,myisam \ -DDEFAULT_CHARSET=gbk […]

限制MySQL Binlog的传输速率

最近一台核心库备库完成恢复后打开slave,导致主库传送binlog,瞬间占满网络,触发故障。 为了做一些限制, 给mysql在发送binlog的函数(mysql_binlog_send)里每隔一段时间sleep一次, 增加了两个参数: master_send_count  每读master_send_count次事件,sleep一次 master_send_sleep   每次sleep的时间为master_send_sleep ,单位为毫秒ms 以下统计数据,每1秒统计一次。 1.不受限制 set global master_send_count = 0; set global master_send_sleep = 0; 2.  set global master_send_count = 10; set global master_send_sleep = 100; 3. set global master_send_count = 10; set global master_send_sleep = 200; 4. set global master_send_count = 1; set global master_send_sleep = 15; 5. […]

[MySQL 学习] MySQL5.6 的checkusm

从MySQL5.6.3开始 ,Innodb引入了新的checksum计算方式,checksum算法由新参数 innodb_checksum_algorithm来控制,默认为crc32算法,主要有两种算法,一种是老的计算方法(innodb_checksum_algorithm=innodb),使用这种算法是兼容老版本的MySQL。但如果使用crc32算法,则会无法兼容老版本,因为使用了不同的算法计算checksum,会导致校验page失败。 当设置为none时,则在page中写入一个常量(BUF_NO_CHECKSUM_MAGIC) 另外还有两个值strict_innodb  和strict_crc32  ,当设置为这两个值时,如果该表存在混合的checksum计算方式, 则只根据当前的设置计算一次,而不会使用别的算法计算checksum。 在Percona版本的5.5.18中,也引入了一种快速checksum方法(对应的函数为buf_calc_page_new_checksum_32),由参数innodb_fast_checksum控制,但该参数不影响压缩page的checksum,压缩页单独计算,调用page_zip_calc_checksum 有趣的是,我在innodb status里增加了checksum耗时统计,并让5.5.18支持Percona 本身的fast checksum,发现其居然比老的checksum计算方式耗时要长。当然都在毫秒级别 值得一提的是,CRC32算法由Facebook贡献,具体代码可以在storage/innobase/ut/ut0crc32.cc查阅,算法采用了汇编来提高效率。社区的力量!! 鉴于CRC32和老checksum方式没有特别明显的改善(对于需要频繁I/O,读写Page的情况,效果会稍微明显些),对checksum优化的优先级降低 🙂 原创文章,转载请注明: 转载自Simple Life 本文链接地址: [MySQL 学习] MySQL5.6 的checkusm Post Footer automatically generated by wp-posturl plugin for wordpress.

[MySQL学习] MySQL/Innodb shutdown流程

写的比较简略////// ——————————— 我们通过mysqladmin来进行shutdown,会对mysqld发送SIGKILL信号,当接收到信号后,mysqld创建一个新的线程,线程调用函数为kill_server_thread 另外还可以通过调用COM_SHUTDOWN来关闭mysqld,没尝试过。当然最终调用的函数kill_server_thread函数。 kill_server_thread->kill_server 设置kill_in_progress=true,防止重复关闭mysqld,每个新的kill线程都要先判断这个值 设置abort_loop=1,这可以让某些循环等待的线程退出循环 调用close_connections a.关闭所有线程连接 b.关闭slave(end_slave()) 调用unireg_end->clean_up,主要做以下事情 a.清理一些全局结构体及内存资源 b.依次关闭插件plugin_shutdown 关闭innodb的入口函数是innobase_end,其关闭行为通过参数 innodb_fast_shutdown 来控制,流程如下: hash_table_free(innobase_open_tables)  //释放innodb表占用的内存 innobase_shutdown_for_mysql  //下面细述 释放一些全局内存和锁资源 innobase_shutdown_for_mysql流程: a.logs_empty_and_mark_files_at_shutdown 这个函数可以看做是innodb shutdown的主要函数。 |–>首先打印一条信息(InnoDB: Starting shutdown), 也就是我们在alter log里看到的,表示innodb shutdown开始 了。 srv_shutdown_state = SRV_SHUTDOWN_CLEANUP; |–>当 1.error monitor线程、lock_timeout线程(用于唤醒其他等待锁的线程)、以及monitor线程处于活跃状态时,loop 2.当前分配的事务数大于0(trx_n_mysql_transactions>0)或者存在状态不为Prepare的事务(UT_LIST_GET_LEN(trx_sys->trx_list) > trx_n_prepared), loop 3. 存在任意一个活跃后台线程时, loop 4.log_sys->n_pending_checkpoint_writes>0 或者log_sys->n_pending_writes大于0时,loop 5. 存在pending io时(buf_pool_check_no_pending_io) ,  loop |–>当UNIV_LOG_ARCHIVE被定义时,调用log_archive_all()写归档日志,log archive 貌似已被弃用,但代码还在。 |–>当srv_fast_shutdown=2时 log_buffer_flush_to_disk(); […]

[MySQL学习] 一个压缩Page从磁盘读入buffer pool的过程

以下是边看代码边记录的,从磁盘读取一个压缩Page到buffer pool的的全过程,以函数buf_page_get_gen作为入口 buf_page_get_gen 1.根据space和offset来计算请求的page是否已经读到了buffer pool中 fold = buf_page_address_fold(space, offset); block = (buf_block_t*) buf_page_hash_get_low(                           buf_pool, space, offset, fold); 判断:如果这个block所对应表正在被drop掉(使用lazy drop table),则调用buf_LRU_free_block((buf_page_t*)block, TRUE, TRUE)将其从LRU中删除 block->page.space_was_being_deleted在函数buf_LRU_mark_space_was_deleted内被设置 2.if (block && buf_pool_watch_is_sentinel(buf_pool, &block->page))    则将block设置为NULL。 buffer pool的watch[BUF_POOL_WATCH_SIZE];成员暂不清楚其用途,似乎用在insert buffer上,回头专门研究下 是在MySQL5.5.5引入 一个普通读的mode值为BUF_GET,因此以下也会忽略掉不必要的代码流程 3.当page不在bp时,则从磁盘读取该page。         if (buf_read_page(space, […]

[MySQL学习] Innodb压缩表相关结构体

简要记录一下压缩表在buffer pool中的相关结构体: //////////////////////////////////////////////////////////// struct buf_pool_struct{ mutex_t     zip_mutex;   //用于保护压缩page(buf_page_t) mutex_t     zip_free_mutex; mutex_t     zip_hash_mutex;   //保护zip_hash hash_table_t*   zip_hash;  //hash table of buf_block_t blocks whose frames are allocated to the zip buddy system, indexed by block->frame ulint       n_pend_unzip;  //number of pending decompressions UT_LIST_BASE_NODE_T(buf_block_t) unzip_LRU;   //base node of the unzip_LRU list […]

[MySQL 优化] 移除多余的checksum

1.bug#64170 根据bug#64170的描述,一个page在读入内存时就已经计算了一次checksum: buf_page_get_gen        |–>buf_read_page   (buf0buf.c:2543)               ->buf_read_page_low                   ->buf_page_io_complete                        ->buf_page_is_corrupted                              ->page_zip_calc_checksum 2612 […]