阿里巴巴DBA,原去哪儿网DBA。专注于MySQL源码研究、DBA运维、CGroup虚拟化及Linux Kernel源码研究等。 github:https://github.com/HengWang/ Email:king_wangheng@163.com 微博 :@王恒-Henry QQ :506437736
分类: Mysql/postgreSQL
2012-08-28 19:19:41
目的
MySQL的binlog日志中,基于行模式的方式,有table
id的信息,而该table id并不是binlog中的操作表的固定id。为了进一步了解table
id的改变,研究MySQL源码(MySQL-5.5.20),查看具体的处理逻辑,供开发和DBA参考。
源码分析
table id的分配在函数assign_new_table_id()(sql\sql_base.cc:3598)中分配,从处理的逻辑来看,每次分配都是对上一次的table id自增1。核心代码如下所示:
点击(此处)折叠或打开
|
而在TABLE_SHARE结构体(sql\table.h:541)的定义中,可以发现,table_map_id变量仅用于行模式的复制操作。具体定义如下所示:
点击(此处)折叠或打开
|
根据以上线索,跟踪调用assign_new_table_id()函数的引用。只在get_table_share()函数(sql\sql_base.cc:560)中调用,该函数首先调用my_hash_search_using_hash_value()函数(mysys\hash.c:218)查找cache中是否有操作的表定义。如果找到表定义,则对其引用数自增1并返回该表定义;否则,创建一个TABLE_SHARE变量,并调用assign_new_table_id()函数分配一个新的table id,然后保存在cache中,调用open_table_def()函数(sql\table.cc:594)打开表定义并返回。其中,表定义在cache中是通过hash的方式组织,通过表的hash值获得。
核心代码如下所示:
点击(此处)折叠或打开
|
写binlog的时候,在THD::binlog_write_table_map()函数(sql\log.cc:4760)中初始化Table_map_log_event对象the_event,初始化参数table id的值,即table_map_id的值,而该值是assign_new_table_id()函数获得的table id的值。核心代码如下:
点击(此处)折叠或打开
|
由以上内容可知,基于行模式的复制中,binlog中的table
id是根据初始化的每个Table_map_log_event的时,传入的table_map_id的值。而get_table_share()函数可知,当cache中有该表定义时,该值的table id是不变的;而当cache中没有改表定义时,该值根据上一次操作的table
id自增1获得的。
为了更清晰的了解table
id与cache的关系,对table_def_cache进行分析,在get_table_share()函数中,如果在cache中找到表定义,在返回之前,会判断table_def_cache中是否太大,如果太大将清理cache中最久没用的表定义。
点击(此处)折叠或打开
|
判断大小的标准是table_def_size变量,table_def_size的定义(sql\sys_vars.cc:2148)如下所示:
点击(此处)折叠或打开
|
从以上代码中可知,table_def_size是全变变量,有效值为:400~512*1024,默认值为:400(TABLE_DEF_CACHE_MIN=400;TABLE_DEF_CACHE_DEFAULT=400)。
因此,由上面分析可知,当table_def_cache中的记录数大于400时,表定义将被置换出cache。被置换出的表如果有操作时,重新加载时,table
id的值就会发生改变。
结论
基于行模式复制的binlog中,table
id的变化依赖于cache中是否存储了binlog操作表的表定义。如果cache中存在,则table id不变;而当cache中不存在时,该值根据上一次操作的table
id自增1。因此,table
id与实际操作的数据表没有直接对应关系,而与操作的数据表是否在cache中有关。此外,table_def_cache中默认存放400个表定义,如果超出该范围,会将最久未用的表定义置换出cache。