- 深入理解MySQL主从原理
- 高鹏
- 969字
- 2021-04-16 16:29:31
2.4.2 MAP_EVENT
1.MAP_EVENT的作用
MAP_EVENT是行模式特有的,它的主要作用是映射table id和实际访问表。其中还包含了一些表的定义,如表所在库名、表名、字段类型、可变字段长度等。这里的库名和QUERY_EVENT的库名不一样,这个库名来自表的定义,而QUERY_EVENT的库名来自当前登录的数据库,即源码变量thd->db。
2.源码重要接口
主库
· 初始化构造函数:Table_map_log_event::Table_map_log_event(THD *thd_arg,TABLE *tbl,const Table_id& tid,bool is_transactional);
· 写入binlog cache:Table_map_log_event::write_data_header,Table_map_log_event::write_data_body。
从库
· 读取构造函数:Table_map_log_event(const char *buf,uint event_len,const Format_description_event *description_event);
· 应用函数:Table_map_log_event::do_apply_event。
3.主体格式
MAP_EVENT的主体格式如图2-6所示。
![](https://epubservercos.yuewen.com/A01218/19823444008569806/epubprivate/OEBPS/Images/txt002_23.jpg?sign=1738872528-6abpMtVjEEHZz1yDZ8i5trHVpZdqo62n-0-34210422e31b51414a8217233e1ab6cd)
图2-6
其中,固定部分如下。
table_id:6字节,这个table_id和InnoDB层的table_id不一样,它分配的时机是第一次打开表定义时。它不是固定的,重启MySQL实例或者执行flush table命令都会导致其改变。下面是table_id更改的代码:
![](https://epubservercos.yuewen.com/A01218/19823444008569806/epubprivate/OEBPS/Images/txt002_24.jpg?sign=1738872528-uPMtb1450hmZ2yepoR3xpkJFCY9rGT26-0-d198349476a37165ebfc47c0d4d3b5e5)
Reserved:2字节,保留以后使用。
可变部分如下。
db len:表所在数据库名的长度。
db name:实际数据库名,以0x00结尾。
table len:表名的长度。
table name:实际表名,以0x00结尾。
no of cols:表中字段数量。
array of col types:字段的类型数组。
metadata len:metadata block的长度。
metadata block:对于可变字段需要记录字段的长度,但对于int这种数据类型就不需要了,因为它的长度是固定的。下面代码是varchar关于可变长度的输出,它占用2字节。
![](https://epubservercos.yuewen.com/A01218/19823444008569806/epubprivate/OEBPS/Images/txt002_25.jpg?sign=1738872528-EL6GUzKbbyvd2Y7K5731MwInbdxYuJw5-0-7e36033cffe0867e48436f7d575bc4d7)
如果感兴趣可以查看do_save_field_metadata函数。
m_null_bits:一个位图,用于表示字段是否可以为空。下面是位图的获取方式。
![](https://epubservercos.yuewen.com/A01218/19823444008569806/epubprivate/OEBPS/Images/txt002_26.jpg?sign=1738872528-99LDPDaehjizXf82sUgylDaH9RrnOquX-0-fe329c8e17ffb118d8b65b0dc4420064)
4.实例解析
执行如下语句:
![](https://epubservercos.yuewen.com/A01218/19823444008569806/epubprivate/OEBPS/Images/txt002_27.jpg?sign=1738872528-yIli0EyHRdBZwNKD7e3wWhWhl19RCmtK-0-188828cb994d29ad1377e3675b6698f0)
这个INSERT语句的MAP_EVENT如下:
![](https://epubservercos.yuewen.com/A01218/19823444008569806/epubprivate/OEBPS/Images/txt002_28.jpg?sign=1738872528-htqW9EplDzbY0ltVEL10qEQxf52DismI-0-f0914a8231f811f06a0ab8c235eb95ab)
其中,6c 00 00 00 00 00:表示table_id,即十六进制值6c,转换为十进制值108。
01 00:保留。
02:表所在的数据库名长度为2。
67 70 00:数据库名gp的ASCII表示,以0x00结尾。
02:表名的长度为2。
74 79 00:表名ty的ASCII表示,以0x00结尾。
03:表拥有3个字段。
03 03 03:每个字段的类型都是03,实际就是int。具体可以参考enum_field_types这个枚举类型。
00:metadata长度为0,没有可变字段。
06:位图,即二进制值110,表示第一个字段不可以为空,其他两个字段可以为空。
5.生成时机
本 Event 只会在行模式下生成。生成时机是事务的每条 DML 语句修改的第一行数据在InnoDB 引擎层修改完成,并且在QUERY_EVENT生成之后。通常来讲,每个语句的每个表都会包含这样一个MAP_EVENT。
6.table_id的易变性
前面我们说过了,table_id是可变的,现在来构造这种情况,如表2-1所示,还是使用上面的ty表。
表2-1
![img](https://epubservercos.yuewen.com/A01218/19823444008569806/epubprivate/OEBPS/Images/txt002_29.jpg?sign=1738872528-KLDXjo7oxThCBohXhOzg5OXfY5SADZ0k-0-e08f139ed92220148422926c7db3bcf5)
我们可以观察到如下情况(输出做了适当换行)。
![](https://epubservercos.yuewen.com/A01218/19823444008569806/epubprivate/OEBPS/Images/txt002_30.jpg?sign=1738872528-d7XiPstxyk4NabDhqBxeq4el2KHP6Emm-0-7dc9895bb7de42b79c8d7597ef2fe7a7)
![](https://epubservercos.yuewen.com/A01218/19823444008569806/epubprivate/OEBPS/Images/txt002_31.jpg?sign=1738872528-09kNUfxjeLt5Bk7wrGL0ZSeR5w41iKpd-0-fa75772cbaed90b95d86649cae966355)
这是一个事务,其中,相同表的table_id却不一样,可以观察到如下现象。
· at 2434:Table_map:gp.ty mapped to number 133。
· at 2527:Table_map:gp.ty mapped to number 147。
我们发现,这里同样的ty表对应了两个不同的table_id,证明table_id是可变的。