Browse Source
MDEV-35049: btr_search_check_free_space_in_heap() is a bottleneck
MDEV-35049: btr_search_check_free_space_in_heap() is a bottleneck
Let us use implement a simple fixed-size allocator for the adaptive hash index, insted of complicating mem_heap_t or mem_block_info_t. MEM_HEAP_BTR_SEARCH: Remove. mem_block_info_t::free_block(), mem_heap_free_block_free(): Remove. mem_heap_free_top(), mem_heap_get_top(): Remove. btr_sea::partition::spare: Replaces mem_block_info_t::free_block. This keeps one spare block per adaptive hash index partition, to process an insert. We must not wait for buf_pool.mutex while holding any btr_sea::partition::latch. That is why we cache one block for future allocations. This is protected by a new btr_sea::partition::blocks_mutex in order to relieve pressure on btr_sea::partition::latch. btr_sea::partition::prepare_insert(): Replaces btr_search_check_free_space_in_heap(). btr_sea::partition::erase(): Replaces ha_search_and_delete_if_found(). btr_sea::partition::cleanup_after_erase(): Replaces the most part of ha_delete_hash_node(). Unlike the previous implementation, we will retain a spare block for prepare_insert(). This should reduce some contention on buf_pool.mutex. btr_search.n_parts: Replaces btr_ahi_parts. btr_search.enabled: Replaces btr_search_enabled. This must hold whenever buf_block_t::index is set while a thread is holding a btr_sea::partition::latch. dict_index_t::search_info: Remove pointer indirection, and use Atomic_relaxed or Atomic_counter for most fields. btr_search_guess_on_hash(): Let the caller ensure that latch_mode is BTR_MODIFY_LEAF or BTR_SEARCH_LEAF. Release btr_sea::partition::latch before buffer-fixing the block. The page latch that we already acquired is preventing buffer pool eviction. We must validate both block->index and block->page.state while holding part.latch in order to avoid race conditions with buffer page relocation or buf_pool_t::resize(). btr_search_check_guess(): Remove the constant parameter can_only_compare_to_cursor_rec=false. ahi_node: Replaces ha_node_t. This has been tested by running the regression test suite with the adaptive hash index enabled: ./mtr --mysqld=--loose-innodb-adaptive-hash-index=ON Reviewed by: Vladislav Lesinbb-11.8-all-builders
33 changed files with 911 additions and 1547 deletions
-
6extra/mariabackup/xtrabackup.cc
-
3storage/innobase/CMakeLists.txt
-
14storage/innobase/btr/btr0btr.cc
-
59storage/innobase/btr/btr0cur.cc
-
1202storage/innobase/btr/btr0sea.cc
-
8storage/innobase/buf/buf0buf.cc
-
11storage/innobase/buf/buf0lru.cc
-
2storage/innobase/dict/dict0crea.cc
-
15storage/innobase/dict/dict0dict.cc
-
16storage/innobase/dict/dict0mem.cc
-
5storage/innobase/gis/gis0sea.cc
-
13storage/innobase/handler/ha_innodb.cc
-
6storage/innobase/handler/handler0alter.cc
-
6storage/innobase/ibuf/ibuf0ibuf.cc
-
7storage/innobase/include/btr0cur.h
-
396storage/innobase/include/btr0sea.h
-
117storage/innobase/include/btr0sea.inl
-
11storage/innobase/include/btr0types.h
-
4storage/innobase/include/buf0buf.h
-
66storage/innobase/include/dict0mem.h
-
60storage/innobase/include/ha0ha.h
-
154storage/innobase/include/ha0ha.inl
-
68storage/innobase/include/mem0mem.h
-
93storage/innobase/include/mem0mem.inl
-
52storage/innobase/mem/mem0mem.cc
-
3storage/innobase/mtr/mtr0mtr.cc
-
7storage/innobase/row/row0import.cc
-
11storage/innobase/row/row0ins.cc
-
2storage/innobase/row/row0merge.cc
-
2storage/innobase/row/row0mysql.cc
-
2storage/innobase/row/row0sel.cc
-
35storage/innobase/srv/srv0srv.cc
-
2storage/innobase/srv/srv0start.cc
1202
storage/innobase/btr/btr0sea.cc
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -1,117 +0,0 @@ |
|||
/***************************************************************************** |
|||
|
|||
Copyright (c) 1996, 2015, Oracle and/or its affiliates. All Rights Reserved. |
|||
Copyright (c) 2018, 2021, 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.ic |
|||
The index tree adaptive search |
|||
|
|||
Created 2/17/1996 Heikki Tuuri |
|||
*************************************************************************/ |
|||
|
|||
#include "dict0mem.h" |
|||
#include "btr0cur.h" |
|||
#include "buf0buf.h" |
|||
|
|||
/** Create and initialize search info. |
|||
@param[in,out] heap heap where created |
|||
@return own: search info struct */ |
|||
static inline btr_search_t* btr_search_info_create(mem_heap_t* heap) |
|||
{ |
|||
btr_search_t* info = static_cast<btr_search_t*>( |
|||
mem_heap_zalloc(heap, sizeof(btr_search_t))); |
|||
ut_d(info->magic_n = BTR_SEARCH_MAGIC_N); |
|||
#ifdef BTR_CUR_HASH_ADAPT |
|||
info->n_fields = 1; |
|||
info->left_side = TRUE; |
|||
#endif /* BTR_CUR_HASH_ADAPT */ |
|||
return(info); |
|||
} |
|||
|
|||
#ifdef BTR_CUR_HASH_ADAPT |
|||
/** Updates the search info. |
|||
@param[in,out] info search info |
|||
@param[in,out] cursor cursor which was just positioned */ |
|||
void btr_search_info_update_slow(btr_search_t *info, btr_cur_t *cursor); |
|||
|
|||
/*********************************************************************//** |
|||
Updates the search info. */ |
|||
static 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 */ |
|||
{ |
|||
ut_ad(!index->is_spatial()); |
|||
ut_ad(!index->table->is_temporary()); |
|||
|
|||
if (!btr_search_enabled) { |
|||
return; |
|||
} |
|||
|
|||
btr_search_t* info; |
|||
info = btr_search_get_info(index); |
|||
|
|||
info->hash_analysis++; |
|||
|
|||
if (info->hash_analysis < BTR_SEARCH_HASH_ANALYSIS) { |
|||
|
|||
/* Do nothing */ |
|||
|
|||
return; |
|||
|
|||
} |
|||
|
|||
ut_ad(cursor->flag != BTR_CUR_HASH); |
|||
|
|||
btr_search_info_update_slow(info, cursor); |
|||
} |
|||
|
|||
/** Lock all search latches in exclusive mode. */ |
|||
static inline void btr_search_x_lock_all() |
|||
{ |
|||
for (ulint i = 0; i < btr_ahi_parts; ++i) { |
|||
btr_search_sys.parts[i].latch.wr_lock(SRW_LOCK_CALL); |
|||
} |
|||
} |
|||
|
|||
/** Unlock all search latches from exclusive mode. */ |
|||
static inline void btr_search_x_unlock_all() |
|||
{ |
|||
for (ulint i = 0; i < btr_ahi_parts; ++i) { |
|||
btr_search_sys.parts[i].latch.wr_unlock(); |
|||
} |
|||
} |
|||
|
|||
/** Lock all search latches in shared mode. */ |
|||
static inline void btr_search_s_lock_all() |
|||
{ |
|||
for (ulint i = 0; i < btr_ahi_parts; ++i) { |
|||
btr_search_sys.parts[i].latch.rd_lock(SRW_LOCK_CALL); |
|||
} |
|||
} |
|||
|
|||
/** Unlock all search latches from shared mode. */ |
|||
static inline void btr_search_s_unlock_all() |
|||
{ |
|||
for (ulint i = 0; i < btr_ahi_parts; ++i) { |
|||
btr_search_sys.parts[i].latch.rd_unlock(); |
|||
} |
|||
} |
|||
#endif /* BTR_CUR_HASH_ADAPT */ |
@ -1,60 +0,0 @@ |
|||
/***************************************************************************** |
|||
|
|||
Copyright (c) 1994, 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/ha0ha.h |
|||
The hash table interface for the adaptive hash index |
|||
|
|||
Created 8/18/1994 Heikki Tuuri |
|||
*******************************************************/ |
|||
|
|||
#ifndef ha0ha_h |
|||
#define ha0ha_h |
|||
|
|||
#include "hash0hash.h" |
|||
#include "page0types.h" |
|||
#include "buf0types.h" |
|||
#include "rem0types.h" |
|||
|
|||
#ifdef BTR_CUR_HASH_ADAPT |
|||
/*************************************************************//** |
|||
Looks for an element in a hash table. |
|||
@return pointer to the data of the first hash table node in chain |
|||
having the fold number, NULL if not found */ |
|||
UNIV_INLINE |
|||
const rec_t* |
|||
ha_search_and_get_data( |
|||
/*===================*/ |
|||
hash_table_t* table, /*!< in: hash table */ |
|||
ulint fold); /*!< in: folded value of the searched data */ |
|||
|
|||
/** The hash table external chain node */ |
|||
struct ha_node_t { |
|||
ulint fold; /*!< fold value for the data */ |
|||
ha_node_t* next; /*!< next chain node or NULL if none */ |
|||
#if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG |
|||
buf_block_t* block; /*!< buffer block containing the data, or NULL */ |
|||
#endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */ |
|||
const rec_t* data; /*!< pointer to the data */ |
|||
}; |
|||
|
|||
#include "ha0ha.inl" |
|||
#endif /* BTR_CUR_HASH_ADAPT */ |
|||
|
|||
#endif |
@ -1,154 +0,0 @@ |
|||
/***************************************************************************** |
|||
|
|||
Copyright (c) 1994, 2015, 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/ha0ha.ic |
|||
The hash table interface for the adaptive hash index |
|||
|
|||
Created 8/18/1994 Heikki Tuuri |
|||
*************************************************************************/ |
|||
|
|||
#ifdef BTR_CUR_HASH_ADAPT |
|||
#include "btr0types.h" |
|||
|
|||
/******************************************************************//** |
|||
Gets a hash node data. |
|||
@return pointer to the data */ |
|||
UNIV_INLINE |
|||
const rec_t* |
|||
ha_node_get_data( |
|||
/*=============*/ |
|||
const ha_node_t* node) /*!< in: hash chain node */ |
|||
{ |
|||
return(node->data); |
|||
} |
|||
|
|||
/******************************************************************//** |
|||
Sets hash node data. */ |
|||
UNIV_INLINE |
|||
void |
|||
ha_node_set_data_func( |
|||
/*==================*/ |
|||
ha_node_t* node, /*!< in: hash chain node */ |
|||
#if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG |
|||
buf_block_t* block, /*!< in: buffer block containing the data */ |
|||
#endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */ |
|||
const rec_t* data) /*!< in: pointer to the data */ |
|||
{ |
|||
#if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG |
|||
node->block = block; |
|||
#endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */ |
|||
node->data = data; |
|||
} |
|||
|
|||
#if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG |
|||
/** Sets hash node data. |
|||
@param n in: hash chain node |
|||
@param b in: buffer block containing the data |
|||
@param d in: pointer to the data */ |
|||
# define ha_node_set_data(n,b,d) ha_node_set_data_func(n,b,d) |
|||
#else /* UNIV_AHI_DEBUG || UNIV_DEBUG */ |
|||
/** Sets hash node data. |
|||
@param n in: hash chain node |
|||
@param b in: buffer block containing the data |
|||
@param d in: pointer to the data */ |
|||
# define ha_node_set_data(n,b,d) ha_node_set_data_func(n,d) |
|||
#endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */ |
|||
|
|||
/******************************************************************//** |
|||
Gets the next node in a hash chain. |
|||
@return next node, NULL if none */ |
|||
UNIV_INLINE |
|||
ha_node_t* |
|||
ha_chain_get_next( |
|||
/*==============*/ |
|||
const ha_node_t* node) /*!< in: hash chain node */ |
|||
{ |
|||
return(node->next); |
|||
} |
|||
|
|||
/******************************************************************//** |
|||
Gets the first node in a hash chain. |
|||
@return first node, NULL if none */ |
|||
UNIV_INLINE |
|||
ha_node_t* |
|||
ha_chain_get_first( |
|||
/*===============*/ |
|||
hash_table_t* table, /*!< in: hash table */ |
|||
ulint fold) /*!< in: fold value determining the chain */ |
|||
{ |
|||
return static_cast<ha_node_t*>(table->array[table->calc_hash(fold)].node); |
|||
} |
|||
|
|||
/*************************************************************//** |
|||
Looks for an element in a hash table. |
|||
@return pointer to the data of the first hash table node in chain |
|||
having the fold number, NULL if not found */ |
|||
UNIV_INLINE |
|||
const rec_t* |
|||
ha_search_and_get_data( |
|||
/*===================*/ |
|||
hash_table_t* table, /*!< in: hash table */ |
|||
ulint fold) /*!< in: folded value of the searched data */ |
|||
{ |
|||
ut_ad(btr_search_enabled); |
|||
|
|||
for (const ha_node_t* node = ha_chain_get_first(table, fold); |
|||
node != NULL; |
|||
node = ha_chain_get_next(node)) { |
|||
|
|||
if (node->fold == fold) { |
|||
|
|||
return(node->data); |
|||
} |
|||
} |
|||
|
|||
return(NULL); |
|||
} |
|||
|
|||
/*********************************************************//** |
|||
Looks for an element when we know the pointer to the data. |
|||
@return pointer to the hash table node, NULL if not found in the table */ |
|||
UNIV_INLINE |
|||
ha_node_t* |
|||
ha_search_with_data( |
|||
/*================*/ |
|||
hash_table_t* table, /*!< in: hash table */ |
|||
ulint fold, /*!< in: folded value of the searched data */ |
|||
const rec_t* data) /*!< in: pointer to the data */ |
|||
{ |
|||
ha_node_t* node; |
|||
|
|||
ut_ad(btr_search_enabled); |
|||
|
|||
node = ha_chain_get_first(table, fold); |
|||
|
|||
while (node) { |
|||
if (node->data == data) { |
|||
|
|||
return(node); |
|||
} |
|||
|
|||
node = ha_chain_get_next(node); |
|||
} |
|||
|
|||
return(NULL); |
|||
} |
|||
|
|||
#endif /* BTR_CUR_HASH_ADAPT */ |
Write
Preview
Loading…
Cancel
Save
Reference in new issue