mirror of
https://github.com/MariaDB/server.git
synced 2025-01-18 21:12:26 +01:00
ad2bf1129c
Problem: ======== During buffer pool resizing, InnoDB recreates the dictionary hash tables. Dictionary hash table reuses the heap of AHI hash tables. It leads to memory corruption. Fix: ==== - While disabling AHI, free the heap and AHI hash tables. Recreate the AHI hash tables and assign new heap when AHI is enabled. - btr_blob_free() access invalid page if page was reallocated during buffer poolresizing. So btr_blob_free() should get the page from buf_pool instead of using existing block. - btr_search_enabled and block->index should be checked after acquiring the btr_search_sys latch - Moved the buffer_pool_scan debug sync to earlier before accessing the btr_search_sys latches to avoid the hang of truncate_purge_debug test case - srv_printf_innodb_monitor() should acquire btr_search_sys latches before AHI hash tables.
339 lines
11 KiB
C
339 lines
11 KiB
C
/*****************************************************************************
|
|
|
|
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
|
|
Copyright (c) 2018, 2020, 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/btr0sea.h
|
|
The index tree adaptive search
|
|
|
|
Created 2/17/1996 Heikki Tuuri
|
|
*************************************************************************/
|
|
|
|
#ifndef btr0sea_h
|
|
#define btr0sea_h
|
|
|
|
#include "dict0dict.h"
|
|
#ifdef BTR_CUR_HASH_ADAPT
|
|
#include "ha0ha.h"
|
|
|
|
/** Creates and initializes the adaptive search system at a database start.
|
|
@param[in] hash_size hash table size. */
|
|
void
|
|
btr_search_sys_create(ulint hash_size);
|
|
|
|
/** Frees the adaptive search system at a database shutdown. */
|
|
void
|
|
btr_search_sys_free();
|
|
|
|
/** Disable the adaptive hash search system and empty the index. */
|
|
void btr_search_disable();
|
|
|
|
/** Enable the adaptive hash search system.
|
|
@param[in] resize Flag to indicate call during buf_pool_resize() */
|
|
void
|
|
btr_search_enable(bool resize=false);
|
|
|
|
/*********************************************************************//**
|
|
Updates the search info. */
|
|
UNIV_INLINE
|
|
void
|
|
btr_search_info_update(
|
|
/*===================*/
|
|
dict_index_t* index, /*!< in: index of the cursor */
|
|
btr_cur_t* cursor);/*!< in: cursor which was just positioned */
|
|
|
|
/** Tries to guess the right search position based on the hash search info
|
|
of the index. Note that if mode is PAGE_CUR_LE, which is used in inserts,
|
|
and the function returns TRUE, then cursor->up_match and cursor->low_match
|
|
both have sensible values.
|
|
@param[in,out] index index
|
|
@param[in,out] info index search info
|
|
@param[in] tuple logical record
|
|
@param[in] mode PAGE_CUR_L, ....
|
|
@param[in] latch_mode BTR_SEARCH_LEAF, ...;
|
|
NOTE that only if has_search_latch is 0, we will
|
|
have a latch set on the cursor page, otherwise
|
|
we assume the caller uses his search latch
|
|
to protect the record!
|
|
@param[out] cursor tree cursor
|
|
@param[in] has_search_latch
|
|
latch mode the caller currently has on
|
|
search system: RW_S/X_LATCH or 0
|
|
@param[in] mtr mini transaction
|
|
@return TRUE if succeeded */
|
|
ibool
|
|
btr_search_guess_on_hash(
|
|
dict_index_t* index,
|
|
btr_search_t* info,
|
|
const dtuple_t* tuple,
|
|
ulint mode,
|
|
ulint latch_mode,
|
|
btr_cur_t* cursor,
|
|
ulint has_search_latch,
|
|
mtr_t* mtr);
|
|
|
|
/** Moves or deletes hash entries for moved records. If new_page is already
|
|
hashed, then the hash index for page, if any, is dropped. If new_page is not
|
|
hashed, and page is hashed, then a new hash index is built to new_page with the
|
|
same parameters as page (this often happens when a page is split).
|
|
@param[in,out] new_block records are copied to this page.
|
|
@param[in,out] block index page from which record are copied, and the
|
|
copied records will be deleted from this page.
|
|
@param[in,out] index record descriptor */
|
|
void
|
|
btr_search_move_or_delete_hash_entries(
|
|
buf_block_t* new_block,
|
|
buf_block_t* block,
|
|
dict_index_t* index);
|
|
|
|
/** Drop any adaptive hash index entries that point to an index page.
|
|
@param[in,out] block block containing index page, s- or x-latched, or an
|
|
index page for which we know that
|
|
block->buf_fix_count == 0 or it is an index page which
|
|
has already been removed from the buf_pool->page_hash
|
|
i.e.: it is in state BUF_BLOCK_REMOVE_HASH */
|
|
void
|
|
btr_search_drop_page_hash_index(buf_block_t* block);
|
|
|
|
/** Drop possible adaptive hash index entries when a page is evicted
|
|
from the buffer pool or freed in a file, or the index is being dropped.
|
|
@param[in] page_id page id */
|
|
void btr_search_drop_page_hash_when_freed(const page_id_t page_id);
|
|
|
|
/** Updates the page hash index when a single record is inserted on a page.
|
|
@param[in] cursor cursor which was positioned to the place to insert
|
|
using btr_cur_search_, and the new record has been
|
|
inserted next to the cursor. */
|
|
void
|
|
btr_search_update_hash_node_on_insert(btr_cur_t* cursor);
|
|
|
|
/** Updates the page hash index when a single record is inserted on a page.
|
|
@param[in] cursor cursor which was positioned to the
|
|
place to insert using btr_cur_search_...,
|
|
and the new record has been inserted next
|
|
to the cursor */
|
|
void
|
|
btr_search_update_hash_on_insert(btr_cur_t* cursor);
|
|
|
|
/** Updates the page hash index when a single record is deleted from a page.
|
|
@param[in] cursor cursor which was positioned on the record to delete
|
|
using btr_cur_search_, the record is not yet deleted.*/
|
|
void
|
|
btr_search_update_hash_on_delete(btr_cur_t* cursor);
|
|
|
|
/** Validates the search system.
|
|
@return true if ok */
|
|
bool
|
|
btr_search_validate();
|
|
|
|
/** Lock all search latches in exclusive mode. */
|
|
UNIV_INLINE
|
|
void
|
|
btr_search_x_lock_all();
|
|
|
|
/** Unlock all search latches from exclusive mode. */
|
|
UNIV_INLINE
|
|
void
|
|
btr_search_x_unlock_all();
|
|
|
|
/** Lock all search latches in shared mode. */
|
|
UNIV_INLINE
|
|
void
|
|
btr_search_s_lock_all();
|
|
|
|
#ifdef UNIV_DEBUG
|
|
/** Check if thread owns all the search latches.
|
|
@param[in] mode lock mode check
|
|
@retval true if owns all of them
|
|
@retval false if does not own some of them */
|
|
UNIV_INLINE
|
|
bool
|
|
btr_search_own_all(ulint mode);
|
|
|
|
/** Check if thread owns any of the search latches.
|
|
@param[in] mode lock mode check
|
|
@retval true if owns any of them
|
|
@retval false if owns no search latch */
|
|
UNIV_INLINE
|
|
bool
|
|
btr_search_own_any(ulint mode);
|
|
#endif /* UNIV_DEBUG */
|
|
|
|
/** Unlock all search latches from shared mode. */
|
|
UNIV_INLINE
|
|
void
|
|
btr_search_s_unlock_all();
|
|
|
|
/** Get the latch based on index attributes.
|
|
A latch is selected from an array of latches using pair of index-id, space-id.
|
|
@param[in] index index handler
|
|
@return latch */
|
|
UNIV_INLINE
|
|
rw_lock_t*
|
|
btr_get_search_latch(const dict_index_t* index);
|
|
|
|
/** Get the hash-table based on index attributes.
|
|
A table is selected from an array of tables using pair of index-id, space-id.
|
|
@param[in] index index handler
|
|
@return hash table */
|
|
UNIV_INLINE
|
|
hash_table_t*
|
|
btr_get_search_table(const dict_index_t* index);
|
|
#else /* BTR_CUR_HASH_ADAPT */
|
|
# define btr_search_sys_create(size)
|
|
# define btr_search_drop_page_hash_index(block)
|
|
# define btr_search_s_lock_all(index)
|
|
# define btr_search_s_unlock_all(index)
|
|
# define btr_search_info_update(index, cursor)
|
|
# define btr_search_move_or_delete_hash_entries(new_block, block, index)
|
|
# define btr_search_update_hash_on_insert(cursor)
|
|
# define btr_search_update_hash_on_delete(cursor)
|
|
#endif /* BTR_CUR_HASH_ADAPT */
|
|
|
|
#ifdef BTR_CUR_ADAPT
|
|
/** Create and initialize search info.
|
|
@param[in,out] heap heap where created
|
|
@return own: search info struct */
|
|
UNIV_INLINE
|
|
btr_search_t*
|
|
btr_search_info_create(mem_heap_t* heap)
|
|
MY_ATTRIBUTE((nonnull, warn_unused_result));
|
|
|
|
/** @return the search info of an index */
|
|
UNIV_INLINE
|
|
btr_search_t*
|
|
btr_search_get_info(dict_index_t* index)
|
|
{
|
|
return(index->search_info);
|
|
}
|
|
#endif /* BTR_CUR_ADAPT */
|
|
|
|
/** The search info struct in an index */
|
|
struct btr_search_t{
|
|
/* @{ The following fields are not protected by any latch.
|
|
Unfortunately, this means that they must be aligned to
|
|
the machine word, i.e., they cannot be turned into bit-fields. */
|
|
buf_block_t* root_guess;/*!< the root page frame when it was last time
|
|
fetched, or NULL */
|
|
ulint withdraw_clock; /*!< the withdraw clock value of the buffer
|
|
pool when root_guess was stored */
|
|
#ifdef BTR_CUR_HASH_ADAPT
|
|
ulint hash_analysis; /*!< when this exceeds
|
|
BTR_SEARCH_HASH_ANALYSIS, the hash
|
|
analysis starts; this is reset if no
|
|
success noticed */
|
|
ibool last_hash_succ; /*!< TRUE if the last search would have
|
|
succeeded, or did succeed, using the hash
|
|
index; NOTE that the value here is not exact:
|
|
it is not calculated for every search, and the
|
|
calculation itself is not always accurate! */
|
|
ulint n_hash_potential;
|
|
/*!< number of consecutive searches
|
|
which would have succeeded, or did succeed,
|
|
using the hash index;
|
|
the range is 0 .. BTR_SEARCH_BUILD_LIMIT + 5 */
|
|
/* @} */
|
|
ulint ref_count; /*!< Number of blocks in this index tree
|
|
that have search index built
|
|
i.e. block->index points to this index.
|
|
Protected by search latch except
|
|
when during initialization in
|
|
btr_search_info_create(). */
|
|
|
|
/*---------------------- @{ */
|
|
ulint n_fields; /*!< recommended prefix length for hash search:
|
|
number of full fields */
|
|
ulint n_bytes; /*!< recommended prefix: number of bytes in
|
|
an incomplete field
|
|
@see BTR_PAGE_MAX_REC_SIZE */
|
|
ibool left_side; /*!< TRUE or FALSE, depending on whether
|
|
the leftmost record of several records with
|
|
the same prefix should be indexed in the
|
|
hash index */
|
|
/*---------------------- @} */
|
|
#ifdef UNIV_SEARCH_PERF_STAT
|
|
ulint n_hash_succ; /*!< number of successful hash searches thus
|
|
far */
|
|
ulint n_hash_fail; /*!< number of failed hash searches */
|
|
ulint n_patt_succ; /*!< number of successful pattern searches thus
|
|
far */
|
|
ulint n_searches; /*!< number of searches */
|
|
#endif /* UNIV_SEARCH_PERF_STAT */
|
|
#endif /* BTR_CUR_HASH_ADAPT */
|
|
#ifdef UNIV_DEBUG
|
|
ulint magic_n; /*!< magic number @see BTR_SEARCH_MAGIC_N */
|
|
/** value of btr_search_t::magic_n, used in assertions */
|
|
# define BTR_SEARCH_MAGIC_N 1112765
|
|
#endif /* UNIV_DEBUG */
|
|
};
|
|
|
|
#ifdef BTR_CUR_HASH_ADAPT
|
|
/** @return number of leaf pages pointed to by the adaptive hash index */
|
|
inline ulint dict_index_t::n_ahi_pages() const
|
|
{
|
|
if (!btr_search_enabled)
|
|
return 0;
|
|
rw_lock_t *latch = btr_get_search_latch(this);
|
|
rw_lock_s_lock(latch);
|
|
ulint ref_count= search_info->ref_count;
|
|
rw_lock_s_unlock(latch);
|
|
return ref_count;
|
|
}
|
|
|
|
/** The hash index system */
|
|
struct btr_search_sys_t{
|
|
hash_table_t** hash_tables; /*!< the adaptive hash tables,
|
|
mapping dtuple_fold values
|
|
to rec_t pointers on index pages */
|
|
};
|
|
|
|
/** Latches protecting access to adaptive hash index. */
|
|
extern rw_lock_t** btr_search_latches;
|
|
|
|
/** The adaptive hash index */
|
|
extern btr_search_sys_t* btr_search_sys;
|
|
|
|
#ifdef UNIV_SEARCH_PERF_STAT
|
|
/** Number of successful adaptive hash index lookups */
|
|
extern ulint btr_search_n_succ;
|
|
/** Number of failed adaptive hash index lookups */
|
|
extern ulint btr_search_n_hash_fail;
|
|
#endif /* UNIV_SEARCH_PERF_STAT */
|
|
|
|
/** After change in n_fields or n_bytes in info, this many rounds are waited
|
|
before starting the hash analysis again: this is to save CPU time when there
|
|
is no hope in building a hash index. */
|
|
#define BTR_SEARCH_HASH_ANALYSIS 17
|
|
|
|
/** Limit of consecutive searches for trying a search shortcut on the search
|
|
pattern */
|
|
#define BTR_SEARCH_ON_PATTERN_LIMIT 3
|
|
|
|
/** Limit of consecutive searches for trying a search shortcut using
|
|
the hash index */
|
|
#define BTR_SEARCH_ON_HASH_LIMIT 3
|
|
|
|
/** We do this many searches before trying to keep the search latch
|
|
over calls from MySQL. If we notice someone waiting for the latch, we
|
|
again set this much timeout. This is to reduce contention. */
|
|
#define BTR_SEA_TIMEOUT 10000
|
|
#endif /* BTR_CUR_HASH_ADAPT */
|
|
|
|
#include "btr0sea.ic"
|
|
|
|
#endif
|