函数buf_page_is_corrupted (innodb_plugin/buf/buf0buf.c)这个函数,是在InnoDB中获取page数据后,对page作校验,判断内容是否损坏。
在压力测试中发现,innodb.so最耗费cpu的就是这个buf_page_is_corrupted。
Percona对这个函数作了优化。本文介绍与此有关的配置、优化原理以及进一步的优化空间。(当前版本5.1.48 innodb-plugin 1.0.9)
1、函数主流程
每个page头部的前四个字节是本page的checksum, 在page写入时计算得到。因此函数主流程如下:
a) 读前四个字节得到checksum_field
b) 对page重新计算checksum, buf_calc_page_new_checksum(read_buf)
c) 若a、b的结果相同则认为page未损坏。
2、 函数瓶颈
显然函数主要计算时间在buf_calc_page_new_checksum中,后者直接调用ut_fold_binary(实现位置 ./include/ut0rnd.ic)。我们来看这个ut_fold_binary的函数实现:
UNIV_INLINE
ulint
ut_fold_binary(
/*===========*/
const byte* str, /*!< in: string of bytes */
ulint len) /*!< in: length */
{
const byte* str_end = str + len;
ulint fold = 0;
ut_ad(str || !len);
while (str < str_end) {
fold = ut_fold_ulint_pair(fold, (ulint)(*str));
str++;
}
return(fold);
}
说明:其中ut_fold_ulint_pair的第二个参数表明,在该函数中,是以一个uint方式使用的(如下)。该函数在同一个文件中,通过两个uint的异或和移位得到返回值。但在第13行中的str++, 使得每个字节都被使用了4次。
ut_fold_ulint_pair(
/*===============*/
ulint n1, /*!< in: ulint */
ulint n2) /*!< in: ulint */
{
return(((((n1 ^ n2 ^ UT_HASH_RANDOM_MASK2) << 8) + n1)
^ UT_HASH_RANDOM_MASK) + n2);
}
3、 优化
Percona版本的改进中,将实现了一个新的函数ut_fold_ulint_pair_32, 将步进修改为4个字节。
实际上,将16k数据签名成4个字节,使用前后两种方法的信息损失是相同的,因此优化版本概率上并不损失准确性。
在64位机器上,若每次直接取两个unsigned long作ut_fold_ulint_pair操作(当然需要为此写一个ut_fold_ulint_pair_64函数),计算速度相同,但步进长度加倍,能够进一步优化此函数性能。
代码上需要作如下修改
a) ./include/ut0rnd.ic 和 ./include/ut0rnd.h 中增加ut_fold_binary_64的定义和声明
b) buf/buf0buf.c中增加buf_calc_page_new_checksum_64, 并在buf_page_is_corrupted增加调用
c) 在buf_flush_init_for_writing(buf/buf0flu.c)中,写入page前换用buf_calc_page_new_checksum_64得到checksum
4、 测试结果
用sysbench作压力,并计算三种buf_calc_page_new_checksum的平均执行时间。得益于神器SystemTap,不需要再另外统计时间的代码(痛苦回忆中)。
|
函数 |
平均执行时间 |
|
buf_calc_page_new_checksum |
65ms |
|
buf_calc_page_new_checksum_32 |
24ms |
|
buf_calc_page_new_checksum_64 |
16ms |
本文探讨InnoDB中buf_page_is_corrupted函数的工作原理及优化方法。该函数用于检查页数据的完整性。Percona版对其进行了改进,通过调整ut_fold_binary函数的步进来提升效率。在64位系统上,进一步的优化可以减少计算时间。
3194

被折叠的 条评论
为什么被折叠?



