一、buf_page_get_gen
它的作用是将文件数据读入缓存。
前面在“6 InnoDB相关的数据结构”一节中,已经提到了buf_pool_t的初始化;并在事务初始化时,宏buf_page_get会调用buf_page_get_gen。我们知道buf_pool中会缓存多种页:索引页、数据页、undo页等,buf_page_get_gen视为了进入database page。现把它的主要代码展示如下:
本次执行以buf_page_get_gen (space=0, zip_size=0, offset=5, rw_latch=2, guess=0x0, mode=10, file=..., line=120, mtr=0xbfffdfd8)为例。(参考上一篇)
buf_block_t*
buf_page_get_gen(
/*=============*/
ulint space, /*!< in: space id */
ulint zip_size,/*!< in: compressed page size in bytes or 0 for uncompressed pages */
ulint offset, /*!< in: page number */
ulint rw_latch,/*!< in: RW_S_LATCH, RW_X_LATCH, RW_NO_LATCH */
buf_block_t* guess, /*!< in: guessed block or NULL */
ulint mode, /*!< in: BUF_GET, BUF_GET_IF_IN_POOL,
BUF_PEEK_IF_IN_POOL, BUF_GET_NO_LATCH, or
BUF_GET_IF_IN_POOL_OR_WATCH */
const char* file, /*!< in: file name */
ulint line, /*!< in: line where called */
mtr_t* mtr) /*!< in: mini-transaction */ //不可分割的事务,原子性
{
buf_block_t* block;
ulint fold;
unsigned access_time;
ulint fix_type;
ibool must_read;
ulint retries = 0;
buf_pool_t* buf_pool = buf_pool_get(space, offset);
buf_pool->stat.n_page_gets++;
fold = buf_page_address_fold(space, offset); //Calculates a folded value of a file page address to use in the page hash table.
loop:
block = guess;
buf_pool_mutex_enter(buf_pool);
if (block) {
/* If the guess is a compressed page descriptor that
has been allocated by buf_page_alloc_descriptor(),
it may have been freed by buf_relocate(). */
if (!buf_block_is_uncompressed(buf_pool, block)
|| offset != block->page.offset
|| space != block->page.space
|| buf_block_get_state(block) != BUF_BLOCK_FILE_PAGE) {
block = guess = NULL;
} else {
ut_ad(!block->page.in_zip_hash);
ut_ad(block->page.in_page_hash);
}
}
if (block == NULL) {
block = (buf_block_t*) buf_page_hash_get_low(
buf_pool, space, offset, fold); //Returns the control block of a file page
}
if (block && buf_pool_watch_is_sentinel(buf_pool, &block->page)) {
block = NULL;
}
if (block == NULL) {
/* Page not in buf_pool: needs to be read from file */
if (mode == BUF_GET_IF_IN_POOL_OR_WATCH) {
block = (buf_block_t*) buf_pool_watch_set(
space, offset, fold);
if (UNIV_LIKELY_NULL(block)) {
goto got_block;
}
}
buf_pool_mutex_exit(buf_pool);
if (mode == BUF_GET_IF_IN_POOL
|| mode == BUF_PEEK_IF_IN_POOL
|| mode == BUF_GET_IF_IN_POOL_OR_WATCH) {
return(NULL);
}
if (buf_read_page(space, zip_size, offset)) { //异步从文件读入数据到buf_pool
buf_read_ahead_random(space, zip_size, offset, ibuf_inside(mtr));//随机预读相关
retries = 0;
} else if (retries < BUF_PAGE_READ_MAX_RETRIES) {
++retries;
} else {
//打印错误
}
goto loop; //回到loop,这次异步线程已经将数据取来,所以所要找的block就不为空了。
}
got_block:
ut_ad(page_zip_get_size(&block->page.zip) == zip_size);
must_read = buf_block_get_io_fix(block) == BUF_IO_READ; //本例执行中must_read=0
if (must_read && (mode == BUF_GET_IF_IN_POOL
|| mode == BUF_PEEK_IF_IN_POOL)) {
/* The page is being read to buffer pool,
but we cannot wait around for the read to
complete. */
null_exit:
buf_pool_mutex_exit(buf_pool);
return(NULL);
}
switch (buf_block_get_state(block)) {
buf_page_t* bpage;
ibool success;
case BUF_BLOCK_FILE_PAGE: //本例是这种情况,表示该block存的是一个文件页
break;
.... //其他case情况
}
ut_ad(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE);
mutex_enter(&block->mutex);
buf_block_buf_fix_inc(block, file, line); //block->page.buf_fix_count++;
buf_pool_mutex_exit(buf_pool);
/* Check if this is the firs