导读 这是MySQL8.0修复的上古bug之一,在2003年由Percona的CEO(当时应该还没Percona吧)提出的bug#199,光看这bug号就扑面而来一股上古时代的沧桑气息。


问题的本质在于InnoDB初始化AUTO_INCREMENT的方式,在每次重启时,总是算出表上最大的自增值作为最大值,下一次分配从该值开始。这意味着如果在btree右侧叶节点大量删除记录,重启后,自增值可能被重用。这在很多场景下可能导致问题,包括但不限于:主备切换、历史数据迁移等场景。在bug#199下面一大堆的回复里,可以看到大量的同行抱怨。

官方的修复就比较优雅了,不改变任何现有的存储,而是通过redo log来进行恢复。该补丁基于WL#7816的框架实现的,要想搞懂这个补丁,得先看看WL#7816做了哪些改动,为了解决这个问题,InnoDB使用一个引擎私有的系统表+特殊redo log的方式,在引擎内部自己解决corruption标记持久化的问题。其大概思路为:

  1. 当发现索引损坏时,写入一条redo log,但不更新数据词典
  2. 引入一个innodb引擎私有的系统表,称为DD Buffer Table,每次checkpoint之前会将索引corruption bit存入其中。
  3. 在崩溃恢复时,同时从redo log和DD Buffer Table中读取索引 corruption bit, 合并结果,并标记内存中的表和索引对象。
初始化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中:

  1. 在做checkpoint(log_checkpoint)之前,所有在dirty_dict_tables链表上的表对象,对应persist metadata都需要回写到DDTableBuffer中(dict_persist_to_dd_table_buffer)
  2. 从内存中驱逐一个表对象时(dict_table_remove_from_cache_low),如果需要的话也会去尝试回写。
  3. 在对包含自增列的表做DDL后,需要持久化counter,在如下函数中,会调用dict_table_set_and_persist_autoinc:
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):

  1. 通过表对象初始化需要回写的Metadata数据: corrupt index及autoinc值(dict_init_dynamic_metadata)
  2. 构建记录值,插入DDTableBuffer系统表(DDTableBuffer::replace(), 如果记录存在的话,则进行悲观更新操作
  3. 表对象的diry_status修改成 METADATA_BUFFERED,表示有buffer的元数据
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的“特性”的同学,一定要注意到这个改动...

本文地址:http://www.linuxprobe.com/mysql-bug.html

悲剧啊!Mysql的上古BUG!!!的更多相关文章

  1. 一个MySQL JDBC驱动bug引起的血案

    1.1      问题背景 公司是做电商系统的,整个系统搭建在华为云上.系统设计的时候,考虑到后续的用户和订单数量比较大,需要使用一些大数据库的组件.关系型数据库这块,考虑到后续数据量的快速增长,不是 ...

  2. "Cannot convert value '0000-00-00' from column 2 to TIMESTAMP"mysql时间转换bug

    今天在项目中遇到这样的一个bug,Cannot convert value '0000-00-00' from column 2 to TIMESTAMP 仔细一查,经过http://blog.csd ...

  3. Spring+SpringMVC+MyBatis+easyUI整合基础篇(八)mysql中文查询bug修复

    写在前面的话 在测试搜索时出现的问题,mysql通过中文查询条件搜索不出数据,但是英文和数字可以搜索到记录,中文无返回记录.本文就是写一下发现问题的过程及解决方法.此bug在第一个项目中点这里还存在, ...

  4. mysql 5.6 bug

    https://dev.mysql.com/doc/refman/5.6/en/account-management-sql.html USE mysql; SELECT Host,User FROM ...

  5. 【MySQL 线上 BUG 分析】之 多表同字段异常:Column ‘xxx’ in field list is ambiguous

    一.生产出错! 今天早上11点左右,我在工作休息之余,撸了一下猫.突然,工作群响了,老大在里面说:APP出错了! 妈啊,这太吓人了,因为只是说了出错,但是没说错误的信息.所以我赶紧到APP上看看. 这 ...

  6. 分享2个近期遇到的MySQL数据库的BUG案例

    近一个月处理历史数据问题时,居然连续遇到了2个MySQL BUG,分享给大家一下,也欢迎指正是否有问题. BUG1: 数据库版本:  MySQL5.7.25 - 28 操作系统: Centos 7.7 ...

  7. MySQL 的一个Bug?

    在 my.ini 中的 [mysqld] 段设置 mysql basedir 和 datadir,如下: #Path to installation directory. All paths are ...

  8. Powser Design 16.5 导入Mysql数据库的bug

    在Power Designer 16.5中,想导入mysql的某个数据库,选择导入后会导入全部数据库. 解决方案: 打开powerdesigner.选择file--->reverse engin ...

  9. MySql 参数赋值bug (MySql.Data, Version=6.9.6.0 沙雕玩意)

    直接将参数赋值为常量0则参数值为null,出现异常:MySql.Data.MySqlClient.MySqlException (0x80004005): Column 'PayType' canno ...

随机推荐

  1. Spring.net 配置说明

    Spring.net使用说明   使用方法: 1.在配置文件设置Spring.net 节点  在配置节中,声明Spring.net,配置 context,objects 标签,来源(type) < ...

  2. [LeetCode] 4Sum II 四数之和之二

    Given four lists A, B, C, D of integer values, compute how many tuples (i, j, k, l) there are such t ...

  3. 写出将字符串中的数字转换为整型的方法,如:“as31d2v”->312,并写出相应的单元测试,正则去掉非数值、小数点及正负号外的字符串

    写出将字符串中的数字转换为整型的方法,如:"as31d2v"->312,并写出相应的单元测试,输入超过int范围时提示不合法输入. public struct Convert ...

  4. 【WPF】整个自定义按钮后台添加

  5. 关于CAJViewer 无法获取document路径问题

    修改注册表 进入注册表编辑器: win+R >>输入 regedit  如下图: 修改关键注册表项(两项相同值应同时修改) 1.HKEY_CURRENT_USER\Software\Mic ...

  6. react native 图片样式导致的坑

    最近项目中遇到一个问题,代码如下,点击进入另一个页面时需要显示的图片会黑屏,另外退回到该页面的时候下面代码中的第一个图片会全黑几秒才渲染,从另一个路径进入该页面时并没有此问题,就找了半天是不是数据的问 ...

  7. JavaScript系列文章:自动类型转换-续

    在上一篇文章中,我们详细讲解了JavaScript中的自动类型转换,由于篇幅限制,没能覆盖到所有的转换规则,这次准备详细讲解一下. 上次我们提到了对象类型参与运算时转换规则: 1). 在逻辑环境中执行 ...

  8. UVA445

    测试了很多数据都没问题,但是就是一直WA... #include<stdio.h> #include<string.h> int main(){ ]; int n; while ...

  9. js中网页区域/正文/屏幕 宽和高

    网页可见区域宽: document.body.clientWidth; 网页可见区域高: document.body.clientHeight; 网页可见区域宽: document.body.offs ...

  10. Linux系统下设置环境变量

    例如我现在有一个软件understand代码审阅软件,现在我每次想要打开这个软件就要进到~/scitools/bin/linux32目录下,去执行可执行文件understand; 但每次都这样我会觉得 ...