来源: MySQL 深潜 - 一文详解 MySQL Data Dictionary - 知乎
背景
在 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 层和引擎层共享一份元数据,不再存在不同步的问题。
整体架构
data dictionary 提供了统一的 client API 供 Server 层和引擎层使用,包含对元数据访问的 acquire() / drop() / store() / update() 基本操作。底层实现了对 InnoDB 引擎存放的数据字典表的读写操作,包含开表(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 中的表示。
Table_impl
Table_impl 类中包含一个表相关的元数据属性定义,比如下列最基本引擎类型、comment、分区类型、分区表达式等。
class Table_impl : public Abstract_table_impl, virtual public Table {
// Fields.
Object_id m_se_private_id;
String_type m_engine;
String_type m_comment;
// - Partitioning related fields.
enum_partition_type m_partition_type;
String_type m_partition_expression;
String_type m_partition_expression_utf8;
enum_default_partitioning m_default_partitioning;
// References to tightly-coupled objects.
Index_collection m_indexes;
Foreign_key_collection m_foreign_keys;
Foreign_key_parent_collection m_foreign_key_parents;
Partition_collection m_partitions;
Partition_leaf_vector m_leaf_partitions;
Trigger_collection m_triggers;
Check_constraint_collection m_check_constraints;
};
Table_impl 也是代码实现中 client 最常访问的内存结构,开发者想要增加新的属性,直接在这个类中添加和初始化即可,但是仅仅如此不会自动将该属性持久化到存储引擎中。除了上述简单属性之外,还包括与一个表相关的复杂属性,比如列信息、索引信息、分区信息等,这些复杂属性都是存在其他的 DD 表中,在内存 cache 中也都会集成到 Table_impl 对象里。
从 Abstract_table_impl 继承来的 Collection<Column *> m_columns 就表示表的所有列集合,集合中的每一个对象 Column_impl 表示该列的元信息。包括数值类型、是否为 NULL、是否自增、默认值等等。
class Column_impl : public Entity_object_impl, public Column {
// Fields.
enum_column_types m_type;
bool m_is_nullable;
bool m_is_zerofill;
bool m_is_unsigned;
bool m_is_auto_increment;
bool m_is_virtual;
bool m_default_value_null;