mirror of
https://github.com/MariaDB/server.git
synced 2025-01-20 05:52:27 +01:00
2ddbc912e7
For some reason, GCC 4.2.1 ignores casts (for removing constness) in calls to inline functions. page_align(), ut_align_down(): Make the parameter const void*, but still return a non-const pointer. This is ugly, but these functions cannot be replaced with a const-preserving macro in a portable way, given that the pointer argument is not always pointing to bytes. buf_block_get_page_zip(): Implement as a const-preserving macro. buf_frame_get_page_zip(), buf_block_align(): Add const qualifiers. lock_rec_get_prev(): Silence GCC 4.2.1 warnings. mlog_write_initial_log_record(), mlog_write_initial_log_record_fast(), mtr_memo_contains(): Add const qualifier to the pointer. page_header_get_ptr(): Rewrite as page_header_get_offs(), and implement as a macro that calls this function.
1086 lines
28 KiB
Text
1086 lines
28 KiB
Text
/******************************************************
|
|
The database buffer buf_pool
|
|
|
|
(c) 1995 Innobase Oy
|
|
|
|
Created 11/5/1995 Heikki Tuuri
|
|
*******************************************************/
|
|
|
|
#include "buf0flu.h"
|
|
#include "buf0lru.h"
|
|
#include "buf0rea.h"
|
|
#include "mtr0mtr.h"
|
|
|
|
/************************************************************************
|
|
Reads the freed_page_clock of a buffer block. */
|
|
UNIV_INLINE
|
|
ulint
|
|
buf_page_get_freed_page_clock(
|
|
/*==========================*/
|
|
/* out: freed_page_clock */
|
|
const buf_page_t* bpage) /* in: block */
|
|
{
|
|
return(bpage->freed_page_clock);
|
|
}
|
|
|
|
/************************************************************************
|
|
Reads the freed_page_clock of a buffer block. */
|
|
UNIV_INLINE
|
|
ulint
|
|
buf_block_get_freed_page_clock(
|
|
/*===========================*/
|
|
/* out: freed_page_clock */
|
|
const buf_block_t* block) /* in: block */
|
|
{
|
|
return(buf_page_get_freed_page_clock(&block->page));
|
|
}
|
|
|
|
/************************************************************************
|
|
Recommends a move of a block to the start of the LRU list if there is danger
|
|
of dropping from the buffer pool. NOTE: does not reserve the buffer pool
|
|
mutex. */
|
|
UNIV_INLINE
|
|
ibool
|
|
buf_page_peek_if_too_old(
|
|
/*=====================*/
|
|
/* out: TRUE if should be made
|
|
younger */
|
|
const buf_page_t* bpage) /* in: block to make younger */
|
|
{
|
|
return(buf_pool->freed_page_clock
|
|
>= buf_page_get_freed_page_clock(bpage)
|
|
+ 1 + (buf_pool->curr_size / 4));
|
|
}
|
|
|
|
/*************************************************************************
|
|
Gets the current size of buffer buf_pool in bytes. */
|
|
UNIV_INLINE
|
|
ulint
|
|
buf_pool_get_curr_size(void)
|
|
/*========================*/
|
|
/* out: size in bytes */
|
|
{
|
|
return(buf_pool->curr_size * UNIV_PAGE_SIZE);
|
|
}
|
|
|
|
/************************************************************************
|
|
Gets the smallest oldest_modification lsn for any page in the pool. Returns
|
|
zero if all modified pages have been flushed to disk. */
|
|
UNIV_INLINE
|
|
ib_uint64_t
|
|
buf_pool_get_oldest_modification(void)
|
|
/*==================================*/
|
|
/* out: oldest modification in pool,
|
|
zero if none */
|
|
{
|
|
buf_page_t* bpage;
|
|
ib_uint64_t lsn;
|
|
|
|
mutex_enter(&(buf_pool->mutex));
|
|
|
|
bpage = UT_LIST_GET_LAST(buf_pool->flush_list);
|
|
|
|
if (bpage == NULL) {
|
|
lsn = 0;
|
|
} else {
|
|
ut_ad(bpage->in_flush_list);
|
|
lsn = bpage->oldest_modification;
|
|
}
|
|
|
|
mutex_exit(&(buf_pool->mutex));
|
|
|
|
return(lsn);
|
|
}
|
|
|
|
/***********************************************************************
|
|
Increments the buf_pool clock by one and returns its new value. Remember
|
|
that in the 32 bit version the clock wraps around at 4 billion! */
|
|
UNIV_INLINE
|
|
ulint
|
|
buf_pool_clock_tic(void)
|
|
/*====================*/
|
|
/* out: new clock value */
|
|
{
|
|
ut_ad(mutex_own(&(buf_pool->mutex)));
|
|
|
|
buf_pool->ulint_clock++;
|
|
|
|
return(buf_pool->ulint_clock);
|
|
}
|
|
|
|
/*************************************************************************
|
|
Gets the state of a block. */
|
|
UNIV_INLINE
|
|
enum buf_page_state
|
|
buf_page_get_state(
|
|
/*===============*/
|
|
/* out: state */
|
|
const buf_page_t* bpage) /* in: pointer to the control block */
|
|
{
|
|
enum buf_page_state state = (enum buf_page_state) bpage->state;
|
|
|
|
#ifdef UNIV_DEBUG
|
|
switch (state) {
|
|
case BUF_BLOCK_ZIP_FREE:
|
|
case BUF_BLOCK_ZIP_PAGE:
|
|
case BUF_BLOCK_ZIP_DIRTY:
|
|
case BUF_BLOCK_NOT_USED:
|
|
case BUF_BLOCK_READY_FOR_USE:
|
|
case BUF_BLOCK_FILE_PAGE:
|
|
case BUF_BLOCK_MEMORY:
|
|
case BUF_BLOCK_REMOVE_HASH:
|
|
break;
|
|
default:
|
|
ut_error;
|
|
}
|
|
#endif /* UNIV_DEBUG */
|
|
|
|
return(state);
|
|
}
|
|
/*************************************************************************
|
|
Gets the state of a block. */
|
|
UNIV_INLINE
|
|
enum buf_page_state
|
|
buf_block_get_state(
|
|
/*================*/
|
|
/* out: state */
|
|
const buf_block_t* block) /* in: pointer to the control block */
|
|
{
|
|
return(buf_page_get_state(&block->page));
|
|
}
|
|
/*************************************************************************
|
|
Sets the state of a block. */
|
|
UNIV_INLINE
|
|
void
|
|
buf_page_set_state(
|
|
/*===============*/
|
|
buf_page_t* bpage, /* in/out: pointer to control block */
|
|
enum buf_page_state state) /* in: state */
|
|
{
|
|
#ifdef UNIV_DEBUG
|
|
enum buf_page_state old_state = buf_page_get_state(bpage);
|
|
|
|
switch (old_state) {
|
|
case BUF_BLOCK_ZIP_FREE:
|
|
ut_error;
|
|
break;
|
|
case BUF_BLOCK_ZIP_PAGE:
|
|
ut_a(state == BUF_BLOCK_ZIP_DIRTY);
|
|
break;
|
|
case BUF_BLOCK_ZIP_DIRTY:
|
|
ut_a(state == BUF_BLOCK_ZIP_PAGE);
|
|
break;
|
|
case BUF_BLOCK_NOT_USED:
|
|
ut_a(state == BUF_BLOCK_READY_FOR_USE);
|
|
break;
|
|
case BUF_BLOCK_READY_FOR_USE:
|
|
ut_a(state == BUF_BLOCK_MEMORY
|
|
|| state == BUF_BLOCK_FILE_PAGE
|
|
|| state == BUF_BLOCK_NOT_USED);
|
|
break;
|
|
case BUF_BLOCK_MEMORY:
|
|
ut_a(state == BUF_BLOCK_NOT_USED);
|
|
break;
|
|
case BUF_BLOCK_FILE_PAGE:
|
|
ut_a(state == BUF_BLOCK_NOT_USED
|
|
|| state == BUF_BLOCK_REMOVE_HASH);
|
|
break;
|
|
case BUF_BLOCK_REMOVE_HASH:
|
|
ut_a(state == BUF_BLOCK_MEMORY);
|
|
break;
|
|
}
|
|
#endif /* UNIV_DEBUG */
|
|
bpage->state = state;
|
|
ut_ad(buf_page_get_state(bpage) == state);
|
|
}
|
|
|
|
/*************************************************************************
|
|
Sets the state of a block. */
|
|
UNIV_INLINE
|
|
void
|
|
buf_block_set_state(
|
|
/*================*/
|
|
buf_block_t* block, /* in/out: pointer to control block */
|
|
enum buf_page_state state) /* in: state */
|
|
{
|
|
buf_page_set_state(&block->page, state);
|
|
}
|
|
|
|
/*************************************************************************
|
|
Determines if a block is mapped to a tablespace. */
|
|
UNIV_INLINE
|
|
ibool
|
|
buf_page_in_file(
|
|
/*=============*/
|
|
/* out: TRUE if mapped */
|
|
const buf_page_t* bpage) /* in: pointer to control block */
|
|
{
|
|
switch (buf_page_get_state(bpage)) {
|
|
case BUF_BLOCK_ZIP_FREE:
|
|
/* This is a free page in buf_pool->zip_free[].
|
|
Such pages should only be accessed by the buddy allocator. */
|
|
ut_error;
|
|
break;
|
|
case BUF_BLOCK_ZIP_PAGE:
|
|
case BUF_BLOCK_ZIP_DIRTY:
|
|
case BUF_BLOCK_FILE_PAGE:
|
|
return(TRUE);
|
|
case BUF_BLOCK_NOT_USED:
|
|
case BUF_BLOCK_READY_FOR_USE:
|
|
case BUF_BLOCK_MEMORY:
|
|
case BUF_BLOCK_REMOVE_HASH:
|
|
break;
|
|
}
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
/*************************************************************************
|
|
Determine the approximate LRU list position of a block. */
|
|
UNIV_INLINE
|
|
ulint
|
|
buf_page_get_LRU_position(
|
|
/*======================*/
|
|
/* out: LRU list position */
|
|
const buf_page_t* bpage) /* in: control block */
|
|
{
|
|
ut_ad(buf_page_in_file(bpage));
|
|
|
|
return(bpage->LRU_position);
|
|
}
|
|
|
|
/*************************************************************************
|
|
Gets the mutex of a block. */
|
|
UNIV_INLINE
|
|
mutex_t*
|
|
buf_page_get_mutex(
|
|
/*===============*/
|
|
/* out: pointer to mutex protecting bpage */
|
|
buf_page_t* bpage) /* in: pointer to control block */
|
|
{
|
|
switch (buf_page_get_state(bpage)) {
|
|
case BUF_BLOCK_ZIP_FREE:
|
|
ut_error;
|
|
break;
|
|
case BUF_BLOCK_ZIP_PAGE:
|
|
case BUF_BLOCK_ZIP_DIRTY:
|
|
return(&buf_pool->zip_mutex);
|
|
default:
|
|
return(&((buf_block_t*) bpage)->mutex);
|
|
}
|
|
}
|
|
|
|
/*************************************************************************
|
|
Get the flush type of a page. */
|
|
UNIV_INLINE
|
|
enum buf_flush
|
|
buf_page_get_flush_type(
|
|
/*====================*/
|
|
/* out: flush type */
|
|
const buf_page_t* bpage) /* in: buffer page */
|
|
{
|
|
enum buf_flush flush_type = (enum buf_flush) bpage->flush_type;
|
|
|
|
#ifdef UNIV_DEBUG
|
|
switch (flush_type) {
|
|
case BUF_FLUSH_LRU:
|
|
case BUF_FLUSH_SINGLE_PAGE:
|
|
case BUF_FLUSH_LIST:
|
|
return(flush_type);
|
|
case BUF_FLUSH_N_TYPES:
|
|
break;
|
|
}
|
|
ut_error;
|
|
#endif /* UNIV_DEBUG */
|
|
return(flush_type);
|
|
}
|
|
/*************************************************************************
|
|
Set the flush type of a page. */
|
|
UNIV_INLINE
|
|
void
|
|
buf_page_set_flush_type(
|
|
/*====================*/
|
|
buf_page_t* bpage, /* in: buffer page */
|
|
enum buf_flush flush_type) /* in: flush type */
|
|
{
|
|
bpage->flush_type = flush_type;
|
|
ut_ad(buf_page_get_flush_type(bpage) == flush_type);
|
|
}
|
|
|
|
/*************************************************************************
|
|
Map a block to a file page. */
|
|
UNIV_INLINE
|
|
void
|
|
buf_block_set_file_page(
|
|
/*====================*/
|
|
buf_block_t* block, /* in/out: pointer to control block */
|
|
ulint space, /* in: tablespace id */
|
|
ulint page_no)/* in: page number */
|
|
{
|
|
buf_block_set_state(block, BUF_BLOCK_FILE_PAGE);
|
|
block->page.space = space;
|
|
block->page.offset = page_no;
|
|
}
|
|
|
|
/*************************************************************************
|
|
Gets the io_fix state of a block. */
|
|
UNIV_INLINE
|
|
enum buf_io_fix
|
|
buf_page_get_io_fix(
|
|
/*================*/
|
|
/* out: io_fix state */
|
|
const buf_page_t* bpage) /* in: pointer to the control block */
|
|
{
|
|
enum buf_io_fix io_fix = (enum buf_io_fix) bpage->io_fix;
|
|
#ifdef UNIV_DEBUG
|
|
switch (io_fix) {
|
|
case BUF_IO_NONE:
|
|
case BUF_IO_READ:
|
|
case BUF_IO_WRITE:
|
|
return(io_fix);
|
|
}
|
|
ut_error;
|
|
#endif /* UNIV_DEBUG */
|
|
return(io_fix);
|
|
}
|
|
|
|
/*************************************************************************
|
|
Gets the io_fix state of a block. */
|
|
UNIV_INLINE
|
|
enum buf_io_fix
|
|
buf_block_get_io_fix(
|
|
/*================*/
|
|
/* out: io_fix state */
|
|
const buf_block_t* block) /* in: pointer to the control block */
|
|
{
|
|
return(buf_page_get_io_fix(&block->page));
|
|
}
|
|
|
|
/*************************************************************************
|
|
Sets the io_fix state of a block. */
|
|
UNIV_INLINE
|
|
void
|
|
buf_page_set_io_fix(
|
|
/*================*/
|
|
buf_page_t* bpage, /* in/out: control block */
|
|
enum buf_io_fix io_fix) /* in: io_fix state */
|
|
{
|
|
ut_ad(mutex_own(&buf_pool->mutex));
|
|
ut_ad(mutex_own(buf_page_get_mutex(bpage)));
|
|
|
|
bpage->io_fix = io_fix;
|
|
ut_ad(buf_page_get_io_fix(bpage) == io_fix);
|
|
}
|
|
|
|
/*************************************************************************
|
|
Sets the io_fix state of a block. */
|
|
UNIV_INLINE
|
|
void
|
|
buf_block_set_io_fix(
|
|
/*=================*/
|
|
buf_block_t* block, /* in/out: control block */
|
|
enum buf_io_fix io_fix) /* in: io_fix state */
|
|
{
|
|
buf_page_set_io_fix(&block->page, io_fix);
|
|
}
|
|
|
|
/************************************************************************
|
|
Determine if a buffer block can be relocated in memory. The block
|
|
can be dirty, but it must not be I/O-fixed or bufferfixed. */
|
|
UNIV_INLINE
|
|
ibool
|
|
buf_page_can_relocate(
|
|
/*==================*/
|
|
const buf_page_t* bpage) /* control block being relocated */
|
|
{
|
|
ut_ad(mutex_own(&buf_pool->mutex));
|
|
ut_ad(mutex_own(buf_page_get_mutex((buf_page_t*) bpage)));
|
|
ut_ad(buf_page_in_file(bpage));
|
|
ut_ad(bpage->in_LRU_list);
|
|
|
|
return(buf_page_get_io_fix(bpage) == BUF_IO_NONE
|
|
&& bpage->buf_fix_count == 0);
|
|
}
|
|
|
|
/*************************************************************************
|
|
Determine if a block has been flagged old. */
|
|
UNIV_INLINE
|
|
ibool
|
|
buf_page_is_old(
|
|
/*============*/
|
|
/* out: TRUE if old */
|
|
const buf_page_t* bpage) /* in: control block */
|
|
{
|
|
ut_ad(buf_page_in_file(bpage));
|
|
|
|
return(bpage->old);
|
|
}
|
|
|
|
/*************************************************************************
|
|
Flag a block old. */
|
|
UNIV_INLINE
|
|
void
|
|
buf_page_set_old(
|
|
/*=============*/
|
|
buf_page_t* bpage, /* in/out: control block */
|
|
ibool old) /* in: old */
|
|
{
|
|
ut_a(buf_page_in_file(bpage));
|
|
ut_ad(mutex_own(&buf_pool->mutex));
|
|
|
|
bpage->old = old;
|
|
}
|
|
|
|
/*************************************************************************
|
|
Determine if a block has been accessed in the buffer pool. */
|
|
UNIV_INLINE
|
|
ibool
|
|
buf_page_is_accessed(
|
|
/*=================*/
|
|
/* out: TRUE if accessed */
|
|
const buf_page_t* bpage) /* in: control block */
|
|
{
|
|
ut_ad(buf_page_in_file(bpage));
|
|
|
|
return(bpage->accessed);
|
|
}
|
|
|
|
/*************************************************************************
|
|
Flag a block accessed. */
|
|
UNIV_INLINE
|
|
void
|
|
buf_page_set_accessed(
|
|
/*==================*/
|
|
buf_page_t* bpage, /* in/out: control block */
|
|
ibool accessed) /* in: accessed */
|
|
{
|
|
ut_a(buf_page_in_file(bpage));
|
|
ut_ad(mutex_own(buf_page_get_mutex(bpage)));
|
|
|
|
bpage->accessed = accessed;
|
|
}
|
|
|
|
/*************************************************************************
|
|
Gets the buf_block_t handle of a buffered file block if an uncompressed
|
|
page frame exists, or NULL. */
|
|
UNIV_INLINE
|
|
buf_block_t*
|
|
buf_page_get_block(
|
|
/*===============*/
|
|
/* out: control block, or NULL */
|
|
buf_page_t* bpage) /* in: control block, or NULL */
|
|
{
|
|
if (UNIV_LIKELY(bpage != NULL)) {
|
|
ut_ad(buf_page_in_file(bpage));
|
|
|
|
if (buf_page_get_state(bpage) == BUF_BLOCK_FILE_PAGE) {
|
|
return((buf_block_t*) bpage);
|
|
}
|
|
}
|
|
|
|
return(NULL);
|
|
}
|
|
|
|
#ifdef UNIV_DEBUG
|
|
/*************************************************************************
|
|
Gets a pointer to the memory frame of a block. */
|
|
UNIV_INLINE
|
|
buf_frame_t*
|
|
buf_block_get_frame(
|
|
/*================*/
|
|
/* out: pointer to the frame */
|
|
const buf_block_t* block) /* in: pointer to the control block */
|
|
{
|
|
ut_ad(block);
|
|
|
|
switch (buf_block_get_state(block)) {
|
|
case BUF_BLOCK_ZIP_FREE:
|
|
case BUF_BLOCK_ZIP_PAGE:
|
|
case BUF_BLOCK_ZIP_DIRTY:
|
|
case BUF_BLOCK_NOT_USED:
|
|
ut_error;
|
|
break;
|
|
case BUF_BLOCK_FILE_PAGE:
|
|
ut_a(block->page.buf_fix_count > 0);
|
|
/* fall through */
|
|
case BUF_BLOCK_READY_FOR_USE:
|
|
case BUF_BLOCK_MEMORY:
|
|
case BUF_BLOCK_REMOVE_HASH:
|
|
goto ok;
|
|
}
|
|
ut_error;
|
|
ok:
|
|
return((buf_frame_t*) block->frame);
|
|
}
|
|
#endif /* UNIV_DEBUG */
|
|
|
|
/*************************************************************************
|
|
Gets the space id of a block. */
|
|
UNIV_INLINE
|
|
ulint
|
|
buf_page_get_space(
|
|
/*===============*/
|
|
/* out: space id */
|
|
const buf_page_t* bpage) /* in: pointer to the control block */
|
|
{
|
|
ut_ad(bpage);
|
|
ut_a(buf_page_in_file(bpage));
|
|
|
|
return(bpage->space);
|
|
}
|
|
|
|
/*************************************************************************
|
|
Gets the space id of a block. */
|
|
UNIV_INLINE
|
|
ulint
|
|
buf_block_get_space(
|
|
/*================*/
|
|
/* out: space id */
|
|
const buf_block_t* block) /* in: pointer to the control block */
|
|
{
|
|
ut_ad(block);
|
|
ut_a(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE);
|
|
|
|
return(block->page.space);
|
|
}
|
|
|
|
/*************************************************************************
|
|
Gets the page number of a block. */
|
|
UNIV_INLINE
|
|
ulint
|
|
buf_page_get_page_no(
|
|
/*=================*/
|
|
/* out: page number */
|
|
const buf_page_t* bpage) /* in: pointer to the control block */
|
|
{
|
|
ut_ad(bpage);
|
|
ut_a(buf_page_in_file(bpage));
|
|
|
|
return(bpage->offset);
|
|
}
|
|
|
|
/*************************************************************************
|
|
Gets the page number of a block. */
|
|
UNIV_INLINE
|
|
ulint
|
|
buf_block_get_page_no(
|
|
/*==================*/
|
|
/* out: page number */
|
|
const buf_block_t* block) /* in: pointer to the control block */
|
|
{
|
|
ut_ad(block);
|
|
ut_a(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE);
|
|
|
|
return(block->page.offset);
|
|
}
|
|
|
|
/*************************************************************************
|
|
Gets the compressed page size of a block. */
|
|
UNIV_INLINE
|
|
ulint
|
|
buf_page_get_zip_size(
|
|
/*==================*/
|
|
/* out: compressed page size, or 0 */
|
|
const buf_page_t* bpage) /* in: pointer to the control block */
|
|
{
|
|
return(bpage->zip.ssize ? 512 << bpage->zip.ssize : 0);
|
|
}
|
|
|
|
/*************************************************************************
|
|
Gets the compressed page size of a block. */
|
|
UNIV_INLINE
|
|
ulint
|
|
buf_block_get_zip_size(
|
|
/*===================*/
|
|
/* out: compressed page size, or 0 */
|
|
const buf_block_t* block) /* in: pointer to the control block */
|
|
{
|
|
return(block->page.zip.ssize ? 512 << block->page.zip.ssize : 0);
|
|
}
|
|
|
|
#if defined UNIV_DEBUG || defined UNIV_ZIP_DEBUG
|
|
/***********************************************************************
|
|
Gets the block to whose frame the pointer is pointing to. */
|
|
UNIV_INLINE
|
|
const buf_block_t*
|
|
buf_block_align(
|
|
/*============*/
|
|
/* out: pointer to block */
|
|
const byte* ptr) /* in: pointer to a frame */
|
|
{
|
|
const buf_block_t* block;
|
|
ulint space_id, page_no;
|
|
|
|
ptr = ut_align_down(ptr, UNIV_PAGE_SIZE);
|
|
page_no = mach_read_from_4(ptr + FIL_PAGE_OFFSET);
|
|
space_id = mach_read_from_4(ptr + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
|
|
|
|
block = (const buf_block_t*) buf_page_hash_get(space_id, page_no);
|
|
ut_ad(block);
|
|
ut_ad(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE);
|
|
ut_ad(block->frame == ptr);
|
|
return(block);
|
|
}
|
|
|
|
/*************************************************************************
|
|
Gets the compressed page descriptor corresponding to an uncompressed page
|
|
if applicable. */
|
|
UNIV_INLINE
|
|
const page_zip_des_t*
|
|
buf_frame_get_page_zip(
|
|
/*===================*/
|
|
/* out: compressed page descriptor, or NULL */
|
|
const byte* ptr) /* in: pointer to the page */
|
|
{
|
|
page_zip_des_t* page_zip;
|
|
mutex_enter(&buf_pool->mutex);
|
|
page_zip = buf_block_get_page_zip(buf_block_align(ptr));
|
|
mutex_exit(&buf_pool->mutex);
|
|
return(page_zip);
|
|
}
|
|
#endif /* UNIV_DEBUG || UNIV_ZIP_DEBUG */
|
|
|
|
/**************************************************************************
|
|
Gets the space id, page offset, and byte offset within page of a
|
|
pointer pointing to a buffer frame containing a file page. */
|
|
UNIV_INLINE
|
|
void
|
|
buf_ptr_get_fsp_addr(
|
|
/*=================*/
|
|
const void* ptr, /* in: pointer to a buffer frame */
|
|
ulint* space, /* out: space id */
|
|
fil_addr_t* addr) /* out: page offset and byte offset */
|
|
{
|
|
const page_t* page = (const page_t*) ut_align_down(ptr,
|
|
UNIV_PAGE_SIZE);
|
|
|
|
*space = mach_read_from_4(page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
|
|
addr->page = mach_read_from_4(page + FIL_PAGE_OFFSET);
|
|
addr->boffset = ut_align_offset(ptr, UNIV_PAGE_SIZE);
|
|
}
|
|
|
|
/**************************************************************************
|
|
Gets the hash value of the page the pointer is pointing to. This can be used
|
|
in searches in the lock hash table. */
|
|
UNIV_INLINE
|
|
ulint
|
|
buf_block_get_lock_hash_val(
|
|
/*========================*/
|
|
/* out: lock hash value */
|
|
const buf_block_t* block) /* in: block */
|
|
{
|
|
return(block->lock_hash_val);
|
|
}
|
|
|
|
/************************************************************************
|
|
Allocates a buffer block. */
|
|
UNIV_INLINE
|
|
buf_block_t*
|
|
buf_block_alloc(
|
|
/*============*/
|
|
/* out, own: the allocated block,
|
|
in state BUF_BLOCK_MEMORY */
|
|
ulint zip_size) /* in: compressed page size in bytes,
|
|
or 0 if uncompressed tablespace */
|
|
{
|
|
buf_block_t* block;
|
|
|
|
block = buf_LRU_get_free_block(zip_size);
|
|
|
|
buf_block_set_state(block, BUF_BLOCK_MEMORY);
|
|
|
|
return(block);
|
|
}
|
|
|
|
/************************************************************************
|
|
Frees a buffer block which does not contain a file page. */
|
|
UNIV_INLINE
|
|
void
|
|
buf_block_free(
|
|
/*===========*/
|
|
buf_block_t* block) /* in, own: block to be freed */
|
|
{
|
|
mutex_enter(&(buf_pool->mutex));
|
|
|
|
mutex_enter(&block->mutex);
|
|
|
|
ut_a(buf_block_get_state(block) != BUF_BLOCK_FILE_PAGE);
|
|
|
|
buf_LRU_block_free_non_file_page(block);
|
|
|
|
mutex_exit(&block->mutex);
|
|
|
|
mutex_exit(&(buf_pool->mutex));
|
|
}
|
|
|
|
/*************************************************************************
|
|
Copies contents of a buffer frame to a given buffer. */
|
|
UNIV_INLINE
|
|
byte*
|
|
buf_frame_copy(
|
|
/*===========*/
|
|
/* out: buf */
|
|
byte* buf, /* in: buffer to copy to */
|
|
const buf_frame_t* frame) /* in: buffer frame */
|
|
{
|
|
ut_ad(buf && frame);
|
|
|
|
ut_memcpy(buf, frame, UNIV_PAGE_SIZE);
|
|
|
|
return(buf);
|
|
}
|
|
|
|
/************************************************************************
|
|
Calculates a folded value of a file page address to use in the page hash
|
|
table. */
|
|
UNIV_INLINE
|
|
ulint
|
|
buf_page_address_fold(
|
|
/*==================*/
|
|
/* out: the folded value */
|
|
ulint space, /* in: space id */
|
|
ulint offset) /* in: offset of the page within space */
|
|
{
|
|
return((space << 20) + space + offset);
|
|
}
|
|
|
|
/************************************************************************
|
|
This function is used to get info if there is an io operation
|
|
going on on a buffer page. */
|
|
UNIV_INLINE
|
|
ibool
|
|
buf_page_io_query(
|
|
/*==============*/
|
|
/* out: TRUE if io going on */
|
|
buf_page_t* bpage) /* in: buf_pool block, must be bufferfixed */
|
|
{
|
|
ibool io_fixed;
|
|
|
|
mutex_enter(&(buf_pool->mutex));
|
|
|
|
ut_ad(buf_page_in_file(bpage));
|
|
ut_ad(bpage->buf_fix_count > 0);
|
|
|
|
io_fixed = buf_page_get_io_fix(bpage) != BUF_IO_NONE;
|
|
mutex_exit(&(buf_pool->mutex));
|
|
|
|
return(io_fixed);
|
|
}
|
|
|
|
/************************************************************************
|
|
Gets the youngest modification log sequence number for a frame.
|
|
Returns zero if not file page or no modification occurred yet. */
|
|
UNIV_INLINE
|
|
ib_uint64_t
|
|
buf_page_get_newest_modification(
|
|
/*=============================*/
|
|
/* out: newest modification to page */
|
|
const buf_page_t* bpage) /* in: block containing the
|
|
page frame */
|
|
{
|
|
ib_uint64_t lsn;
|
|
|
|
mutex_enter(&(buf_pool->mutex));
|
|
|
|
if (buf_page_in_file(bpage)) {
|
|
lsn = bpage->newest_modification;
|
|
} else {
|
|
lsn = 0;
|
|
}
|
|
|
|
mutex_exit(&(buf_pool->mutex));
|
|
|
|
return(lsn);
|
|
}
|
|
|
|
/************************************************************************
|
|
Increments the modify clock of a frame by 1. The caller must (1) own the
|
|
buf_pool mutex and block bufferfix count has to be zero, (2) or own an x-lock
|
|
on the block. */
|
|
UNIV_INLINE
|
|
void
|
|
buf_block_modify_clock_inc(
|
|
/*=======================*/
|
|
buf_block_t* block) /* in: block */
|
|
{
|
|
#ifdef UNIV_SYNC_DEBUG
|
|
ut_ad((mutex_own(&(buf_pool->mutex))
|
|
&& (block->page.buf_fix_count == 0))
|
|
|| rw_lock_own(&(block->lock), RW_LOCK_EXCLUSIVE));
|
|
#endif /* UNIV_SYNC_DEBUG */
|
|
|
|
block->modify_clock++;
|
|
}
|
|
|
|
/************************************************************************
|
|
Returns the value of the modify clock. The caller must have an s-lock
|
|
or x-lock on the block. */
|
|
UNIV_INLINE
|
|
ib_uint64_t
|
|
buf_block_get_modify_clock(
|
|
/*=======================*/
|
|
/* out: value */
|
|
buf_block_t* block) /* in: block */
|
|
{
|
|
#ifdef UNIV_SYNC_DEBUG
|
|
ut_ad(rw_lock_own(&(block->lock), RW_LOCK_SHARED)
|
|
|| rw_lock_own(&(block->lock), RW_LOCK_EXCLUSIVE));
|
|
#endif /* UNIV_SYNC_DEBUG */
|
|
|
|
return(block->modify_clock);
|
|
}
|
|
|
|
/***********************************************************************
|
|
Increments the bufferfix count. */
|
|
UNIV_INLINE
|
|
void
|
|
buf_block_buf_fix_inc_func(
|
|
/*=======================*/
|
|
#ifdef UNIV_SYNC_DEBUG
|
|
const char* file, /* in: file name */
|
|
ulint line, /* in: line */
|
|
#endif /* UNIV_SYNC_DEBUG */
|
|
buf_block_t* block) /* in: block to bufferfix */
|
|
{
|
|
#ifdef UNIV_SYNC_DEBUG
|
|
ibool ret;
|
|
|
|
ret = rw_lock_s_lock_func_nowait(&(block->debug_latch), file, line);
|
|
ut_a(ret);
|
|
#endif /* UNIV_SYNC_DEBUG */
|
|
ut_ad(mutex_own(&block->mutex));
|
|
|
|
block->page.buf_fix_count++;
|
|
}
|
|
#ifdef UNIV_SYNC_DEBUG
|
|
# define buf_block_buf_fix_inc(b,f,l) buf_block_buf_fix_inc_func(f,l,b)
|
|
#else /* UNIV_SYNC_DEBUG */
|
|
# define buf_block_buf_fix_inc(b,f,l) buf_block_buf_fix_inc_func(b)
|
|
#endif /* UNIV_SYNC_DEBUG */
|
|
|
|
/***********************************************************************
|
|
Decrements the bufferfix count. */
|
|
UNIV_INLINE
|
|
void
|
|
buf_block_buf_fix_dec(
|
|
/*==================*/
|
|
buf_block_t* block) /* in: block to bufferunfix */
|
|
{
|
|
ut_ad(mutex_own(&block->mutex));
|
|
|
|
block->page.buf_fix_count--;
|
|
#ifdef UNIV_SYNC_DEBUG
|
|
rw_lock_s_unlock(&block->debug_latch);
|
|
#endif
|
|
}
|
|
|
|
/**********************************************************************
|
|
Returns the control block of a file page, NULL if not found. */
|
|
UNIV_INLINE
|
|
buf_page_t*
|
|
buf_page_hash_get(
|
|
/*==============*/
|
|
/* out: block, NULL if not found */
|
|
ulint space, /* in: space id */
|
|
ulint offset) /* in: offset of the page within space */
|
|
{
|
|
buf_page_t* bpage;
|
|
ulint fold;
|
|
|
|
ut_ad(buf_pool);
|
|
ut_ad(mutex_own(&(buf_pool->mutex)));
|
|
|
|
/* Look for the page in the hash table */
|
|
|
|
fold = buf_page_address_fold(space, offset);
|
|
|
|
HASH_SEARCH(hash, buf_pool->page_hash, fold, buf_page_t*, bpage,
|
|
bpage->space == space && bpage->offset == offset);
|
|
ut_a(!bpage || buf_page_in_file(bpage));
|
|
ut_ad(!bpage || bpage->in_page_hash);
|
|
ut_ad(!bpage || !bpage->in_zip_hash);
|
|
|
|
return(bpage);
|
|
}
|
|
|
|
/**********************************************************************
|
|
Returns the control block of a file page, NULL if not found
|
|
or an uncompressed page frame does not exist. */
|
|
UNIV_INLINE
|
|
buf_block_t*
|
|
buf_block_hash_get(
|
|
/*===============*/
|
|
/* out: block, NULL if not found */
|
|
ulint space, /* in: space id */
|
|
ulint offset) /* in: offset of the page within space */
|
|
{
|
|
return(buf_page_get_block(buf_page_hash_get(space, offset)));
|
|
}
|
|
|
|
/************************************************************************
|
|
Returns TRUE if the page can be found in the buffer pool hash table. NOTE
|
|
that it is possible that the page is not yet read from disk, though. */
|
|
UNIV_INLINE
|
|
ibool
|
|
buf_page_peek(
|
|
/*==========*/
|
|
/* out: TRUE if found from page hash table,
|
|
NOTE that the page is not necessarily yet read
|
|
from disk! */
|
|
ulint space, /* in: space id */
|
|
ulint offset) /* in: page number */
|
|
{
|
|
const buf_page_t* bpage;
|
|
|
|
mutex_enter(&buf_pool->mutex);
|
|
|
|
bpage = buf_page_hash_get(space, offset);
|
|
|
|
mutex_exit(&buf_pool->mutex);
|
|
|
|
return(bpage != NULL);
|
|
}
|
|
|
|
/************************************************************************
|
|
Tries to get the page, but if file io is required, releases all latches
|
|
in mtr down to the given savepoint. If io is required, this function
|
|
retrieves the page to buffer buf_pool, but does not bufferfix it or latch
|
|
it. */
|
|
UNIV_INLINE
|
|
buf_block_t*
|
|
buf_page_get_release_on_io(
|
|
/*=======================*/
|
|
/* out: pointer to the block, or NULL
|
|
if not in buffer buf_pool */
|
|
ulint space, /* in: space id */
|
|
ulint zip_size, /* in: compressed page size in bytes
|
|
or 0 for uncompressed pages */
|
|
ulint offset, /* in: offset of the page within space
|
|
in units of a page */
|
|
buf_block_t* guess, /* in: guessed block or NULL */
|
|
ulint rw_latch, /* in: RW_X_LATCH, RW_S_LATCH,
|
|
or RW_NO_LATCH */
|
|
ulint savepoint, /* in: mtr savepoint */
|
|
mtr_t* mtr) /* in: mtr */
|
|
{
|
|
buf_block_t* block;
|
|
|
|
block = buf_page_get_gen(space, zip_size, offset, rw_latch, guess,
|
|
BUF_GET_IF_IN_POOL,
|
|
__FILE__, __LINE__,
|
|
mtr);
|
|
if (block != NULL) {
|
|
|
|
return(block);
|
|
}
|
|
|
|
/* The page was not in the buffer buf_pool: release the latches
|
|
down to the savepoint */
|
|
|
|
mtr_rollback_to_savepoint(mtr, savepoint);
|
|
|
|
buf_page_get(space, zip_size, offset, RW_S_LATCH, mtr);
|
|
|
|
/* When we get here, the page is in buffer, but we release
|
|
the latches again down to the savepoint, before returning */
|
|
|
|
mtr_rollback_to_savepoint(mtr, savepoint);
|
|
|
|
return(NULL);
|
|
}
|
|
|
|
/************************************************************************
|
|
Releases a compressed-only page acquired with buf_page_get_zip(). */
|
|
UNIV_INLINE
|
|
void
|
|
buf_page_release_zip(
|
|
/*=================*/
|
|
buf_page_t* bpage) /* in: buffer block */
|
|
{
|
|
buf_block_t* block;
|
|
|
|
ut_ad(bpage);
|
|
ut_a(bpage->buf_fix_count > 0);
|
|
|
|
switch (buf_page_get_state(bpage)) {
|
|
case BUF_BLOCK_ZIP_PAGE:
|
|
case BUF_BLOCK_ZIP_DIRTY:
|
|
mutex_enter(&buf_pool->zip_mutex);
|
|
bpage->buf_fix_count--;
|
|
mutex_exit(&buf_pool->zip_mutex);
|
|
return;
|
|
case BUF_BLOCK_FILE_PAGE:
|
|
block = (buf_block_t*) bpage;
|
|
mutex_enter(&block->mutex);
|
|
#ifdef UNIV_SYNC_DEBUG
|
|
rw_lock_s_unlock(&block->debug_latch);
|
|
#endif
|
|
bpage->buf_fix_count--;
|
|
mutex_exit(&block->mutex);
|
|
return;
|
|
case BUF_BLOCK_ZIP_FREE:
|
|
case BUF_BLOCK_NOT_USED:
|
|
case BUF_BLOCK_READY_FOR_USE:
|
|
case BUF_BLOCK_MEMORY:
|
|
case BUF_BLOCK_REMOVE_HASH:
|
|
break;
|
|
}
|
|
|
|
ut_error;
|
|
}
|
|
|
|
/************************************************************************
|
|
Decrements the bufferfix count of a buffer control block and releases
|
|
a latch, if specified. */
|
|
UNIV_INLINE
|
|
void
|
|
buf_page_release(
|
|
/*=============*/
|
|
buf_block_t* block, /* in: buffer block */
|
|
ulint rw_latch, /* in: RW_S_LATCH, RW_X_LATCH,
|
|
RW_NO_LATCH */
|
|
mtr_t* mtr) /* in: mtr */
|
|
{
|
|
ut_ad(block);
|
|
|
|
ut_a(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE);
|
|
ut_a(block->page.buf_fix_count > 0);
|
|
|
|
if (rw_latch == RW_X_LATCH && mtr->modifications) {
|
|
mutex_enter(&buf_pool->mutex);
|
|
buf_flush_note_modification(block, mtr);
|
|
mutex_exit(&buf_pool->mutex);
|
|
}
|
|
|
|
mutex_enter(&block->mutex);
|
|
|
|
#ifdef UNIV_SYNC_DEBUG
|
|
rw_lock_s_unlock(&(block->debug_latch));
|
|
#endif
|
|
block->page.buf_fix_count--;
|
|
|
|
mutex_exit(&block->mutex);
|
|
|
|
if (rw_latch == RW_S_LATCH) {
|
|
rw_lock_s_unlock(&(block->lock));
|
|
} else if (rw_latch == RW_X_LATCH) {
|
|
rw_lock_x_unlock(&(block->lock));
|
|
}
|
|
}
|
|
|
|
#ifdef UNIV_SYNC_DEBUG
|
|
/*************************************************************************
|
|
Adds latch level info for the rw-lock protecting the buffer frame. This
|
|
should be called in the debug version after a successful latching of a
|
|
page if we know the latching order level of the acquired latch. */
|
|
UNIV_INLINE
|
|
void
|
|
buf_block_dbg_add_level(
|
|
/*====================*/
|
|
buf_block_t* block, /* in: buffer page
|
|
where we have acquired latch */
|
|
ulint level) /* in: latching order level */
|
|
{
|
|
sync_thread_add_level(&block->lock, level);
|
|
}
|
|
#endif /* UNIV_SYNC_DEBUG */
|