mirror of
https://github.com/MariaDB/server.git
synced 2025-01-17 20:42:30 +01:00
458 lines
16 KiB
C++
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
|