测试了两个case,属于之前blog的遗留问题:
- innodb如何加载数据字典
- flush tables都做了什么操作
先来看下innodb加载数据字典:
首次使用:select * from tt;
1. 创建handler对象
函数调用栈:
open_binary_frm
get_new_handler
innobase_create_handler
ha_innobase::ha_innobase
根据单实例 handlerton + table_share两个参数,创建了handler对象,赋值table->file。server层对innodb的操作,都通过这个接口完成。
2. open innobase_share
innobase_share是innodb层对某张表的定义,全局共享结构, 受 innobase_share_mutex保护。
innobase_open_tables hash表保存着所有的INNOBASE_SHARE。
这里完成初始化一个innobase_share结构。
3. 加载数据字典:
初始化innodb_share中的dict_table_t
步骤:
mutex_enter(&(dict_sys->mutex));
dict_sys_t:整个系统的数据字典, 全局的 dict_sys_t* dict_sys;
包括:hash_table_t* table_hash; /*!< hash table of the tables, based
包括:UT_LIST_BASE_NODE_T(dict_table_t) table_LRU; /*!< LRU list of tables */
dict_table_get
dict_table_get_low
存在: dict_table_check_if_in_cache_low: 从hash表中取出,并更新lru链表。
不存在:dict_load_table
1. load 表定义
2. load columns
3. load index
4. load foreign key
注:数组字典使用了两个结构存储,一个hash方便查询, 一个是lru链表,用于缓存的置换。
flush tables;
reload_acl_and_cache:
1. 清空query_cache:使用structure_guard_mutex锁。
2. close_cached_tables:关闭没有使用的。使用LOCK_open锁进行保护。
3. 递增:refresh_version
free_cache_entry: free掉 table_cache中的table
inter_close_table: 清空 io_cache
closefrm:
- 关闭handler
- free innobase_share
- 释放table_share: 从table_def_cache上删除。
记录binlog:
flush talbes记录了statement的binlog。
注: 如果使用了flush tables with read lock:将使用global的read lock, 通过meta lock来实现。
结论:
对于一个表, flush_tables一共关闭了 table, table_share, handler, innobase_share. 只保留了dict_table_t数据字典。
flush tables不关闭正在使用的,当table再次使用的时候,发现version已经发生了变化,就关闭,并重新打开。