官方的修复就比较优雅了,不改变任何现有的存储,而是通过redo log来进行恢复。该补丁基于WL#7816的框架实现的,要想搞懂这个补丁,得先看看WL#7816做了哪些改动,为了解决这个问题,InnoDB使用一个引擎私有的系统表+特殊redo log的方式,在引擎内部自己解决corruption标记持久化的问题。其大概思路为:
初始化Persister
目前Persister的类型仅有两种,一个用于corruption bit的持久化,一个用于自增列的持久化,对应的类为: Persister: |-- CorruptedIndexPersister |-- AutoIncPersister Persister对应全局对象dict_persist_t::persisters,可以通过类型persistent_type_t来找到对应的Persister,目前仅有PM_INDEX_CORRUPTED及PM_TABLE_AUTO_INC,但从注释来看,未来肯定会做更多的扩展,Persister在启动时调用函数dict_persist_init进行初始化。
新的系统表
新的系统表名为SYS_TABLE_INFO_BUFFER,对应管理类为DDTableBuffer,指针存储在dict_persist->table_buffer中。 系统表包含两个列:TABLE_ID及BLOB类型的METADATA(ref DDTableBuffer::init),METADATA列包含了所有需要持久化的元数据。
回写DDTableBuffer
有几种情况会将内存修改回写到DDTableBuffer中:
ha_innobase::commit_inplace_alter_table create_table_info_t::initialize_autoinc() // for example: alter table..auto_increment = ?? row_rename_table_for_mysql; // rename from temporary table to normal table 回写的过程也比较简单(dict_table_persist_to_dd_table_buffer_low):
Recovery and Startup
在崩溃恢复时,当解析到日志MLOG_TABLE_DYNAMIC_META时(MetadataRecover::parseMetadataLog),会进行解析并将解析得到的数据存储到集合中(MetadataRecover::m_tables),如果存在相同table-id的项,就进行替换,确保总是最新的。 在完成recovery后,搜集到的meta信息暂时存储到srv_dict_metadata中, 随后进行apply(srv_dict_recover_on_restart), apply的过程也比较简单,载入表对象,然后对表对象进行更新(MetadataRecover::apply),例如对于autoinc列,就总是选择更大的那个值。
最后
这个bug已经挂了相当长的时间,不排除把这个bug当作InnoDB的“特性”的同学,一定要注意到这个改动... (责任编辑:IT) |