mariadb/storage/innobase/include/buf0flu.h
2022-01-17 16:41:51 +01:00

458 lines
16 KiB
C++

/*****************************************************************************
Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2014, 2018, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
*****************************************************************************/
/**************************************************//**
@file include/buf0flu.h
The database buffer pool flush algorithm
Created 11/5/1995 Heikki Tuuri
*******************************************************/
#ifndef buf0flu_h
#define buf0flu_h
#include "ut0byte.h"
#include "log0log.h"
#include "buf0types.h"
/** Flag indicating if the page_cleaner is in active state. */
extern bool buf_page_cleaner_is_active;
#ifdef UNIV_DEBUG
/** Value of MySQL global variable used to disable page cleaner. */
extern my_bool innodb_page_cleaner_disabled_debug;
#endif /* UNIV_DEBUG */
/** Event to synchronise with the flushing. */
extern os_event_t buf_flush_event;
class ut_stage_alter_t;
/** Handled page counters for a single flush */
struct flush_counters_t {
ulint flushed; /*!< number of dirty pages flushed */
ulint evicted; /*!< number of clean pages evicted */
ulint unzip_LRU_evicted;/*!< number of uncompressed page images
evicted */
};
/********************************************************************//**
Remove a block from the flush list of modified blocks. */
void
buf_flush_remove(
/*=============*/
buf_page_t* bpage); /*!< in: pointer to the block in question */
/*******************************************************************//**
Relocates a buffer control block on the flush_list.
Note that it is assumed that the contents of bpage has already been
copied to dpage. */
void
buf_flush_relocate_on_flush_list(
/*=============================*/
buf_page_t* bpage, /*!< in/out: control block being moved */
buf_page_t* dpage); /*!< in/out: destination block */
/** Update the flush system data structures when a write is completed.
@param[in,out] bpage flushed page
@param[in] dblwr whether the doublewrite buffer was used */
void buf_flush_write_complete(buf_page_t* bpage, bool dblwr);
/** Initialize a page for writing to the tablespace.
@param[in] block buffer block; NULL if bypassing the buffer pool
@param[in,out] page page frame
@param[in,out] page_zip_ compressed page, or NULL if uncompressed
@param[in] newest_lsn newest modification LSN to the page */
void
buf_flush_init_for_writing(
const buf_block_t* block,
byte* page,
void* page_zip_,
lsn_t newest_lsn);
# if defined UNIV_DEBUG || defined UNIV_IBUF_DEBUG
/********************************************************************//**
Writes a flushable page asynchronously from the buffer pool to a file.
NOTE: buf_pool->mutex and block->mutex must be held upon entering this
function, and they will be released by this function after flushing.
This is loosely based on buf_flush_batch() and buf_flush_page().
@return TRUE if the page was flushed and the mutexes released */
ibool
buf_flush_page_try(
/*===============*/
buf_pool_t* buf_pool, /*!< in/out: buffer pool instance */
buf_block_t* block) /*!< in/out: buffer control block */
MY_ATTRIBUTE((warn_unused_result));
# endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */
/** Do flushing batch of a given type.
NOTE: The calling thread is not allowed to own any latches on pages!
@param[in,out] buf_pool buffer pool instance
@param[in] type flush type
@param[in] min_n wished minimum mumber of blocks flushed
(it is not guaranteed that the actual number is that big, though)
@param[in] lsn_limit in the case BUF_FLUSH_LIST all blocks whose
oldest_modification is smaller than this should be flushed (if their number
does not exceed min_n), otherwise ignored
@param[out] n the number of pages which were processed is
passed back to caller. Ignored if NULL
@retval true if a batch was queued successfully.
@retval false if another batch of same type was already running. */
bool
buf_flush_do_batch(
buf_pool_t* buf_pool,
buf_flush_t type,
ulint min_n,
lsn_t lsn_limit,
flush_counters_t* n);
/** This utility flushes dirty blocks from the end of the flush list of all
buffer pool instances.
NOTE: The calling thread is not allowed to own any latches on pages!
@param[in] min_n wished minimum mumber of blocks flushed (it is
not guaranteed that the actual number is that big, though)
@param[in] lsn_limit in the case BUF_FLUSH_LIST all blocks whose
oldest_modification is smaller than this should be flushed (if their number
does not exceed min_n), otherwise ignored
@param[out] n_processed the number of pages which were processed is
passed back to caller. Ignored if NULL.
@return true if a batch was queued successfully for each buffer pool
instance. false if another batch of same type was already running in
at least one of the buffer pool instance */
bool
buf_flush_lists(
ulint min_n,
lsn_t lsn_limit,
ulint* n_processed);
/******************************************************************//**
This function picks up a single page from the tail of the LRU
list, flushes it (if it is dirty), removes it from page_hash and LRU
list and puts it on the free list. It is called from user threads when
they are unable to find a replaceable page at the tail of the LRU
list i.e.: when the background LRU flushing in the page_cleaner thread
is not fast enough to keep pace with the workload.
@return true if success. */
bool
buf_flush_single_page_from_LRU(
/*===========================*/
buf_pool_t* buf_pool); /*!< in/out: buffer pool instance */
/******************************************************************//**
Waits until a flush batch of the given type ends */
void
buf_flush_wait_batch_end(
/*=====================*/
buf_pool_t* buf_pool, /*!< in: buffer pool instance */
buf_flush_t type); /*!< in: BUF_FLUSH_LRU
or BUF_FLUSH_LIST */
/**
Waits until a flush batch of the given lsn ends
@param[in] new_oldest target oldest_modified_lsn to wait for */
void
buf_flush_wait_flushed(
lsn_t new_oldest);
/********************************************************************//**
This function should be called at a mini-transaction commit, if a page was
modified in it. Puts the block to the list of modified blocks, if it not
already in it. */
UNIV_INLINE
void
buf_flush_note_modification(
/*========================*/
buf_block_t* block, /*!< in: block which is modified */
lsn_t start_lsn, /*!< in: start lsn of the first mtr in a
set of mtr's */
lsn_t end_lsn, /*!< in: end lsn of the last mtr in the
set of mtr's */
FlushObserver* observer); /*!< in: flush observer */
/********************************************************************//**
This function should be called when recovery has modified a buffer page. */
UNIV_INLINE
void
buf_flush_recv_note_modification(
/*=============================*/
buf_block_t* block, /*!< in: block which is modified */
lsn_t start_lsn, /*!< in: start lsn of the first mtr in a
set of mtr's */
lsn_t end_lsn); /*!< in: end lsn of the last mtr in the
set of mtr's */
/********************************************************************//**
Returns TRUE if the file page block is immediately suitable for replacement,
i.e., transition FILE_PAGE => NOT_USED allowed.
@return TRUE if can replace immediately */
ibool
buf_flush_ready_for_replace(
/*========================*/
buf_page_t* bpage); /*!< in: buffer control block, must be
buf_page_in_file(bpage) and in the LRU list */
#ifdef UNIV_DEBUG
/** Disables page cleaner threads (coordinator and workers).
It's used by: SET GLOBAL innodb_page_cleaner_disabled_debug = 1 (0).
@param[in] thd thread handle
@param[in] var pointer to system variable
@param[out] var_ptr where the formal string goes
@param[in] save immediate result from check function */
void
buf_flush_page_cleaner_disabled_debug_update(
THD* thd,
struct st_mysql_sys_var* var,
void* var_ptr,
const void* save);
#endif /* UNIV_DEBUG */
/******************************************************************//**
page_cleaner thread tasked with flushing dirty pages from the buffer
pools. As of now we'll have only one coordinator of this thread.
@return a dummy parameter */
extern "C"
os_thread_ret_t
DECLARE_THREAD(buf_flush_page_cleaner_coordinator)(
/*===============================================*/
void* arg); /*!< in: a dummy parameter required by
os_thread_create */
/******************************************************************//**
Worker thread of page_cleaner.
@return a dummy parameter */
extern "C"
os_thread_ret_t
DECLARE_THREAD(buf_flush_page_cleaner_worker)(
/*==========================================*/
void* arg); /*!< in: a dummy parameter required by
os_thread_create */
/** Initialize page_cleaner. */
void
buf_flush_page_cleaner_init(void);
/** Wait for any possible LRU flushes that are in progress to end. */
void
buf_flush_wait_LRU_batch_end(void);
#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
/******************************************************************//**
Validates the flush list.
@return TRUE if ok */
ibool
buf_flush_validate(
/*===============*/
buf_pool_t* buf_pool);
#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
/********************************************************************//**
Initialize the red-black tree to speed up insertions into the flush_list
during recovery process. Should be called at the start of recovery
process before any page has been read/written. */
void
buf_flush_init_flush_rbt(void);
/*==========================*/
/********************************************************************//**
Frees up the red-black tree. */
void
buf_flush_free_flush_rbt(void);
/*==========================*/
/********************************************************************//**
Writes a flushable page asynchronously from the buffer pool to a file.
NOTE: in simulated aio we must call
os_aio_simulated_wake_handler_threads after we have posted a batch of
writes! NOTE: buf_pool->mutex and buf_page_get_mutex(bpage) must be
held upon entering this function, and they will be released by this
function.
@return TRUE if page was flushed */
ibool
buf_flush_page(
/*===========*/
buf_pool_t* buf_pool, /*!< in: buffer pool instance */
buf_page_t* bpage, /*!< in: buffer control block */
buf_flush_t flush_type, /*!< in: type of flush */
bool sync); /*!< in: true if sync IO request */
/********************************************************************//**
Returns true if the block is modified and ready for flushing.
@return true if can flush immediately */
bool
buf_flush_ready_for_flush(
/*======================*/
buf_page_t* bpage, /*!< in: buffer control block, must be
buf_page_in_file(bpage) */
buf_flush_t flush_type)/*!< in: type of flush */
MY_ATTRIBUTE((warn_unused_result));
/******************************************************************//**
Check if there are any dirty pages that belong to a space id in the flush
list in a particular buffer pool.
@return number of dirty pages present in a single buffer pool */
ulint
buf_pool_get_dirty_pages_count(
/*===========================*/
buf_pool_t* buf_pool, /*!< in: buffer pool */
ulint id, /*!< in: space id to check */
FlushObserver* observer); /*!< in: flush observer to check */
/*******************************************************************//**
Synchronously flush dirty blocks from the end of the flush list of all buffer
pool instances.
NOTE: The calling thread is not allowed to own any latches on pages! */
void
buf_flush_sync_all_buf_pools(void);
/*==============================*/
/** Request IO burst and wake page_cleaner up.
@param[in] lsn_limit upper limit of LSN to be flushed */
void
buf_flush_request_force(
lsn_t lsn_limit);
/** We use FlushObserver to track flushing of non-redo logged pages in bulk
create index(BtrBulk.cc).Since we disable redo logging during a index build,
we need to make sure that all dirty pages modifed by the index build are
flushed to disk before any redo logged operations go to the index. */
class FlushObserver {
public:
/** Constructor
@param[in] space_id table space id
@param[in] trx trx instance
@param[in] stage performance schema accounting object,
used by ALTER TABLE. It is passed to log_preflush_pool_modified_pages()
for accounting. */
FlushObserver(ulint space_id, trx_t* trx, ut_stage_alter_t* stage);
/** Deconstructor */
~FlushObserver();
/** Check pages have been flushed and removed from the flush list
in a buffer pool instance.
@param[in] instance_no buffer pool instance no
@return true if the pages were removed from the flush list */
bool is_complete(ulint instance_no)
{
return(m_flushed->at(instance_no) == m_removed->at(instance_no)
|| m_interrupted);
}
/** @return whether to flush only some pages of the tablespace */
bool is_partial_flush() const { return m_stage != NULL; }
/** @return whether the operation was interrupted */
bool is_interrupted() const { return m_interrupted; }
/** Interrupt observer not to wait. */
void interrupted()
{
m_interrupted = true;
}
/** Check whether the operation has been interrupted */
void check_interrupted();
/** Flush dirty pages. */
void flush();
/** Notify observer of flushing a page
@param[in] buf_pool buffer pool instance
@param[in] bpage buffer page to flush */
void notify_flush(
buf_pool_t* buf_pool,
buf_page_t* bpage);
/** Notify observer of removing a page from flush list
@param[in] buf_pool buffer pool instance
@param[in] bpage buffer page flushed */
void notify_remove(
buf_pool_t* buf_pool,
buf_page_t* bpage);
private:
/** Table space id */
const ulint m_space_id;
/** Trx instance */
const trx_t* const m_trx;
/** Performance schema accounting object, used by ALTER TABLE.
If not NULL, then stage->begin_phase_flush() will be called initially,
specifying the number of pages to be attempted to be flushed and
subsequently, stage->inc() will be called for each page we attempt to
flush. */
ut_stage_alter_t* m_stage;
/* Flush request sent */
std::vector<ulint>* m_flushed;
/* Flush request finished */
std::vector<ulint>* m_removed;
/* True if the operation was interrupted. */
bool m_interrupted;
};
/******************************************************************//**
Start a buffer flush batch for LRU or flush list */
ibool
buf_flush_start(
/*============*/
buf_pool_t* buf_pool, /*!< buffer pool instance */
buf_flush_t flush_type); /*!< in: BUF_FLUSH_LRU
or BUF_FLUSH_LIST */
/******************************************************************//**
End a buffer flush batch for LRU or flush list */
void
buf_flush_end(
/*==========*/
buf_pool_t* buf_pool, /*!< buffer pool instance */
buf_flush_t flush_type); /*!< in: BUF_FLUSH_LRU
or BUF_FLUSH_LIST */
/******************************************************************//**
Gather the aggregated stats for both flush list and LRU list flushing */
void
buf_flush_common(
/*=============*/
buf_flush_t flush_type, /*!< in: type of flush */
ulint page_count); /*!< in: number of pages flushed */
/*******************************************************************//**
This utility flushes dirty blocks from the end of the LRU list or flush_list.
NOTE 1: in the case of an LRU flush the calling thread may own latches to
pages: to avoid deadlocks, this function must be written so that it cannot
end up waiting for these latches! NOTE 2: in the case of a flush list flush,
the calling thread is not allowed to own any latches on pages! */
__attribute__((nonnull))
void
buf_flush_batch(
/*============*/
buf_pool_t* buf_pool, /*!< in: buffer pool instance */
buf_flush_t flush_type, /*!< in: BUF_FLUSH_LRU or
BUF_FLUSH_LIST; if BUF_FLUSH_LIST,
then the caller must not own any
latches on pages */
ulint min_n, /*!< in: wished minimum mumber of blocks
flushed (it is not guaranteed that the
actual number is that big, though) */
lsn_t lsn_limit, /*!< in: in the case of BUF_FLUSH_LIST
all blocks whose oldest_modification is
smaller than this should be flushed
(if their number does not exceed
min_n), otherwise ignored */
flush_counters_t* n); /*!< out: flushed/evicted page
counts */
#include "buf0flu.inl"
#endif