日期:2014-05-16  浏览次数:20504 次

MySQL源码分析(5):Innodb缓存系统(转)
原文地址:http://software.intel.com/zh-cn/blogs/2010/09/01/mysql5innodb/

Innodb缓存系统

1.buffer操作
(1)根据tbl_test文件的space id和offset检查buffer pool中是否已经有缓存,若有则直接读取该page信息,并返回结果;
(2)若没有缓存则会先分配一个空白的page,然后读取磁盘上的数据加载进内存,并将结果返回。当Sql级别命令执行到Innodb的buffer层时就对应到在buf_pool上的对buffer block的读写等操作。
例如客户端输入以下查询语句:
select * from tbl_test;
层层解析执行至缓存系统中将产生如下动作:(没写全)

2.Innodb buffer pool 系统简介
buf_pool->free, 空闲块链表
buf_pool->flush_list, 待写块链表
buf_pool->LRU, LRU块链表
buf_pool->unzip_LRU, 解压后的LRU块链表
buf_pool->zip_clean, 干净的压缩块链表
buf_pool->zip_free[BUF_BUDDY_SIZE],空闲的压缩块链表

buf0buf.c 是整个buffer系统的核心部分,提供了磁盘文件与内存交互的接口。整个buffer pool主要通过这几个链表来进行组织。
Buf0lru.c是buffer系统中负责缓存替换的算法,主要操作对象是LRU链表,目的是为了更好的使用缓存。
Buf0flu.c是系统中负责写数据到磁盘的部分。为了节省系统的IO开销,Innodb实现该部分时,还考虑当前系统中脏的页数、当前系统的负载等因素。
Buf0rea.c是系统中负责读数据的部分,包括普通的读、预读取、insert buffer、恢复。
Buf0buddy.c二进制伙伴分配算法,在分配压缩过的内存块时使用,避免系统中出现内存碎片。
此外,还包含了mem0pool.c来处理一些底层的数据。

3.读操作(从磁盘上加载数据到内存中)
当数据库文件未使用压缩格式存储时,innodb直接通过buf_LRU_get_free_block获得一个空闲的控制块。而当MySQL配置了压缩格式存储时,系统会通过二进制伙伴算法分配得到一个大小合适的控制块,防止出现内存碎片。主要调用流程如下:



Buf_page_get_gen是InnoDB缓存系统封装给外部系统调用的一个主要API。该函数用途是获得一个包含数据的page,并返回给调用函数。在实际使用时调用栈如下图所示:



4.写操作(从buffer pool中删除page并flush到磁盘上)
入口函数是buf_page_release,用以释放buffer pool中的page,该函数会把脏的数据标记到flush队列中。



在Innodb中有一个主控线程(srv_master_thread),主要负责定时写数据到磁盘文件上,其刷新频率的理论值为1秒或10秒,具体参照服务器当前的负载及buffer pool中脏页的比例动态调整,其主要的代码调用过程如下: