一 背景 在 MySQL 8.0 之前,潜文Server 层和存储引擎(比如 InnoDB)会各自保留一份元数据(schema name,详解 table definition 等),不仅在信息存储上有着重复冗余,潜文而且可能存在两者之间存储的详解元数据不同步的现象。不同存储引擎之间(比如 InnoDB 和 MyISAM)有着不同的潜文元数据存储形式和位置(.FRM, .PAR, .OPT, .TRN and .TRG files),造成了元数据无法统一管理。详解此外,潜文将元数据存放在不支持事务的详解表和文件中,使得 DDL 变更不会是潜文原子的,crash recovery 也会成为一个问题。详解 为了解决上述问题,潜文MySQL 在 8.0 中引入了 data dictionary 来进行 Server 层和不同引擎间统一的详解元数据管理,这些元数据都存储在 InnoDB 引擎的潜文表中,自然的详解支持原子性,且 Server 层和引擎层共享一份元数据,潜文不再存在不同步的问题。 二 整体架构 典表的读写操作,包含开表(open table)、构造主键、主键查找等过程。client 和底层存储之间通过两级缓存来加速对元数据对象的内存访问,两级缓存都是源码下载基于 hash map 实现的,一层缓存是 local 的,由每个 client(每个线程对应一个 client)独享;二级缓存是 share 的,为所有线程共享的全局缓存。下面我将对 data dictionary 的数据结构和实现架构做重点介绍,也会分享一个支持原子的 DDL 在 data dictionary 层面的实现过程。 三 metadata 在内存和引擎层面的表示 data dictionary (简称DD)中的数据结构是完全按照多态、接口/实现的形式来组织的,接口通过纯虚类来实现(比如表示一个表的 Table),其实现类(Table_impl)为接口类的名字加 _impl 后缀。下面以 Table_impl 为例介绍一个表的元数据对象在 DD cache 中的表示。 1 Table_impl Table_impl 类中包含一个表相关的元数据属性定义,比如下列最基本引擎类型、comment、高防服务器分区类型、分区表达式等。 Table_impl 也是代码实现中 client 最常访问的内存结构,开发者想要增加新的属性,直接在这个类中添加和初始化即可,但是仅仅如此不会自动将该属性持久化到存储引擎中。除了上述简单属性之外,还包括与一个表相关的复杂属性,比如列信息、索引信息、分区信息等,这些复杂属性都是存在其他的 DD 表中,在内存 cache 中也都会集成到 Table_impl 对象里。 从 Abstract_table_impl 继承来的 Collection m_columns 就表示表的所有列集合,集合中的每一个对象 Column_impl 表示该列的元信息,包括数值类型、是否为 NULL、是否自增、默认值等。同时也包含指向 Abstract_table_impl 的网站模板指针,将该列与其对应的表联系起来。 此外 Table_impl 中也包含所有分区的元信息集合 Collection m_partitions,存放每个分区的 id、引擎、选项、范围值、父子分区等。 因此获取到一个表的 Table_impl,我们就可以获取到与这个表相关联的所有元信息。 2 Table_impl 是如何持久化存储和访问的 DD cache 中的元信息都是在 DD tables 中读取和存储的,每个表存放一类元信息的基本属性字段,比如 tables、columns、indexes等,他们之间通过主外键关联连接起来,组成 Table_impl 的全部元信息。DD tables 存放在 mysql 的表空间中,在 release 版本对用户隐藏,只能通过 INFORMATION SCHEMA 的部分视图查看;在 debug 版本可通过设置 SET debug=+d,skip_dd_table_access_check 直接访问查看。比如: