/** Tries to guess the right search position based on the hash search info oftheindex.NotethatifmodeisPAGE_CUR_LE,whichisusedininserts, andthefunctionreturnsTRUE,thencursor->up_matchandcursor->low_match bothhavesensiblevalues. @param[in,out]indexindex @param[in]tuplelogicalrecord @param[in]gefalse=PAGE_CUR_LE,true=PAGE_CUR_GE @param[in]latch_modeBTR_SEARCH_LEAF,... @param[out]cursortreecursor @param[in]mtrmini-transaction
@return whether the search succeeded */ bool
btr_search_guess_on_hash(
dict_index_t* index, const dtuple_t* tuple, bool ge,
btr_latch_mode latch_mode,
btr_cur_t* cursor,
mtr_t* mtr) noexcept;
/** Move or delete hash entries for moved records, usually in a page split. Ifnew_blockisalreadyhashed,thenanyhashindexforblockisdropped. Ifnew_blockisnothashed,andblockishashed,thenanewhashindexis builttonew_blockwiththesameparametersasblock. @paramnew_blockdestinationpage @paramblocksourcepage(subjecttodeletionlater)
@param mtr mini-transaction (to update trx AHI statistics) */ void btr_search_move_or_delete_hash_entries(buf_block_t *new_block,
buf_block_t *block, const mtr_t &mtr) noexcept;
/** Drop any adaptive hash index entries that point to an index page. @paramblocklatchedblockcontainingindexpage,orabuffer-unfixed indexpageorablockinstateBUF_BLOCK_REMOVE_HASH
@param not_garbage drop only if the index is set and NOT this */ void btr_search_drop_page_hash_index(buf_block_t *block, const dict_index_t *not_garbage) noexcept;
/** Drop possible adaptive hash index entries when a page is evicted fromthebufferpoolorfreedinafile,ortheindexisbeingdropped. @parammtrmini-transaction
@param page_id page identifier of the being-dropped page */ void btr_search_drop_page_hash_when_freed(mtr_t *mtr, const page_id_t page_id)
noexcept;
/** Update the page hash index after a single record is inserted on a page. @paramcursorcursorwhichwaspositionedbeforetheinsertedrecord @paramreorgwhetherthepagewasreorganized
@param mtr mini-transaction (to update trx AHI statistics) */ void btr_search_update_hash_on_insert(btr_cur_t *cursor, bool reorg, const mtr_t &mtr) noexcept;
/** Updates the page hash index before a single record is deleted from a page.
@param cursor cursor positioned on the to-be-deleted record */ void btr_search_update_hash_on_delete(btr_cur_t *cursor) noexcept;
/** Validates the search system. @paramthdconnection,forcheckingifCHECKTABLEhasbeenkilled
@return true if ok */ bool btr_search_validate(THD *thd) noexcept;
# ifdef UNIV_DEBUG /** @return if the index is marked as freed */ bool btr_search_check_marked_free_index(const buf_block_t *block) noexcept; # endif /* UNIV_DEBUG */
struct ahi_node;
/** The possible AHI enabled values: disabled, enabled, enabled butactiveonlywhenspecificallyenabledbyindexortableoption.
Matches innodb_ahi_names from ha_innodb.cc */ enum ahi_status : ulong
{ /** Disabled */
AHI_OFF= 0, /** Enabled */
AHI_ON= 1, /** Enabled, active only where index or table option specifically
enabled AHI */
AHI_IF_SPECIFIED= 2
};
/** The hash index system */ struct btr_sea
{ /** the actual value of innodb_adaptive_hash_index, protected by allpartition::latch.Notethatifbuf_block_t::indexisnotnullptr
while a thread is holding a partition::latch, then also this must hold. */
Atomic_relaxed<ahi_status> enabled;
/** Number of successful adaptive hash index lookups */ union {
Atomic_counter<size_t> hit_count;
size_t hit_count_nonatomic;
};
/** Number of searches down the B-tree (adaptive hash index misses) */ union {
Atomic_counter<size_t> miss_count;
size_t miss_count_nonatomic;
};
/** Number of rows added to the adaptive hash index */ union {
Atomic_counter<size_t> rows_added;
size_t rows_added_nonatomic;
};
/** Number of pages added to the adaptive hash index */ union {
Atomic_counter<size_t> pages_added;
size_t pages_added_nonatomic;
};
/** Snapshots for calculating per-second rates; protected by
srv_innodb_monitor_mutex */
size_t hit_count_old;
size_t miss_count_old;
private: /** Disable the adaptive hash search system and empty the index.
@return the AHI enabled value before the operation is performed */
ATTRIBUTE_COLD ahi_status disable_and_lock() noexcept;
/** Check if AHI is enabled for an index. @paramindextheindex
@return true if AHI enabled for the index */ bool is_enabled(const dict_index_t *index) const noexcept
{ /* Index is enabled if global AHI is enabled and index can be enabled. Ifenabledissetto2(AHI_IF_SPECIFIED),onlyenableindexesdeclared withAHIenabledon(uint8_t{index->search_info.get_enabled()}==2). Wedon'thavetocheckifuint8_t{index->search_info.get_enabled()}!=0 asthetestenabled<=uint8_t{index->search_info.get_enabled()}will notbetrueinthiscase.
/** Check if AHI is enabled for an index, supposing it is enabled for anullptrindex.Thistohandlethecasewherewedonotyetknowif AHIfortheindexisenabledornot. @seebtr_sea::is_enabled(),equivalentwhenindexisnotnullptr. @paramindextheindex(canbenullptr)
@return true if AHI may be enabled for the index */ bool may_be_enabled(const dict_index_t *index) const noexcept
{ const ahi_status enabled{get_enabled()}; return (unlikely(enabled != AHI_OFF) &&
(!index || enabled <= uint8_t{index->search_info.get_enabled()}));
}
/** Disable the adaptive hash search system and empty the index.
@return the AHI enabled value before the operation is performed */
ATTRIBUTE_COLD ahi_status disable() noexcept;
/** Hash cell chain in hash_table */ struct hash_chain
{ /** pointer to the first block */
ahi_node *first;
/** Find an element. @paramuunarypredicate @returnthefirstmatchingelement
@retval nullptr if not found */ template<typename UnaryPred> inline ahi_node *find(UnaryPred u) const noexcept;
/** Search for a pointer to an element. @paramuunarypredicate @returnpointertothefirstmatchingelement,
or to the last element in the chain */ template<typename UnaryPred> inline ahi_node **search(UnaryPred u) noexcept;
};
/** Hash table with singly-linked overflow lists.
Based on @see buf_pool_t::page_hash_table */ struct hash_table
{
static_assert(CPU_LEVEL1_DCACHE_LINESIZE >= 64, "less than 64 bytes");
static_assert(!(CPU_LEVEL1_DCACHE_LINESIZE & 63), "not a multiple of 64 bytes");
/** Number of array[] elements per page_hash_latch.
Must be one less than a power of 2. */ #if0 static constexpr size_t ELEMENTS_PER_LATCH= 64 / sizeof(void*) - 1;
/** Extra padding. FIXME: Is this ever useful to be nonzero? Longtimeago,sometestingonanARMv8implementationseemed
to suggest so, but this has not been validated recently. */ static constexpr size_t EMPTY_SLOTS_PER_LATCH=
((CPU_LEVEL1_DCACHE_LINESIZE / 64) - 1) * (64 / sizeof(void*)); #else static constexpr size_t ELEMENTS_PER_LATCH=
CPU_LEVEL1_DCACHE_LINESIZE / sizeof(void*) - 1; static constexpr size_t EMPTY_SLOTS_PER_LATCH= 0; #endif
/** number of payload elements in array[] */
Atomic_relaxed<size_t> n_cells; /** the hash table, with pad(n_cells) elements, aligned to L1 cache size */
hash_chain *array;
/** Create the hash table. @paramnthelowerboundofn_cells
@return whether the creation succeeded */ inlinebool create(ulint n) noexcept;
/** @return the index of an array element */
ulint calc_hash(ulint fold) const noexcept
{ return calc_hash(fold, n_cells); } /** @return raw array index converted to padded index */ static ulint pad(ulint h) noexcept
{
ulint latches= h / ELEMENTS_PER_LATCH;
ulint empty_slots= latches * EMPTY_SLOTS_PER_LATCH; return1 + latches + empty_slots + h;
} private: /** @return the index of an array element */ static ulint calc_hash(ulint fold, ulint n_cells) noexcept
{ return pad(fold % n_cells);
} public: /** @return the latch covering a hash table chain */ static page_hash_latch &lock_get(hash_chain &chain) noexcept
{
static_assert(!((ELEMENTS_PER_LATCH + 1) & ELEMENTS_PER_LATCH), "must be one less than a power of 2"); const size_t addr= reinterpret_cast<size_t>(&chain);
ut_ad(addr & (ELEMENTS_PER_LATCH * sizeof chain)); return *reinterpret_cast<page_hash_latch*>
(addr & ~(ELEMENTS_PER_LATCH * sizeof chain));
}
/** Get a hash table slot. */
hash_chain &cell_get(ulint fold) const
{ return array[calc_hash(fold, n_cells)]; }
};
/** Partition of the hash table */ struct partition
{ /** latch protecting table: either an exclusive latch, or
a shared latch combined with lock_get() */
alignas(CPU_LEVEL1_DCACHE_LINESIZE)
IF_DBUG(srw_lock_debug,srw_spin_lock) latch; /** map of CRC-32C of rec prefix to rec_t* in buf_page_t::frame */
hash_table table; /** protects blocks; acquired while holding latch
and possibly table.lock_get() */
srw_mutex blocks_mutex; /** allocated blocks */
UT_LIST_BASE_NODE_T(buf_page_t) blocks; /** a cached block to extend blocks */
Atomic_relaxed<buf_block_t*> spare;
/** @return the number of allocated buffer pool blocks */
TPOOL_SUPPRESS_TSAN size_t get_blocks() const noexcept
{ return UT_LIST_GET_LEN(blocks) + !!spare; }
/** Ensure that there is a spare block for a future insert() */ void prepare_insert() noexcept;
/** Undo prepare_insert() in case !btr_search.enabled */ void rollback_insert() noexcept;
private: /** Start cleanup_after_erase()
@return the last allocated element */ inline ahi_node *cleanup_after_erase_start() noexcept; /** Finish cleanup_after_erase(). WereducetheallocatedsizeinUT_LIST_GET_LAST(blocks)->free_offset. Ifthatsizereaches0,thelastblockwillberemovedfromblocks, andablockmayhavetobefreedbyourcaller. @returnbufferblocktobefreed
@retval nullptr if no buffer block was freed */
buf_block_t *cleanup_after_erase_finish() noexcept; public:
__attribute__((nonnull)) /** Clean up after erasing an AHI node, while the caller is holdinganexclusivelatch.Unless"erase"isthelastallocated element,wewillswapitwiththelastallocatedelement. Finally,wereturnviacleanup_after_erase_finish(). @paramerasenodebeingerased @returnbufferblocktobefreed
@retval nullptr if no buffer block was freed */
buf_block_t *cleanup_after_erase(ahi_node *erase) noexcept;
__attribute__((nonnull)) /** Clean up after erasing an AHI node. This is similar to cleanup_after_erase(ahi_node*),exceptthattheoperationmayfail. @paramerasenodebeingerased @paramlthelatchheldtogetherwithsharedlatch @returnbufferblocktobefreed @retvalnullptrifnobufferblockwasfreed @retval-1ifwefailtoshrinktheallocationanderasing
needs to be retried while holding an exclusive latch */
buf_block_t *cleanup_after_erase(ahi_node *erase, page_hash_latch *l)
noexcept;
__attribute__((nonnull)) # ifdefined UNIV_AHI_DEBUG || defined UNIV_DEBUG /** Insert or replace an entry into the hash table. @paramfoldCRC-32Cofrecprefix @paramrecB-treeleafpagerecord
@param block the buffer block that contains rec */ void insert(uint32_t fold, const rec_t *rec, buf_block_t *block) noexcept; # else /** Insert or replace an entry into the hash table. @paramfoldCRC-32Cofrecprefix
@param rec B-tree leaf page record */ void insert(uint32_t fold, const rec_t *rec) noexcept; # endif
/** erase() return value */ enum erase_status{ /** must retry with exclusive latch */
ERASE_RETRY= -1, /** the pointer to the record was erased */
ERASED= 0, /** nothing was erased */
NOT_ERASED= 1
};
/** Delete a pointer to a record if it exists, and release the latch. @tparamextrue=holdingexclusivelatch,false=sharedlatch @paramcellhashtablecellthatmaycontaintheCRC-32Cofrecprefix @paramrecB-treeleafpagerecord
@return status */ template<bool ex>
erase_status erase(hash_chain &cell, const rec_t *rec) noexcept;
};
/** number of hash table entries, to be multiplied by n_parts */
uint n_cells; /** innodb_adaptive_hash_index_parts */
uint n_parts; /** Partitions of the adaptive hash index */
partition parts[512];
/** Get an adaptive hash index partition */
partition &get_part(index_id_t id) noexcept { return parts[id % n_parts]; }
/** Get an adaptive hash index partition */
partition &get_part(const dict_index_t &index) noexcept
{ return get_part(index.id); }
/** Create and initialize at startup */ void create() noexcept;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.