summaryrefslogtreecommitdiff
path: root/storage/innobase/include/buf0buf.h
diff options
context:
space:
mode:
Diffstat (limited to 'storage/innobase/include/buf0buf.h')
-rw-r--r--storage/innobase/include/buf0buf.h1130
1 files changed, 577 insertions, 553 deletions
diff --git a/storage/innobase/include/buf0buf.h b/storage/innobase/include/buf0buf.h
index 3a169cd0fe2..a1b8fc5add2 100644
--- a/storage/innobase/include/buf0buf.h
+++ b/storage/innobase/include/buf0buf.h
@@ -70,9 +70,6 @@ struct fil_addr_t;
#define BUF_EVICT_IF_IN_POOL 20 /*!< evict a clean block if found */
/* @} */
-#define BUF_POOL_WATCH_SIZE (srv_n_purge_threads + 1)
- /*!< Maximum number of concurrent
- buffer pool watches */
#define MAX_PAGE_HASH_LOCKS 1024 /*!< The maximum number of
page_hash locks */
@@ -81,30 +78,20 @@ extern my_bool buf_disable_resize_buffer_pool_debug; /*!< if TRUE, resizing
buffer pool is not allowed. */
# endif /* UNIV_DEBUG */
-/** @brief States of a control block
-@see buf_page_t
-
-The enumeration values must be 0..7. */
-enum buf_page_state {
- BUF_BLOCK_POOL_WATCH, /*!< a sentinel for the buffer pool
- watch, element of buf_pool.watch[] */
- BUF_BLOCK_ZIP_PAGE, /*!< contains a clean
- compressed page */
- BUF_BLOCK_ZIP_DIRTY, /*!< contains a compressed
- page that is in the
- buf_pool.flush_list */
-
- BUF_BLOCK_NOT_USED, /*!< is in the free list;
- must be after the BUF_BLOCK_ZIP_
- constants for compressed-only pages
- @see buf_block_state_valid() */
- BUF_BLOCK_READY_FOR_USE, /*!< when buf_LRU_get_free_block
- returns a block, it is in this state */
- BUF_BLOCK_FILE_PAGE, /*!< contains a buffered file page */
- BUF_BLOCK_MEMORY, /*!< contains some main memory
- object */
- BUF_BLOCK_REMOVE_HASH /*!< hash index should be removed
- before putting to the free list */
+/** buf_page_t::state() values, distinguishing buf_page_t and buf_block_t */
+enum buf_page_state
+{
+ /** available in buf_pool.free or buf_pool.watch */
+ BUF_BLOCK_NOT_USED,
+ /** allocated for something else than a file page */
+ BUF_BLOCK_MEMORY,
+ /** a previously allocated file page, in transit to NOT_USED */
+ BUF_BLOCK_REMOVE_HASH,
+ /** a buf_block_t that is also in buf_pool.LRU */
+ BUF_BLOCK_FILE_PAGE,
+ /** the buf_page_t of a ROW_FORMAT=COMPRESSED page
+ whose uncompressed page frame has been evicted */
+ BUF_BLOCK_ZIP_PAGE
};
/** This structure defines information we will fetch from each buffer pool. It
@@ -218,8 +205,7 @@ buf_page_free_descriptor(
/** Allocate a buffer block.
@return own: the allocated block, in state BUF_BLOCK_MEMORY */
-buf_block_t*
-buf_block_alloc();
+inline buf_block_t *buf_block_alloc();
/********************************************************************//**
Frees a buffer block which does not contain a file page. */
UNIV_INLINE
@@ -637,16 +623,6 @@ buf_block_get_lock_hash_val(
buf_block_t* buf_pool_contains_zip(const void* data);
#endif /* UNIV_DEBUG */
-/***********************************************************************
-FIXME_FTS: Gets the frame the pointer is pointing to. */
-UNIV_INLINE
-buf_frame_t*
-buf_frame_align(
-/*============*/
- /* out: pointer to frame */
- byte* ptr); /* in: pointer to a frame */
-
-
/** Dump a page to stderr.
@param[in] read_buf database page
@param[in] zip_size compressed page size, or 0 */
@@ -705,207 +681,6 @@ buf_block_dbg_add_level(
#else /* UNIV_DEBUG */
# define buf_block_dbg_add_level(block, level) /* nothing */
#endif /* UNIV_DEBUG */
-/*********************************************************************//**
-Gets the state of a block.
-@return state */
-UNIV_INLINE
-enum buf_page_state
-buf_page_get_state(
-/*===============*/
- const buf_page_t* bpage); /*!< in: pointer to the control
- block */
-/*********************************************************************//**
-Gets the state of a block.
-@return state */
-UNIV_INLINE
-enum buf_page_state
-buf_block_get_state(
-/*================*/
- const buf_block_t* block) /*!< in: pointer to the control block */
- MY_ATTRIBUTE((warn_unused_result));
-/*********************************************************************//**
-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 */
-/*********************************************************************//**
-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 */
-/*********************************************************************//**
-Determines if a block is mapped to a tablespace.
-@return TRUE if mapped */
-UNIV_INLINE
-ibool
-buf_page_in_file(
-/*=============*/
- const buf_page_t* bpage) /*!< in: pointer to control block */
- MY_ATTRIBUTE((warn_unused_result));
-
-/*********************************************************************//**
-Determines if a block should be on unzip_LRU list.
-@return TRUE if block belongs to unzip_LRU */
-UNIV_INLINE
-ibool
-buf_page_belongs_to_unzip_LRU(
-/*==========================*/
- const buf_page_t* bpage) /*!< in: pointer to control block */
- MY_ATTRIBUTE((warn_unused_result));
-
-/*********************************************************************//**
-Gets the mutex of a block.
-@return pointer to mutex protecting bpage */
-UNIV_INLINE
-BPageMutex*
-buf_page_get_mutex(
-/*===============*/
- const buf_page_t* bpage) /*!< in: pointer to control block */
- MY_ATTRIBUTE((warn_unused_result));
-
-/*********************************************************************//**
-Get the flush type of a page.
-@return flush type */
-UNIV_INLINE
-buf_flush_t
-buf_page_get_flush_type(
-/*====================*/
- const buf_page_t* bpage) /*!< in: buffer page */
- MY_ATTRIBUTE((warn_unused_result));
-/*********************************************************************//**
-Set the flush type of a page. */
-UNIV_INLINE
-void
-buf_page_set_flush_type(
-/*====================*/
- buf_page_t* bpage, /*!< in: buffer page */
- buf_flush_t flush_type); /*!< in: flush type */
-
-/** Map a block to a file page.
-@param[in,out] block pointer to control block
-@param[in] page_id page id */
-UNIV_INLINE
-void
-buf_block_set_file_page(
- buf_block_t* block,
- const page_id_t page_id);
-
-/*********************************************************************//**
-Gets the io_fix state of a block.
-@return io_fix state */
-UNIV_INLINE
-enum buf_io_fix
-buf_page_get_io_fix(
-/*================*/
- const buf_page_t* bpage) /*!< in: pointer to the control block */
- MY_ATTRIBUTE((warn_unused_result));
-/*********************************************************************//**
-Gets the io_fix state of a block.
-@return io_fix state */
-UNIV_INLINE
-enum buf_io_fix
-buf_block_get_io_fix(
-/*================*/
- const buf_block_t* block) /*!< in: pointer to the control block */
- MY_ATTRIBUTE((warn_unused_result));
-/*********************************************************************//**
-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 */
-/*********************************************************************//**
-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 */
-/*********************************************************************//**
-Makes a block sticky. A sticky block implies that even after we release
-the buf_pool.mutex and the block->mutex:
-* it cannot be removed from the flush_list
-* the block descriptor cannot be relocated
-* it cannot be removed from the LRU list
-Note that:
-* the block can still change its position in the LRU list
-* the next and previous pointers can change. */
-UNIV_INLINE
-void
-buf_page_set_sticky(
-/*================*/
- buf_page_t* bpage); /*!< in/out: control block */
-/*********************************************************************//**
-Removes stickiness of a block. */
-UNIV_INLINE
-void
-buf_page_unset_sticky(
-/*==================*/
- buf_page_t* bpage); /*!< in/out: control block */
-/********************************************************************//**
-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 */
- MY_ATTRIBUTE((warn_unused_result));
-
-/*********************************************************************//**
-Determine if a block has been flagged old.
-@return TRUE if old */
-UNIV_INLINE
-ibool
-buf_page_is_old(
-/*============*/
- const buf_page_t* bpage) /*!< in: control block */
- MY_ATTRIBUTE((warn_unused_result));
-/*********************************************************************//**
-Flag a block old. */
-UNIV_INLINE
-void
-buf_page_set_old(
-/*=============*/
- buf_page_t* bpage, /*!< in/out: control block */
- bool old); /*!< in: old */
-/*********************************************************************//**
-Determine the time of first access of a block in the buffer pool.
-@return ut_time_ms() at the time of first access, 0 if not accessed */
-UNIV_INLINE
-unsigned
-buf_page_is_accessed(
-/*=================*/
- const buf_page_t* bpage) /*!< in: control block */
- MY_ATTRIBUTE((warn_unused_result));
-/*********************************************************************//**
-Flag a block accessed. */
-UNIV_INLINE
-void
-buf_page_set_accessed(
-/*==================*/
- buf_page_t* bpage) /*!< in/out: control block */
- MY_ATTRIBUTE((nonnull));
-/*********************************************************************//**
-Gets the buf_block_t handle of a buffered file block if an uncompressed
-page frame exists, or NULL. Note: even though bpage is not declared a
-const we don't update its value.
-@return control block, or NULL */
-UNIV_INLINE
-buf_block_t*
-buf_page_get_block(
-/*===============*/
- buf_page_t* bpage) /*!< in: control block, or NULL */
- MY_ATTRIBUTE((warn_unused_result));
#ifdef UNIV_DEBUG
/*********************************************************************//**
@@ -929,52 +704,21 @@ if applicable. */
#define is_buf_block_get_page_zip(block) \
UNIV_LIKELY_NULL((block)->page.zip.data)
-/** Initialize a page for read to the buffer buf_pool. If the page is
-(1) already in buf_pool, or
-(2) if we specify to read only ibuf pages and the page is not an ibuf page, or
-(3) if the space is deleted or being deleted,
-then this function does nothing.
-Sets the io_fix flag to BUF_IO_READ and sets a non-recursive exclusive lock
-on the buffer frame. The io-handler must take care that the flag is cleared
-and the lock released later.
-@param[out] err DB_SUCCESS or DB_TABLESPACE_DELETED
-@param[in] mode BUF_READ_IBUF_PAGES_ONLY, ...
-@param[in] page_id page id
-@param[in] zip_size ROW_FORMAT=COMPRESSED page size, or 0
-@param[in] unzip whether the uncompressed page is
- requested (for ROW_FORMAT=COMPRESSED)
-@return pointer to the block
-@retval NULL in case of an error */
-buf_page_t*
-buf_page_init_for_read(
- dberr_t* err,
- ulint mode,
- const page_id_t page_id,
- ulint zip_size,
- bool unzip);
+/** Monitor the buffer page read/write activity, and increment corresponding
+counter value in MONITOR_MODULE_BUF_PAGE.
+@param bpage buffer page whose read or write was completed
+@param io_type BUF_IO_READ or BUF_IO_WRITE */
+ATTRIBUTE_COLD __attribute__((nonnull))
+void buf_page_monitor(const buf_page_t *bpage, buf_io_fix io_type);
-/** Complete a read or write request of a file page to or from the buffer pool.
-@param[in,out] bpage page to complete
-@param[in] dblwr whether the doublewrite buffer was used (on write)
-@param[in] evict whether or not to evict the page from LRU list
+/** Complete a read request of a file page to buf_pool.
+@param bpage recently read page
+@param node data file
@return whether the operation succeeded
-@retval DB_SUCCESS always when writing, or if a read page was OK
-@retval DB_PAGE_CORRUPTED if the checksum fails on a page read
-@retval DB_DECRYPTION_FAILED if page post encryption checksum matches but
- after decryption normal page checksum does
- not match */
-UNIV_INTERN
-dberr_t
-buf_page_io_complete(
- buf_page_t* bpage,
- bool dblwr = false,
- bool evict = false)
- MY_ATTRIBUTE((nonnull));
-
-/** Returns the control block of a file page, NULL if not found.
-@param[in] page_id page id
-@return block, NULL if not found */
-inline buf_page_t *buf_page_hash_get_low(const page_id_t page_id);
+@retval DB_SUCCESS always when writing, or if a read page was OK
+@retval DB_PAGE_CORRUPTED if the checksum fails on a page read
+@retval DB_DECRYPTION_FAILED if the page cannot be decrypted */
+dberr_t buf_page_read_complete(buf_page_t *bpage, const fil_node_t &node);
/** Returns the control block of a file page, NULL if not found.
If the block is found and lock is not NULL then the appropriate
@@ -1022,7 +766,7 @@ buf_block_hash_get_locked(
/* There are four different ways we can try to get a bpage or block
from the page hash:
1) Caller already holds the appropriate page hash lock: in the case call
-buf_page_hash_get_low() function.
+buf_pool_t::page_hash_get_low().
2) Caller wants to hold page hash lock in x-mode
3) Caller wants to hold page hash lock in s-mode
4) Caller doesn't want to hold page hash lock */
@@ -1031,35 +775,16 @@ buf_page_hash_get_low() function.
#define buf_page_hash_get_x_locked(page_id, l) \
buf_page_hash_get_locked(page_id, l, RW_LOCK_X)
#define buf_page_hash_get(page_id) \
- buf_page_hash_get_locked(page_id, NULL, 0)
+ buf_page_hash_get_locked(page_id, nullptr, RW_LOCK_S)
#define buf_page_get_also_watch(page_id) \
- buf_page_hash_get_locked(page_id, NULL, 0, true)
+ buf_page_hash_get_locked(page_id, nullptr, RW_LOCK_S, true)
#define buf_block_hash_get_s_locked(page_id, l) \
buf_block_hash_get_locked(page_id, l, RW_LOCK_S)
#define buf_block_hash_get_x_locked(page_id, l) \
buf_block_hash_get_locked(page_id, l, RW_LOCK_X)
#define buf_block_hash_get(page_id) \
- buf_block_hash_get_locked(page_id, NULL, 0)
-
-/** Determine if a block is a sentinel for a buffer pool watch.
-@param[in] bpage block
-@return whether bpage a sentinel for a buffer pool watch */
-bool buf_pool_watch_is_sentinel(const buf_page_t* bpage)
- MY_ATTRIBUTE((nonnull, warn_unused_result));
-
-/** Stop watching if the page has been read in.
-buf_pool_watch_set(space,offset) must have returned NULL before.
-@param[in] page_id page id */
-void buf_pool_watch_unset(const page_id_t page_id);
-
-/** Check if the page has been read in.
-This may only be called after buf_pool_watch_set(space,offset)
-has returned NULL and before invoking buf_pool_watch_unset(space,offset).
-@param[in] page_id page id
-@return FALSE if the given page was not read in, TRUE if it was */
-bool buf_pool_watch_occurred(const page_id_t page_id)
-MY_ATTRIBUTE((warn_unused_result));
+ buf_block_hash_get_locked(page_id, nullptr, RW_LOCK_S)
/** Calculate aligned buffer pool size based on srv_buf_pool_chunk_unit,
if needed.
@@ -1123,40 +848,37 @@ public:
/** The common buffer control block structure
for compressed and uncompressed frames */
-/** Number of bits used for buffer page states. */
-#define BUF_PAGE_STATE_BITS 3
-
-class buf_page_t {
-public:
- /** @name General fields
- None of these bit-fields must be modified without holding
- buf_page_get_mutex() [buf_block_t::mutex or
- buf_pool.zip_mutex], since they can be stored in the same
- machine word. Some of these fields are additionally protected
- by buf_pool.mutex. */
- /* @{ */
-
- /** Page id. Protected by buf_pool mutex. */
- page_id_t id;
- buf_page_t* hash; /*!< node used in chaining to
- buf_pool.page_hash or
- buf_pool.zip_hash */
-
- /** Count of how manyfold this block is currently bufferfixed. */
- Atomic_counter<uint32_t> buf_fix_count;
-
- /** type of pending I/O operation; also protected by
- buf_pool.mutex for writes only */
- buf_io_fix io_fix;
+class buf_pool_t;
- /** Block state. @see buf_page_in_file */
- buf_page_state state;
+class buf_page_t
+{
+ friend buf_pool_t;
+ friend buf_block_t;
+ /** @name General fields */
+ /* @{ */
+
+public: // FIXME: fix fil_iterate()
+ /** Page id. Protected by buf_pool.hash_lock_get(id) when
+ the page is in buf_pool.page_hash. */
+ page_id_t id_;
+private:
+ /** Count of how manyfold this block is currently bufferfixed. */
+ Atomic_counter<uint32_t> buf_fix_count_;
+
+ /** type of pending I/O operation; protected by buf_pool.mutex
+ if in_LRU_list */
+ Atomic_relaxed<buf_io_fix> io_fix_;
+ /** Block state. @see in_file().
+ State transitions between in_file() states and to
+ BUF_BLOCK_REMOVE_HASH are protected by buf_pool.hash_lock_get(id)
+ when the block is in buf_pool.page_hash.
+ Other transitions when in_LRU_list are protected by buf_pool.mutex. */
+ buf_page_state state_;
- unsigned flush_type:2; /*!< if this block is currently being
- flushed to disk, this tells the
- flush_type.
- @see buf_flush_t */
- /* @} */
+public:
+ /** buf_pool.page_hash link; protected by buf_pool.hash_lock_get(id) */
+ buf_page_t *hash;
+ /* @} */
page_zip_des_t zip; /*!< compressed page; zip.data
(but not the data it points to) is
also protected by buf_pool.mutex;
@@ -1164,97 +886,50 @@ public:
zip.data == NULL means an active
buf_pool.watch */
- ulint real_size; /*!< Real size of the page
- Normal pages == srv_page_size
- page compressed pages, payload
- size alligned to sector boundary.
- */
-
buf_tmp_buffer_t* slot; /*!< Slot for temporary memory
used for encryption/compression
or NULL */
#ifdef UNIV_DEBUG
- /** whether the page is in buf_pool.page_hash;
- protected by buf_pool.mutex(!) and the hash bucket rw-latch */
- ibool in_page_hash;
- ibool in_zip_hash; /*!< TRUE if in buf_pool.zip_hash */
+ /** whether this->list is in buf_pool.zip_hash; protected by buf_pool.mutex */
+ bool in_zip_hash;
+ /** whether this->LRU is in buf_pool.LRU (in_file() holds);
+ protected by buf_pool.mutex */
+ bool in_LRU_list;
+ /** whether this is in buf_pool.page_hash (in_file() holds);
+ protected by buf_pool.mutex */
+ bool in_page_hash;
+ /** whether this->list is in buf_pool.free (state() == BUF_BLOCK_NOT_USED);
+ protected by buf_pool.flush_list_mutex */
+ bool in_free_list;
#endif /* UNIV_DEBUG */
+ /** list member in one of the lists of buf_pool; protected by
+ buf_pool.mutex or buf_pool.flush_list_mutex
- /** @name Page flushing fields
- All these are protected by buf_pool.mutex. */
- /* @{ */
+ state() == BUF_BLOCK_NOT_USED: buf_pool.free or buf_pool.withdraw
- UT_LIST_NODE_T(buf_page_t) list;
- /*!< based on state, this is a
- list node, protected either by
- buf_pool.mutex or by
- buf_pool.flush_list_mutex,
- in one of the following lists in
- buf_pool:
-
- - BUF_BLOCK_NOT_USED: free, withdraw
- - BUF_BLOCK_FILE_PAGE: flush_list
- - BUF_BLOCK_ZIP_DIRTY: flush_list
- - BUF_BLOCK_ZIP_PAGE: zip_clean
-
- If bpage is part of flush_list
- then the node pointers are
- covered by buf_pool.flush_list_mutex.
- Otherwise these pointers are
- protected by buf_pool.mutex.
-
- The contents of the list node
- is undefined if !in_flush_list
- && state == BUF_BLOCK_FILE_PAGE,
- or if state is one of
- BUF_BLOCK_MEMORY,
- BUF_BLOCK_REMOVE_HASH or
- BUF_BLOCK_READY_IN_USE. */
+ state() == BUF_BLOCK_FILE_PAGE ||
+ (state() == BUF_BLOCK_ZIP_PAGE && !oldest_modification()):
+ buf_pool.flush_list (protected by buf_pool.flush_list_mutex)
-#ifdef UNIV_DEBUG
- ibool in_flush_list; /*!< TRUE if in buf_pool.flush_list;
- when buf_pool.flush_list_mutex is
- free, the following should hold:
- in_flush_list
- == (state == BUF_BLOCK_FILE_PAGE
- || state == BUF_BLOCK_ZIP_DIRTY)
- Writes to this field must be
- covered by both block->mutex
- and buf_pool.flush_list_mutex. Hence
- reads can happen while holding
- any one of the two mutexes */
- ibool in_free_list; /*!< TRUE if in buf_pool.free; when
- buf_pool.mutex is free, the following
- should hold: in_free_list
- == (state == BUF_BLOCK_NOT_USED) */
-#endif /* UNIV_DEBUG */
+ state() == BUF_BLOCK_ZIP_PAGE && !oldest_modification(): buf_pool.zip_clean
- lsn_t oldest_modification;
- /*!< log sequence number of
- the START of the log entry
- written of the oldest
- modification to this block
- which has not yet been flushed
- on disk; zero if all
- modifications are on disk.
- Writes to this field must be
- covered by both block->mutex
- and buf_pool.flush_list_mutex. Hence
- reads can happen while holding
- any one of the two mutexes */
- /* @} */
- /** @name LRU replacement algorithm fields
- These fields are protected by buf_pool.mutex only (not
- buf_pool.zip_mutex or buf_block_t::mutex). */
+ The contents is undefined if
+ !oldest_modification() && state() == BUF_BLOCK_FILE_PAGE,
+ or if state() is not any of the above. */
+ UT_LIST_NODE_T(buf_page_t) list;
+
+private:
+ /** log sequence number of the START of the log entry written of the
+ oldest modification to this block which has not yet been written
+ to the data file; 0 if no modifications are pending. */
+ Atomic_counter<lsn_t> oldest_modification_;
+public:
+ /** @name LRU replacement algorithm fields.
+ Protected by buf_pool.mutex. */
/* @{ */
UT_LIST_NODE_T(buf_page_t) LRU;
/*!< node of the LRU list */
-#ifdef UNIV_DEBUG
- ibool in_LRU_list; /*!< TRUE if the page is in
- the LRU list; used in
- debugging */
-#endif /* UNIV_DEBUG */
unsigned old:1; /*!< TRUE if the block is in the old
blocks in buf_pool.LRU_old */
unsigned freed_page_clock:31;/*!< the value of
@@ -1266,11 +941,9 @@ public:
purposes without holding any
mutex or latch */
/* @} */
- unsigned access_time; /*!< time of first access, or
+ Atomic_counter<unsigned> access_time; /*!< time of first access, or
0 if the block was never accessed
- in the buffer pool. Protected by
- block mutex for buf_page_in_file()
- blocks.
+ in the buffer pool.
For state==BUF_BLOCK_MEMORY
blocks, this field can be repurposed
@@ -1281,10 +954,10 @@ public:
the field is protected by
recv_sys_t::mutex. */
/** Change buffer entries for the page exist.
- Protected by io_fix==BUF_IO_READ or by buf_block_t::lock. */
+ Protected by io_fix()==BUF_IO_READ or by buf_block_t::lock. */
bool ibuf_exist;
- /** Block initialization status. Can be modified while holding io_fix
+ /** Block initialization status. Can be modified while holding io_fix()
or buf_block_t::lock X-latch */
enum {
/** the page was read normally and should be flushed normally */
@@ -1299,10 +972,85 @@ public:
FREED
} status;
- void fix() { buf_fix_count++; }
+ buf_page_t() : id_(0)
+ {
+ static_assert(BUF_BLOCK_NOT_USED == 0, "compatibility");
+ memset((void*) this, 0, sizeof *this);
+ }
+
+ /** Initialize some fields */
+ void init()
+ {
+ io_fix_= BUF_IO_NONE;
+ buf_fix_count_= 0;
+ old= 0;
+ freed_page_clock= 0;
+ access_time= 0;
+ oldest_modification_= 0;
+ slot= nullptr;
+ ibuf_exist= false;
+ status= NORMAL;
+ ut_d(in_zip_hash= false);
+ ut_d(in_free_list= false);
+ ut_d(in_LRU_list= false);
+ ut_d(in_page_hash= false);
+ HASH_INVALIDATE(this, hash);
+ }
+
+ /** Initialize some more fields */
+ void init(buf_page_state state, page_id_t id, uint32_t buf_fix_count= 0)
+ {
+ init();
+ state_= state;
+ id_= id;
+ buf_fix_count_= buf_fix_count;
+ }
+
+public:
+ const page_id_t &id() const { return id_; }
+ buf_page_state state() const { return state_; }
+ uint32_t buf_fix_count() const { return buf_fix_count_; }
+ buf_io_fix io_fix() const { return io_fix_; }
+ void io_unfix()
+ {
+ ut_d(const auto old_io_fix= io_fix());
+ ut_ad(old_io_fix == BUF_IO_READ || old_io_fix == BUF_IO_PIN);
+ io_fix_= BUF_IO_NONE;
+ }
+
+ /** @return if this belongs to buf_pool.unzip_LRU */
+ bool belongs_to_unzip_LRU() const
+ {
+ ut_ad(in_file());
+ return zip.data && state() == BUF_BLOCK_FILE_PAGE;
+ }
+
+ inline void add_buf_fix_count(uint32_t count);
+ inline void set_buf_fix_count(uint32_t count);
+ inline void set_state(buf_page_state state);
+ inline void set_io_fix(buf_io_fix io_fix);
+ inline void set_corrupt_id();
+
+ /** @return the oldest modification */
+ lsn_t oldest_modification() const { return oldest_modification_; }
+ /** Set oldest_modification when adding to buf_pool.flush_list */
+ inline void set_oldest_modification(lsn_t lsn);
+ /** Clear oldest_modification when removing from buf_pool.flush_list */
+ inline void clear_oldest_modification();
+
+ /** Prepare to release a file page to buf_pool.free. */
+ void free_file_page()
+ {
+ ut_ad(state() == BUF_BLOCK_REMOVE_HASH);
+ ut_d(oldest_modification_= 0); /* for buf_LRU_free_page(this, false) */
+ set_corrupt_id();
+ ut_d(set_state(BUF_BLOCK_MEMORY));
+ }
+
+ void fix() { buf_fix_count_++; }
uint32_t unfix()
{
- uint32_t count= buf_fix_count--;
+ uint32_t count= buf_fix_count_--;
ut_ad(count != 0);
return count - 1;
}
@@ -1319,6 +1067,47 @@ public:
{
return zip.ssize ? (UNIV_ZIP_SIZE_MIN >> 1) << zip.ssize : 0;
}
+
+ /** @return whether the block is mapped to a data file */
+ bool in_file() const
+ {
+ switch (state_) {
+ case BUF_BLOCK_ZIP_PAGE:
+ case BUF_BLOCK_FILE_PAGE:
+ return true;
+ case BUF_BLOCK_NOT_USED:
+ case BUF_BLOCK_MEMORY:
+ case BUF_BLOCK_REMOVE_HASH:
+ return false;
+ }
+
+ ut_error;
+ return false;
+ }
+
+ /** @return whether the block is modified and ready for flushing */
+ inline bool ready_for_flush() const;
+ /** @return whether the state can be changed to BUF_BLOCK_NOT_USED */
+ bool ready_for_replace() const
+ { return !oldest_modification() && can_relocate(); }
+ /** @return whether the block can be relocated in memory.
+ The block can be dirty, but it must not be I/O-fixed or bufferfixed. */
+ inline bool can_relocate() const;
+ /** @return whether the block has been flagged old in buf_pool.LRU */
+ inline bool is_old() const;
+ /** Set whether a block is old in buf_pool.LRU */
+ inline void set_old(bool old);
+ /** Flag a page accessed in buf_pool
+ @return whether this is not the first access */
+ bool set_accessed()
+ {
+ if (is_accessed()) return true;
+ access_time= static_cast<uint32_t>(ut_time_ms());
+ return false;
+ }
+ /** @return ut_time_ms() at the time of first access of a block in buf_pool
+ @retval 0 if not accessed */
+ unsigned is_accessed() const { ut_ad(in_file()); return access_time; }
};
/** The buffer control block structure */
@@ -1338,21 +1127,25 @@ struct buf_block_t{
srv_page_size */
BPageLock lock; /*!< read-write lock of the buffer
frame */
+#ifdef UNIV_DEBUG
+ /** whether page.list is in buf_pool.withdraw
+ ((state() == BUF_BLOCK_NOT_USED)) and the buffer pool is being shrunk;
+ protected by buf_pool.mutex */
+ bool in_withdraw_list;
+ /** whether unzip_LRU is in buf_pool.unzip_LRU
+ (state() == BUF_BLOCK_FILE_PAGE and zip.data != nullptr);
+ protected by buf_pool.mutex */
+ bool in_unzip_LRU_list;
+#endif
UT_LIST_NODE_T(buf_block_t) unzip_LRU;
/*!< node of the decompressed LRU list;
a block is in the unzip_LRU list
- if page.state == BUF_BLOCK_FILE_PAGE
+ if page.state() == BUF_BLOCK_FILE_PAGE
and page.zip.data != NULL */
-#ifdef UNIV_DEBUG
- ibool in_unzip_LRU_list;/*!< TRUE if the page is in the
- decompressed LRU list;
- used in debugging */
- ibool in_withdraw_list;
-#endif /* UNIV_DEBUG */
uint32_t lock_hash_val; /*!< hashed value of the page address
in the record lock hash table;
protected by buf_block_t::lock
- (or buf_block_t::mutex, buf_pool.mutex
+ (or buf_pool.mutex
in buf_page_get_gen(),
buf_page_init_for_read()
and buf_page_create()) */
@@ -1476,15 +1269,16 @@ struct buf_block_t{
debug utilities in sync0rw */
/* @} */
# endif
- BPageMutex mutex; /*!< mutex protecting this block:
- state (also protected by the buffer
- pool mutex), io_fix, buf_fix_count,
- and accessed; we introduce this new
- mutex in InnoDB-5.1 to relieve
- contention on the buffer pool mutex */
-
void fix() { page.fix(); }
- uint32_t unfix() { return page.unfix(); }
+ uint32_t unfix()
+ {
+ uint32_t fix_count= page.unfix();
+ ut_ad(fix_count || page.io_fix() != BUF_IO_NONE ||
+ page.state() == BUF_BLOCK_ZIP_PAGE ||
+ !rw_lock_own_flagged(&lock, RW_LOCK_FLAG_X | RW_LOCK_FLAG_S |
+ RW_LOCK_FLAG_SX));
+ return fix_count;
+ }
/** @return the physical size, in bytes */
ulint physical_size() const { return page.physical_size(); }
@@ -1492,15 +1286,12 @@ struct buf_block_t{
/** @return the ROW_FORMAT=COMPRESSED physical size, in bytes
@retval 0 if not compressed */
ulint zip_size() const { return page.zip_size(); }
-};
-
-/** Check if a buf_block_t object is in a valid state
-@param block buffer block
-@return TRUE if valid */
-#define buf_block_state_valid(block) \
-(buf_block_get_state(block) >= BUF_BLOCK_NOT_USED \
- && (buf_block_get_state(block) <= BUF_BLOCK_REMOVE_HASH))
+ /** Initialize the block.
+ @param page_id page id
+ @param zip_size ROW_FORMAT=COMPRESSED page size, or 0 */
+ void initialise(const page_id_t page_id, ulint zip_size);
+};
/**********************************************************************//**
Compute the hash fold value for blocks in buf_pool.zip_hash. */
@@ -1523,11 +1314,11 @@ public:
buf_page_t *get() const { ut_ad(mutex_own(m_mutex)); return m_hp; }
/** Set current value
- @param bpage buffer block to be set as hp */
+ @param bpage buffer block to be set as hp */
void set(buf_page_t *bpage)
{
ut_ad(mutex_own(m_mutex));
- ut_ad(!bpage || buf_page_in_file(bpage));
+ ut_ad(!bpage || bpage->in_file());
m_hp= bpage;
}
@@ -1570,7 +1361,7 @@ public:
if (is_hp(bpage))
m_hp= UT_LIST_GET_PREV(list, m_hp);
- ut_ad(!m_hp || m_hp->in_flush_list);
+ ut_ad(!m_hp || m_hp->oldest_modification());
}
};
@@ -1828,6 +1619,10 @@ public:
return false;
}
+ /** Release and evict a corrupted page.
+ @param bpage page that was being read */
+ void corrupted_evict(buf_page_t *bpage);
+
#ifdef UNIV_DEBUG
/** Find a block that points to a ROW_FORMAT=COMPRESSED page
@param data pointer to the start of a ROW_FORMAT=COMPRESSED page frame
@@ -1858,8 +1653,6 @@ public:
inline buf_block_t* block_from_ahi(const byte *ptr) const;
#endif /* BTR_CUR_HASH_ADAPT */
- bool is_block_mutex(const BPageMutex *m) const
- { return is_block_field(reinterpret_cast<const void*>(m)); }
bool is_block_lock(const BPageLock *l) const
{ return is_block_field(reinterpret_cast<const void*>(l)); }
@@ -1878,29 +1671,216 @@ public:
is_block_field(reinterpret_cast<const void*>(block));
}
-#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
+ /** Get the page_hash latch for a page */
+ rw_lock_t *hash_lock_get(const page_id_t id) const
+ {
+ return hash_lock_get_low(id.fold());
+ }
+ /** Get a page_hash latch. */
+ rw_lock_t *hash_lock_get_low(ulint fold) const
+ {
+ return page_hash->sync_obj.rw_locks +
+ hash_get_sync_obj_index(page_hash, fold);
+ }
+#ifdef UNIV_DEBUG
+ /** Check whether a page_hash latch is being held */
+ bool page_hash_lock_own_flagged(ulint fold, rw_lock_flags_t flagged) const
+ {
+ return rw_lock_own_flagged(hash_lock_get_low(fold), flagged);
+ }
+#endif
+
+ /** Acquire a page_hash bucket latch, tolerating concurrent resize()
+ @tparam exclusive whether the latch is to be acquired exclusively
+ @param fold hash bucket key */
+ template<bool exclusive> rw_lock_t *page_hash_lock(ulint fold)
+ {
+ rw_lock_t *latch= hash_lock_get_low(fold);
+ if (exclusive)
+ rw_lock_x_lock(latch);
+ else
+ rw_lock_s_lock(latch);
+ rw_lock_t *l;
+ while ((l= hash_lock_get_low(fold)) != latch)
+ {
+ if (exclusive)
+ rw_lock_x_unlock(latch);
+ else
+ rw_lock_s_unlock(latch);
+ /* FIXME: what if we resize() completes several times while we
+ are not holding any latch here? Is the latch guaranteed to be valid? */
+ if (exclusive)
+ rw_lock_x_lock(l);
+ else
+ rw_lock_s_lock(l);
+ latch= l;
+ }
+ return latch;
+ }
+
+ /** Look up a block descriptor.
+ @param id page identifier
+ @return block descriptor, possibly in watch[]
+ @retval nullptr if not found*/
+ buf_page_t *page_hash_get_low(const page_id_t id)
+ {
+ ut_ad(mutex_own(&mutex) ||
+ rw_lock_own_flagged(hash_lock_get(id),
+ RW_LOCK_FLAG_X | RW_LOCK_FLAG_S));
+ buf_page_t* bpage;
+ /* Look for the page in the hash table */
+ HASH_SEARCH(hash, page_hash, id.fold(), buf_page_t*, bpage,
+ ut_ad(bpage->in_page_hash), id == bpage->id());
+ return bpage;
+ }
+
+ /** Acquire exclusive latches on all page_hash buckets. */
+ void page_hash_lock_all() const
+ {
+ ut_ad(page_hash->magic_n == HASH_TABLE_MAGIC_N);
+ ut_ad(page_hash->type == HASH_TABLE_SYNC_RW_LOCK);
+ for (ulint i= 0; i < page_hash->n_sync_obj; i++)
+ rw_lock_x_lock(&page_hash->sync_obj.rw_locks[i]);
+ }
+ /** Release exclusive latches on all the page_hash buckets. */
+ void page_hash_unlock_all() const
+ {
+ ut_ad(page_hash->magic_n == HASH_TABLE_MAGIC_N);
+ ut_ad(page_hash->type == HASH_TABLE_SYNC_RW_LOCK);
+
+ for (ulint i = 0; i < page_hash->n_sync_obj; i++)
+ rw_lock_x_unlock(&page_hash->sync_obj.rw_locks[i]);
+ }
+
+ /** Determine if a block is a sentinel for a buffer pool watch.
+ @param bpage page descriptor
+ @return whether bpage a sentinel for a buffer pool watch */
+ bool watch_is_sentinel(const buf_page_t &bpage)
+ {
+ ut_ad(mutex_own(&mutex) ||
+ rw_lock_own_flagged(hash_lock_get(bpage.id()),
+ RW_LOCK_FLAG_X | RW_LOCK_FLAG_S));
+ ut_ad(bpage.in_file());
+
+ if (&bpage < &watch[0] || &bpage >= &watch[UT_ARR_SIZE(watch)])
+ {
+ ut_ad(bpage.state() != BUF_BLOCK_ZIP_PAGE || bpage.zip.data);
+ return false;
+ }
+
+ ut_ad(bpage.state() == BUF_BLOCK_ZIP_PAGE);
+ ut_ad(!bpage.in_zip_hash);
+ ut_ad(!bpage.zip.data);
+ return true;
+ }
+
+ /** Check if a watched page has been read.
+ This may only be called after !watch_set() and before invoking watch_unset().
+ @param id page identifier
+ @return whether the page was read to the buffer pool */
+ bool watch_occurred(const page_id_t id)
+ {
+ rw_lock_t *hash_lock= page_hash_lock<false>(id.fold());
+ /* The page must exist because watch_set() increments buf_fix_count. */
+ buf_page_t *bpage= page_hash_get_low(id);
+ const bool is_sentinel= watch_is_sentinel(*bpage);
+ rw_lock_s_unlock(hash_lock);
+ return !is_sentinel;
+ }
+
+ /** Register a watch for a page identifier. The caller must hold an
+ exclusive page hash latch. The *hash_lock may be released,
+ relocated, and reacquired.
+ @param id page identifier
+ @param hash_lock page_hash latch that is held in RW_LOCK_X mode
+ @return a buffer pool block corresponding to id
+ @retval nullptr if the block was not present, and a watch was installed */
+ inline buf_page_t *watch_set(const page_id_t id, rw_lock_t **hash_lock);
+
+ /** Stop watching whether a page has been read in.
+ watch_set(id) must have returned nullptr before.
+ @param id page identifier */
+ void watch_unset(const page_id_t id)
+ {
+ const ulint fold= id.fold();
+ rw_lock_t *hash_lock= page_hash_lock<true>(fold);
+ /* The page must exist because watch_set() increments buf_fix_count. */
+ buf_page_t *watch= page_hash_get_low(id);
+ if (watch->unfix() == 0 && watch_is_sentinel(*watch))
+ {
+ /* The following is based on watch_remove(). */
+ ut_ad(watch->in_page_hash);
+ ut_d(watch->in_page_hash= false);
+ HASH_DELETE(buf_page_t, hash, page_hash, fold, watch);
+ rw_lock_x_unlock(hash_lock);
+ // Now that the watch is detached from page_hash, release it to watch[].
+ mutex_enter(&mutex);
+ /* It is possible that watch_remove() already removed the watch. */
+ if (watch->id_ == id)
+ {
+ ut_ad(!watch->buf_fix_count());
+ ut_ad(watch->state() == BUF_BLOCK_ZIP_PAGE);
+ watch->set_state(BUF_BLOCK_NOT_USED);
+ }
+ mutex_exit(&mutex);
+ }
+ else
+ rw_lock_x_unlock(hash_lock);
+ }
+
+ /** Remove the sentinel block for the watch before replacing it with a
+ real block. watch_unset() or watch_occurred() will notice
+ that the block has been replaced with the real block.
+ @param watch sentinel */
+ inline void watch_remove(buf_page_t *watch);
+
+ /** @return whether less than 1/4 of the buffer pool is available */
+ bool running_out() const
+ {
+ return !recv_recovery_is_on() &&
+ UNIV_UNLIKELY(UT_LIST_GET_LEN(free) + UT_LIST_GET_LEN(LRU) <
+ std::min(curr_size, old_size) / 4);
+ }
+
+#ifdef UNIV_DEBUG
/** Validate the buffer pool. */
void validate();
-#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
-#if defined UNIV_DEBUG_PRINT || defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
+#endif /* UNIV_DEBUG */
+#if defined UNIV_DEBUG_PRINT || defined UNIV_DEBUG
/** Write information of the buf_pool to the error log. */
void print();
-#endif /* UNIV_DEBUG_PRINT || UNIV_DEBUG || UNIV_BUF_DEBUG */
+#endif /* UNIV_DEBUG_PRINT || UNIV_DEBUG */
+
+ /** Remove a block from the LRU list.
+ @return the predecessor in the LRU list */
+ buf_page_t *LRU_remove(buf_page_t *bpage)
+ {
+ ut_ad(mutex_own(&mutex));
+ ut_ad(bpage->in_LRU_list);
+ ut_ad(bpage->in_page_hash);
+ ut_ad(!bpage->in_zip_hash);
+ ut_ad(bpage->in_file());
+ lru_hp.adjust(bpage);
+ lru_scan_itr.adjust(bpage);
+ single_scan_itr.adjust(bpage);
+ ut_d(bpage->in_LRU_list= false);
+ buf_page_t *prev= UT_LIST_GET_PREV(LRU, bpage);
+ UT_LIST_REMOVE(LRU, bpage);
+ return prev;
+ }
+
+ /** Number of pages to read ahead */
+ static constexpr uint32_t READ_AHEAD_PAGES= 64;
/** @name General fields */
/* @{ */
BufPoolMutex mutex; /*!< Buffer pool mutex */
- BufPoolZipMutex zip_mutex; /*!< Zip mutex, protects compressed
- only pages (of type buf_page_t, not
- buf_block_t */
ulint curr_pool_size; /*!< Current pool size in bytes */
ulint LRU_old_ratio; /*!< Reserve this much of the buffer
pool for "old" blocks */
#ifdef UNIV_DEBUG
ulint buddy_n_frames; /*!< Number of frames allocated from
the buffer pool to the buddy system */
-#endif
-#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
ulint mutex_exit_forbidden; /*!< Forbid release mutex */
#endif
ut_allocator<unsigned char> allocator; /*!< Allocator used for
@@ -1911,30 +1891,25 @@ public:
chunk_t* chunks; /*!< buffer pool chunks */
chunk_t* chunks_old; /*!< old buffer pool chunks to be freed
after resizing buffer pool */
- ulint curr_size; /*!< current pool size in pages */
- ulint old_size; /*!< previous pool size in pages */
- ulint read_ahead_area;/*!< size in pages of the area which
- the read-ahead algorithms read if
- invoked */
- hash_table_t* page_hash; /*!< hash table of buf_page_t or
- buf_block_t file pages,
- buf_page_in_file() == TRUE,
- indexed by (space_id, offset).
- page_hash is protected by an
- array of mutexes.
- Changes in page_hash are protected
- by buf_pool.mutex and the relevant
- page_hash mutex. Lookups can happen
- while holding the buf_pool.mutex or
- the relevant page_hash mutex. */
+ /** current pool size in pages */
+ Atomic_counter<ulint> curr_size;
+ /** previous pool size in pages */
+ Atomic_counter<ulint> old_size;
+ /** read-ahead request size in pages */
+ Atomic_counter<uint32_t> read_ahead_area;
+
+ /** Hash table of file pages (buf_page_t::in_file() holds),
+ indexed by page_id_t. Protected by both mutex and hash_lock_get(id). */
+ hash_table_t *page_hash;
hash_table_t* page_hash_old; /*!< old pointer to page_hash to be
freed after resizing buffer pool */
hash_table_t* zip_hash; /*!< hash table of buf_block_t blocks
whose frames are allocated to the
zip buddy system,
- indexed by block->frame */
- ulint n_pend_reads; /*!< number of pending read
- operations */
+ indexed by block->frame;
+ protected by buf_pool.mutex*/
+ /** number of pending read operations */
+ Atomic_counter<ulint> n_pend_reads;
Atomic_counter<ulint>
n_pend_unzip; /*!< number of pending decompressions */
@@ -1968,13 +1943,13 @@ public:
UT_LIST_BASE_NODE_T(buf_page_t) flush_list;
/*!< base node of the modified block
list */
- ibool init_flush[BUF_FLUSH_N_TYPES];
+ ibool init_flush[3];
/*!< this is TRUE when a flush of the
given type is being initialized */
- ulint n_flush[BUF_FLUSH_N_TYPES];
- /*!< this is the number of pending
- writes in the given flush type */
- os_event_t no_flush[BUF_FLUSH_N_TYPES];
+ /** Number of pending writes of a flush type.
+ The sum of these is approximately the sum of BUF_IO_WRITE blocks. */
+ Atomic_counter<ulint> n_flush[3];
+ os_event_t no_flush[3];
/*!< this is in the set state
when there is no flush batch
of the given type running;
@@ -2071,10 +2046,11 @@ public:
frames and buf_page_t descriptors of blocks that exist
in the buffer pool only in compressed form. */
/* @{ */
-#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
+#ifdef UNIV_DEBUG
+ /** unmodified ROW_FORMAT=COMPRESSED pages;
+ protected by buf_pool.mutex */
UT_LIST_BASE_NODE_T(buf_page_t) zip_clean;
- /*!< unmodified compressed pages */
-#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
+#endif /* UNIV_DEBUG */
UT_LIST_BASE_NODE_T(buf_buddy_free_t) zip_free[BUF_BUDDY_SIZES_MAX];
/*!< buddy free lists */
#if BUF_BUDDY_LOW > UNIV_ZIP_SIZE_MIN
@@ -2082,12 +2058,9 @@ public:
#endif
/* @} */
- buf_page_t* watch;
- /*!< Sentinel records for buffer
- pool watches. Protected by
- buf_pool.mutex. */
-
-
+ /** Sentinels to detect if pages are read into the buffer pool while
+ a delete-buffering operation is pending. Protected by mutex. */
+ buf_page_t watch[innodb_purge_threads_MAX + 1];
/** Reserve a buffer. */
buf_tmp_buffer_t *io_buf_reserve() { return io_buf.reserve(); }
private:
@@ -2143,71 +2116,126 @@ private:
/** The InnoDB buffer pool */
extern buf_pool_t buf_pool;
-/** @name Accessors for buffer pool mutexes
-Use these instead of accessing buffer pool mutexes directly. */
-/* @{ */
+inline void buf_page_t::add_buf_fix_count(uint32_t count)
+{
+ ut_ad(mutex_own(&buf_pool.mutex));
+ buf_fix_count_+= count;
+}
-/** Test if block->mutex is owned. */
-#define buf_page_mutex_own(b) (b)->mutex.is_owned()
+inline void buf_page_t::set_buf_fix_count(uint32_t count)
+{
+ ut_ad(mutex_own(&buf_pool.mutex));
+ buf_fix_count_= count;
+}
-/** Acquire the block->mutex. */
-#define buf_page_mutex_enter(b) do { \
- mutex_enter(&(b)->mutex); \
-} while (0)
+inline void buf_page_t::set_state(buf_page_state state)
+{
+ ut_ad(mutex_own(&buf_pool.mutex));
+ state_= state;
+}
-/** Release the trx->mutex. */
-#define buf_page_mutex_exit(b) do { \
- (b)->mutex.exit(); \
-} while (0)
+inline void buf_page_t::set_io_fix(buf_io_fix io_fix)
+{
+ ut_ad(mutex_own(&buf_pool.mutex));
+ io_fix_= io_fix;
+}
+inline void buf_page_t::set_corrupt_id()
+{
+ ut_ad(!oldest_modification());
+#ifdef UNIV_DEBUG
+ switch (state()) {
+ case BUF_BLOCK_REMOVE_HASH:
+ break;
+ case BUF_BLOCK_ZIP_PAGE:
+ case BUF_BLOCK_FILE_PAGE:
+ ut_ad(rw_lock_own(buf_pool.hash_lock_get(id_), RW_LOCK_X));
+ break;
+ case BUF_BLOCK_NOT_USED:
+ case BUF_BLOCK_MEMORY:
+ ut_ad("invalid state" == 0);
+ }
+#endif
+ id_= page_id_t(~0ULL);
+}
-/** Get appropriate page_hash_lock. */
-UNIV_INLINE
-rw_lock_t*
-buf_page_hash_lock_get(const page_id_t& page_id)
+/** Set oldest_modification when adding to buf_pool.flush_list */
+inline void buf_page_t::set_oldest_modification(lsn_t lsn)
{
- return hash_get_lock(buf_pool.page_hash, page_id.fold());
+ ut_ad(mutex_own(&buf_pool.flush_list_mutex));
+ ut_ad(!oldest_modification());
+ oldest_modification_= lsn;
}
-/** If not appropriate page_hash_lock, relock until appropriate. */
-# define buf_page_hash_lock_s_confirm(hash_lock, page_id)\
- hash_lock_s_confirm(hash_lock, buf_pool.page_hash, (page_id).fold())
+/** Clear oldest_modification when removing from buf_pool.flush_list */
+inline void buf_page_t::clear_oldest_modification()
+{
+ ut_ad(mutex_own(&buf_pool.flush_list_mutex));
+ ut_d(const auto state= state_);
+ ut_ad(state == BUF_BLOCK_FILE_PAGE || state == BUF_BLOCK_ZIP_PAGE ||
+ state == BUF_BLOCK_REMOVE_HASH);
+ ut_ad(oldest_modification());
+ oldest_modification_= 0;
+}
-# define buf_page_hash_lock_x_confirm(hash_lock, page_id)\
- hash_lock_x_confirm(hash_lock, buf_pool.page_hash, (page_id).fold())
+/** @return whether the block is modified and ready for flushing */
+inline bool buf_page_t::ready_for_flush() const
+{
+ ut_ad(mutex_own(&buf_pool.mutex));
+ ut_ad(in_LRU_list);
+ ut_a(in_file());
+ return oldest_modification() && io_fix_ == BUF_IO_NONE;
+}
-#ifdef UNIV_DEBUG
-/** Test if page_hash lock is held in s-mode. */
-# define buf_page_hash_lock_held_s(bpage) \
- rw_lock_own(buf_page_hash_lock_get((bpage)->id), RW_LOCK_S)
+/** @return whether the block can be relocated in memory.
+The block can be dirty, but it must not be I/O-fixed or bufferfixed. */
+inline bool buf_page_t::can_relocate() const
+{
+ ut_ad(mutex_own(&buf_pool.mutex));
+ ut_ad(in_file());
+ ut_ad(in_LRU_list);
+ return io_fix_ == BUF_IO_NONE && !buf_fix_count_;
+}
-/** Test if page_hash lock is held in x-mode. */
-# define buf_page_hash_lock_held_x(bpage) \
- rw_lock_own(buf_page_hash_lock_get((bpage)->id), RW_LOCK_X)
+/** @return whether the block has been flagged old in buf_pool.LRU */
+inline bool buf_page_t::is_old() const
+{
+ ut_ad(mutex_own(&buf_pool.mutex));
+ ut_ad(in_file());
+ ut_ad(in_LRU_list);
+ return old;
+}
-/** Test if page_hash lock is held in x or s-mode. */
-# define buf_page_hash_lock_held_s_or_x(bpage)\
- (buf_page_hash_lock_held_s(bpage) \
- || buf_page_hash_lock_held_x(bpage))
+/** Set whether a block is old in buf_pool.LRU */
+inline void buf_page_t::set_old(bool old)
+{
+ ut_ad(in_file());
+ ut_ad(mutex_own(&buf_pool.mutex));
+ ut_ad(in_LRU_list);
-# define buf_block_hash_lock_held_s(block) \
- buf_page_hash_lock_held_s(&(block)->page)
+#ifdef UNIV_LRU_DEBUG
+ ut_a((buf_pool.LRU_old_len == 0) == (buf_pool.LRU_old == nullptr));
+ /* If a block is flagged "old", the LRU_old list must exist. */
+ ut_a(!old || buf_pool.LRU_old);
-# define buf_block_hash_lock_held_x(block) \
- buf_page_hash_lock_held_x(&(block)->page)
+ if (UT_LIST_GET_PREV(LRU, this) && UT_LIST_GET_NEXT(LRU, this))
+ {
+ const buf_page_t *prev= UT_LIST_GET_PREV(LRU, this);
+ const buf_page_t *next = UT_LIST_GET_NEXT(LRU, this);
+ if (prev->old == next->old)
+ ut_a(prev->old == old);
+ else
+ {
+ ut_a(!prev->old);
+ ut_a(buf_pool.LRU_old == (old ? this : next));
+ }
+ }
+#endif /* UNIV_LRU_DEBUG */
-# define buf_block_hash_lock_held_s_or_x(block) \
- buf_page_hash_lock_held_s_or_x(&(block)->page)
-#else /* UNIV_DEBUG */
-# define buf_page_hash_lock_held_s(p) (TRUE)
-# define buf_page_hash_lock_held_x(p) (TRUE)
-# define buf_page_hash_lock_held_s_or_x(p) (TRUE)
-# define buf_block_hash_lock_held_s(p) (TRUE)
-# define buf_block_hash_lock_held_x(p) (TRUE)
-# define buf_block_hash_lock_held_s_or_x(p) (TRUE)
-#endif /* UNIV_DEBUG */
+ this->old= old;
+}
-#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
+#ifdef UNIV_DEBUG
/** Forbid the release of the buffer pool mutex. */
# define buf_pool_mutex_exit_forbid() do { \
ut_ad(mutex_own(&buf_pool.mutex)); \
@@ -2224,15 +2252,12 @@ buf_page_hash_lock_get(const page_id_t& page_id)
/** Allow the release of the buffer pool mutex. */
# define buf_pool_mutex_exit_allow() ((void) 0)
#endif
-/* @} */
/**********************************************************************
Let us list the consistency conditions for different control block states.
NOT_USED: is in free list, not in LRU list, not in flush list, nor
page hash table
-READY_FOR_USE: is not in free list, LRU list, or flush list, nor page
- hash table
MEMORY: is not in free list, LRU list, or flush list, nor page
hash table
FILE_PAGE: space and offset are defined, is in page hash table
@@ -2260,9 +2285,8 @@ FILE_PAGE: space and offset are defined, is in page hash table
State transitions:
-NOT_USED => READY_FOR_USE
-READY_FOR_USE => MEMORY
-READY_FOR_USE => FILE_PAGE
+NOT_USED => MEMORY
+MEMORY => FILE_PAGE
MEMORY => NOT_USED
FILE_PAGE => NOT_USED NOTE: This transition is allowed if and only if
(1) buf_fix_count == 0,
@@ -2284,7 +2308,7 @@ inline buf_page_t *LRUItr::start()
return m_hp;
}
-#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
+#ifdef UNIV_DEBUG
/** Functor to validate the LRU list. */
struct CheckInLRUList {
void operator()(const buf_page_t* elem) const
@@ -2324,7 +2348,7 @@ struct CheckUnzipLRUAndLRUList {
CheckUnzipLRUAndLRUList());
}
};
-#endif /* UNIV_DEBUG || defined UNIV_BUF_DEBUG */
+#endif /* UNIV_DEBUG */
#include "buf0buf.ic"