row-based replication引入此事件
TABLE_MAP_EVENT:
The TABLE_MAP_EVENT defines the structure if the tables that are about to be changed
row模式下,主库的DML对应一个table_map_event和一系列INSERT/UPDATE/WRITE_ROWS_EVENT;
table_map_event对应的class是Table_map_log_event(对应源码sql/log_event.cc),它保存了本次DML操作对应的:table_id,数据库名,表名,字段数,字段类型等,而这些信息都是从table_definition_cache通过get(table_id)获取的。
table_id的用途
innodb采用table_definition_cache缓存表的metadata,cache采用hash table结构,table_id用来做hash key;
通过set_table(table_id)的方法将某个表的信息hash到cache中,又可以通过get_table()方法来根据table_id获得对应的表信息;
table_id和数据库表并非是固定的对应关系,table id在mysql实例生命周期内是递增的;
如果table cache中已经存在该表,则table id不变,而当table cache中不存在时,该值根据上一次操作的table id自增1。
此外,table_definition_cache中默认存放400个表定义,如果超出该范围,会将最久未用的表定义置换出table cache。
table_map_event记录了table_id,而row_log_event也记录了table_id,两者通过table_id关联。
slave先解析table_map_event并存于内存,而后的row_log_event通过table_id找到对应的表信息。
这里的table_id的类型为ulong。
RPL_TABLE_LIST
RPL_TABLE_LIST是包含在Relay_log_info结构(对应源码sql/rpl_mi.h)中的,它记录了这次变更需要lock的多个表信息。
RPL_TABLE_LIST结构(对应源码sql/rpl_utility.h)的父类TABLE_LIST(对应源码:sql/table.h)中定义table_id为:
uint table_id; /* table id (from binlog) for opened table */ //这里就是最终需要bug fix的地方
这里定义为uint和其他地方定义为ulong不一样!
当slave执行table_map_event时,会把table_map_event信息解析到RRL_TABLE_LIST中,同时table_map_event->table_id(ulong)赋值给RPL_TABLE_LIST->table_id(ulint),当前者数值超出ulit时会发生截断;
而执行row_log_event时又需要通过get_table(table_id)从内存中获取表信息,当上面的赋值发生截断时便会产生错误。
解决方案
1、自己打patch,重编译并替换线上MySQL
2、增加table cache 大小。
3、重启主库让table_id归零。
参考资料
http://hatemysql.com/2012/11/23/
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/15480802/viewspace-1430318/
,如需转载,请注明出处,否则将追究法律责任。