diff --git a/extra/mariabackup/xtrabackup.cc b/extra/mariabackup/xtrabackup.cc index 87018b8b5e41b..65529ef2d1cc7 100644 --- a/extra/mariabackup/xtrabackup.cc +++ b/extra/mariabackup/xtrabackup.cc @@ -2643,24 +2643,24 @@ my_bool regex_list_check_match( } static -my_bool +bool find_filter_in_hashtable( const char* name, hash_table_t* table, xb_filter_entry_t** result ) { - xb_filter_entry_t* found = NULL; - const ulint fold = my_crc32c(0, name, strlen(name)); - HASH_SEARCH(name_hash, table, fold, - xb_filter_entry_t*, - found, (void) 0, - !strcmp(found->name, name)); - - if (found && result) { - *result = found; - } - return (found != NULL); + const ulint fold= my_crc32c(0, name, strlen(name)); + for (xb_filter_entry_t *found= static_cast + (table->cell_get(fold)->node); + found; found= found->name_hash) + if (!strcmp(found->name, name)) + { + if (result) + *result= found; + return true; + } + return false; } /************************************************************************ @@ -4143,14 +4143,13 @@ xb_add_filter( const char* name, /*!< in: name of table/database */ hash_table_t* hash) /*!< in/out: hash to insert into */ { - xb_filter_entry_t* entry = xb_new_filter_entry(name); + xb_filter_entry_t *entry= xb_new_filter_entry(name); - if (UNIV_UNLIKELY(!hash->array)) { - hash->create(1000); - } - const ulint fold = my_crc32c(0, entry->name, strlen(entry->name)); - HASH_INSERT(xb_filter_entry_t, name_hash, hash, fold, entry); - return entry; + if (UNIV_UNLIKELY(!hash->array)) + hash->create(1000); + hash->cell_get(my_crc32c(0, entry->name, strlen(entry->name)))-> + append(*entry, &xb_filter_entry_t::name_hash); + return entry; } /*********************************************************************** @@ -4204,11 +4203,13 @@ xb_register_filter_entry( if (databases_hash && databases_hash->array) { const ulint fold = my_crc32c(0, dbname, p - name); - HASH_SEARCH(name_hash, databases_hash, - fold, - xb_filter_entry_t*, - db_entry, (void) 0, - !strcmp(db_entry->name, dbname)); + db_entry = static_cast( + databases_hash->cell_get(fold)->node); + for (; db_entry; db_entry = db_entry->name_hash) { + if (!strcmp(db_entry->name, dbname)) { + break; + } + } } if (!db_entry) { db_entry = xb_add_filter(dbname, databases_hash); @@ -4396,33 +4397,17 @@ xb_filters_init() } } -static -void -xb_filter_hash_free(hash_table_t* hash) +static void xb_filter_hash_free(hash_table_t* hash) { - ulint i; - - /* free the hash elements */ - for (i = 0; i < hash->n_cells; i++) { - xb_filter_entry_t* table; - - table = static_cast - (HASH_GET_FIRST(hash, i)); - - while (table) { - xb_filter_entry_t* prev_table = table; - - table = static_cast - (HASH_GET_NEXT(name_hash, prev_table)); - const ulint fold = my_crc32c(0, prev_table->name, - strlen(prev_table->name)); - HASH_DELETE(xb_filter_entry_t, name_hash, hash, - fold, prev_table); - free(prev_table); - } - } - - hash->free(); + for (ulint i= 0; i < hash->n_cells; i++) + for (auto prev= static_cast(hash->array[i].node); + prev; ) + { + auto next= prev->name_hash; + free(prev); + prev= next; + } + hash->free(); } static void xb_regex_list_free(regex_list_t* list) @@ -5331,8 +5316,8 @@ xb_delta_open_matching_space( table->name = ((char*)table) + sizeof(xb_filter_entry_t); memcpy(table->name, dest_space_name, len + 1); const ulint fold = my_crc32c(0, dest_space_name, len); - HASH_INSERT(xb_filter_entry_t, name_hash, &inc_dir_tables_hash, - fold, table); + inc_dir_tables_hash.cell_get(fold)->append( + *table, &xb_filter_entry_t::name_hash); mysql_mutex_lock(&fil_system.mutex); fil_space = fil_space_get_by_name(dest_space_name); @@ -5752,8 +5737,8 @@ static ibool prepare_handle_new_files(const char *data_home_dir, strcpy(table->name, table_name.c_str()); const ulint fold = my_crc32c(0, table->name, table_name.size()); - HASH_INSERT(xb_filter_entry_t, name_hash, &inc_dir_tables_hash, - fold, table); + inc_dir_tables_hash.cell_get(fold)->append( + *table, &xb_filter_entry_t::name_hash); } return TRUE; @@ -5769,29 +5754,15 @@ rm_if_not_found( const char* data_home_dir, /*!name, name)); - - if (!table) { - snprintf(name, FN_REFLEN, "%s/%s/%s", data_home_dir, - db_name, file_name); - return os_file_delete(0, name); - } - - return(TRUE); + char name[FN_REFLEN]; + /* Truncate ".ibd" */ + name[snprintf(name, FN_REFLEN, "%s/%s", db_name, file_name) - 4]= '\0'; + if (find_filter_in_hashtable(name, &inc_dir_tables_hash, nullptr)) + return true; + snprintf(name, FN_REFLEN, "%s/%s/%s", data_home_dir, db_name, file_name); + return os_file_delete(0, name); } /** Function enumerates files in datadir (provided by path) which are matched diff --git a/storage/innobase/btr/btr0sea.cc b/storage/innobase/btr/btr0sea.cc index 5d99e24273b41..7b685a0e8a35a 100644 --- a/storage/innobase/btr/btr0sea.cc +++ b/storage/innobase/btr/btr0sea.cc @@ -543,9 +543,7 @@ static void ha_delete_hash_node(hash_table_t *table, mem_heap_t *heap, ut_a(del_node->block->n_pointers-- < MAX_N_POINTERS); #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */ - const ulint fold= del_node->fold; - - HASH_DELETE(ha_node_t, next, table, fold, del_node); + table->cell_get(del_node->fold)->remove(*del_node, &ha_node_t::next); ha_node_t *top= static_cast(mem_heap_get_top(heap, sizeof *top)); @@ -564,8 +562,7 @@ static void ha_delete_hash_node(hash_table_t *table, mem_heap_t *heap, /* We have to look for the predecessor */ ha_node_t *node= static_cast(cell->node); - while (top != HASH_GET_NEXT(next, node)) - node= static_cast(HASH_GET_NEXT(next, node)); + while (top != node->next) node= node->next; /* Now we have the predecessor node */ node->next= del_node; diff --git a/storage/innobase/buf/buf0buddy.cc b/storage/innobase/buf/buf0buddy.cc index 85a698bc875b5..44f49a6e415ef 100644 --- a/storage/innobase/buf/buf0buddy.cc +++ b/storage/innobase/buf/buf0buddy.cc @@ -341,58 +341,52 @@ static buf_buddy_free_t* buf_buddy_alloc_zip(ulint i) } /** Deallocate a buffer frame of srv_page_size. -@param[in] buf buffer frame to deallocate */ -static -void -buf_buddy_block_free(void* buf) +@param buf buffer frame to deallocate */ +static void buf_buddy_block_free(void *buf) noexcept { - const ulint fold = BUF_POOL_ZIP_FOLD_PTR(buf); - buf_page_t* bpage; - buf_block_t* block; - - mysql_mutex_assert_owner(&buf_pool.mutex); - ut_a(!ut_align_offset(buf, srv_page_size)); - - HASH_SEARCH(hash, &buf_pool.zip_hash, fold, buf_page_t*, bpage, - ut_ad(bpage->state() == buf_page_t::MEMORY - && bpage->in_zip_hash), - bpage->frame == buf); - ut_a(bpage); - ut_a(bpage->state() == buf_page_t::MEMORY); - ut_ad(bpage->in_zip_hash); - ut_d(bpage->in_zip_hash = false); - HASH_DELETE(buf_page_t, hash, &buf_pool.zip_hash, fold, bpage); - bpage->hash = nullptr; - - ut_d(memset(buf, 0, srv_page_size)); - MEM_UNDEFINED(buf, srv_page_size); - - block = (buf_block_t*) bpage; - buf_LRU_block_free_non_file_page(block); - - ut_ad(buf_pool.buddy_n_frames > 0); - ut_d(buf_pool.buddy_n_frames--); + mysql_mutex_assert_owner(&buf_pool.mutex); + ut_a(!ut_align_offset(buf, srv_page_size)); + + const ulint fold= BUF_POOL_ZIP_FOLD_PTR(buf); + buf_page_t **prev; + for (prev= reinterpret_cast + (&buf_pool.zip_hash.cell_get(fold)->node); *prev; prev= &(*prev)->hash) + { + ut_ad((*prev)->in_zip_hash); + ut_ad((*prev)->state() == buf_page_t::MEMORY); + if ((*prev)->frame == buf) + goto found; + } + + ut_error; +found: + ut_d((*prev)->in_zip_hash= false); + buf_page_t *bpage= *prev; + *prev= bpage->hash; + bpage->hash= nullptr; + + ut_d(memset(buf, 0, srv_page_size)); + MEM_UNDEFINED(buf, srv_page_size); + + buf_LRU_block_free_non_file_page(reinterpret_cast(bpage)); + ut_ad(buf_pool.buddy_n_frames > 0); + ut_d(buf_pool.buddy_n_frames--); } -/**********************************************************************//** -Allocate a buffer block to the buddy allocator. */ -static -void -buf_buddy_block_register( -/*=====================*/ - buf_block_t* block) /*!< in: buffer frame to allocate */ +/** Allocate a buffer block to the buddy allocator. +@param block buffer block to register */ +static void buf_buddy_block_register(buf_block_t *block) noexcept { - const ulint fold = BUF_POOL_ZIP_FOLD(block); - ut_ad(block->page.state() == buf_page_t::MEMORY); - - ut_a(block->page.frame); - ut_a(!ut_align_offset(block->page.frame, srv_page_size)); + const ulint fold= BUF_POOL_ZIP_FOLD(block); + ut_ad(block->page.state() == buf_page_t::MEMORY); - ut_ad(!block->page.in_zip_hash); - ut_d(block->page.in_zip_hash = true); - HASH_INSERT(buf_page_t, hash, &buf_pool.zip_hash, fold, &block->page); + ut_a(block->page.frame); + ut_a(!ut_align_offset(block->page.frame, srv_page_size)); - ut_d(buf_pool.buddy_n_frames++); + ut_ad(!block->page.in_zip_hash); + ut_d(block->page.in_zip_hash= true); + buf_pool.zip_hash.cell_get(fold)->append(block->page, &buf_page_t::hash); + ut_d(buf_pool.buddy_n_frames++); } /** Allocate a block from a bigger object. diff --git a/storage/innobase/dict/dict0crea.cc b/storage/innobase/dict/dict0crea.cc index fb08694053c08..0572bab004f38 100644 --- a/storage/innobase/dict/dict0crea.cc +++ b/storage/innobase/dict/dict0crea.cc @@ -1309,7 +1309,7 @@ dict_create_index_step( return(thr); } -bool dict_sys_t::load_sys_tables() +bool dict_sys_t::load_sys_tables() noexcept { ut_ad(!srv_any_background_activity()); bool mismatch= false; @@ -1352,7 +1352,7 @@ bool dict_sys_t::load_sys_tables() return mismatch; } -dberr_t dict_sys_t::create_or_check_sys_tables() +dberr_t dict_sys_t::create_or_check_sys_tables() noexcept { if (sys_tables_exist()) return DB_SUCCESS; diff --git a/storage/innobase/dict/dict0dict.cc b/storage/innobase/dict/dict0dict.cc index 9d9a6765bd0f8..c1d73d64bce49 100644 --- a/storage/innobase/dict/dict0dict.cc +++ b/storage/innobase/dict/dict0dict.cc @@ -639,6 +639,53 @@ template bool dict_table_t::parse_name<>(char(&)[NAME_LEN + 1], char(&)[NAME_LEN + 1], size_t*, size_t*) const; +dict_table_t *dict_sys_t::acquire_temporary_table(table_id_t id) const noexcept +{ + ut_ad(frozen()); + ut_ad(id >= DICT_HDR_FIRST_ID); + for (dict_table_t *t= static_cast(temp_id_hash.cell_get + (ut_fold_ull(id))->node); t; + t= t->id_hash) + { + ut_ad(t->is_temporary()); + ut_ad(t->cached); + if (t->id == id) + { + t->acquire(); + return t; + } + } + return nullptr; +} + +dict_table_t *dict_sys_t::find_table(table_id_t id) const noexcept +{ + ut_ad(frozen()); + for (dict_table_t *t= static_cast(table_id_hash.cell_get + (ut_fold_ull(id))->node); t; + t= t->id_hash) + { + ut_ad(!t->is_temporary()); + ut_ad(t->cached); + if (t->id == id) + return t; + } + return nullptr; +} + +dict_table_t *dict_sys_t::find_table(const span &name) + const noexcept +{ + ut_ad(frozen()); + for (dict_table_t *table= static_cast + (table_hash.cell_get(my_crc32c(0, name.data(), name.size()))->node); + table; table= table->name_hash) + if (strlen(table->name.m_name) == name.size() && + !memcmp(table->name.m_name, name.data(), name.size())) + return table; + return nullptr; +} + /** Acquire MDL shared for the table name. @tparam trylock whether to use non-blocking operation @param[in,out] table table object @@ -927,7 +974,7 @@ dict_table_col_in_clustered_key( } /** Initialise the data dictionary cache. */ -void dict_sys_t::create() +void dict_sys_t::create() noexcept { ut_ad(this == &dict_sys); ut_ad(!is_initialised()); @@ -1113,59 +1160,34 @@ void dict_table_t::add_to_cache() } /** Add a table definition to the data dictionary cache */ -inline void dict_sys_t::add(dict_table_t* table) +inline void dict_sys_t::add(dict_table_t *table) noexcept { - ut_ad(!find(table)); - - ulint fold = my_crc32c(0, table->name.m_name, - strlen(table->name.m_name)); - - table->autoinc_mutex.init(); - table->lock_mutex_init(); - - /* Look for a table with the same name: error if such exists */ - { - dict_table_t* table2; - HASH_SEARCH(name_hash, &table_hash, fold, - dict_table_t*, table2, ut_ad(table2->cached), - !strcmp(table2->name.m_name, table->name.m_name)); - ut_a(table2 == NULL); - -#ifdef UNIV_DEBUG - /* Look for the same table pointer with a different name */ - HASH_SEARCH_ALL(name_hash, &table_hash, - dict_table_t*, table2, ut_ad(table2->cached), - table2 == table); - ut_ad(table2 == NULL); -#endif /* UNIV_DEBUG */ - } - HASH_INSERT(dict_table_t, name_hash, &table_hash, fold, table); - - /* Look for a table with the same id: error if such exists */ - hash_table_t* id_hash = table->is_temporary() - ? &temp_id_hash : &table_id_hash; - const ulint id_fold = ut_fold_ull(table->id); - { - dict_table_t* table2; - HASH_SEARCH(id_hash, id_hash, id_fold, - dict_table_t*, table2, ut_ad(table2->cached), - table2->id == table->id); - ut_a(table2 == NULL); - -#ifdef UNIV_DEBUG - /* Look for the same table pointer with a different id */ - HASH_SEARCH_ALL(id_hash, id_hash, - dict_table_t*, table2, ut_ad(table2->cached), - table2 == table); - ut_ad(table2 == NULL); -#endif /* UNIV_DEBUG */ - - HASH_INSERT(dict_table_t, id_hash, id_hash, id_fold, table); - } + ut_ad(!table->name_hash); + ut_ad(!table->id_hash); + table->autoinc_mutex.init(); + table->lock_mutex_init(); + dict_table_t **after; + after= reinterpret_cast + (&table_hash.cell_get(my_crc32c(0, table->name.m_name, + strlen(table->name.m_name)))->node); + for (; *after; after = &(*after)->name_hash) + { + ut_ad((*after)->cached); + ut_a(strcmp((*after)->name.m_name, table->name.m_name)); + } + *after= table; - UT_LIST_ADD_FIRST(table->can_be_evicted ? table_LRU : table_non_LRU, - table); - ut_ad(dict_lru_validate()); + after= reinterpret_cast + (&(table->is_temporary() ? temp_id_hash : table_id_hash). + cell_get(ut_fold_ull(table->id))->node); + for (; *after; after = &(*after)->id_hash) + { + ut_ad((*after)->cached); + ut_a((*after)->id != table->id); + } + *after= table; + UT_LIST_ADD_FIRST(table->can_be_evicted ? table_LRU : table_non_LRU, table); + ut_ad(dict_lru_validate()); } /** Test whether a table can be evicted from dict_sys.table_LRU. @@ -1277,7 +1299,7 @@ dict_index_t *dict_index_t::clone_if_needed() /** Evict unused, unlocked tables from table_LRU. @param half whether to consider half the tables only (instead of all) @return number of tables evicted */ -ulint dict_sys_t::evict_table_LRU(bool half) +ulint dict_sys_t::evict_table_LRU(bool half) noexcept { #ifdef MYSQL_DYNAMIC_PLUGIN constexpr ulint max_tables = 400; @@ -1475,9 +1497,6 @@ dict_table_rename_in_cache( ut_a(old_name_len < sizeof old_name); strcpy(old_name, table->name.m_name); - const uint32_t fold= my_crc32c(0, new_name.data(), new_name.size()); - ut_a(!dict_sys.find_table(new_name)); - if (!dict_table_is_file_per_table(table)) { } else if (dberr_t err = table->rename_tablespace(new_name, replace_new_file)) { @@ -1485,10 +1504,11 @@ dict_table_rename_in_cache( } /* Remove table from the hash tables of tables */ - HASH_DELETE(dict_table_t, name_hash, &dict_sys.table_hash, - my_crc32c(0, table->name.m_name, old_name_len), table); + dict_sys.table_hash.cell_get(my_crc32c(0, table->name.m_name, + old_name_len)) + ->remove(*table, &dict_table_t::name_hash); - bool keep_mdl_name = !table->name.is_temporary(); + bool keep_mdl_name = !table->name.is_temporary(); if (!keep_mdl_name) { } else if (const char* s = static_cast @@ -1521,8 +1541,16 @@ dict_table_rename_in_cache( } /* Add table to hash table of tables */ - HASH_INSERT(dict_table_t, name_hash, &dict_sys.table_hash, fold, - table); + ut_ad(!table->name_hash); + dict_table_t** after = reinterpret_cast( + &dict_sys.table_hash.cell_get(my_crc32c(0, new_name.data(), + new_name.size())) + ->node); + for (; *after; after = &(*after)->name_hash) { + ut_ad((*after)->cached); + ut_a(strcmp((*after)->name.m_name, new_name.data())); + } + *after = table; if (table->name.is_temporary()) { /* In ALTER TABLE we think of the rename table operation @@ -1774,35 +1802,11 @@ dict_table_rename_in_cache( return(DB_SUCCESS); } -/**********************************************************************//** -Change the id of a table object in the dictionary cache. This is used in -DISCARD TABLESPACE. */ -void -dict_table_change_id_in_cache( -/*==========================*/ - dict_table_t* table, /*!< in/out: table object already in cache */ - table_id_t new_id) /*!< in: new id to set */ -{ - ut_ad(dict_sys.locked()); - ut_ad(table->magic_n == DICT_TABLE_MAGIC_N); - ut_ad(!table->is_temporary()); - - /* Remove the table from the hash table of id's */ - - HASH_DELETE(dict_table_t, id_hash, &dict_sys.table_id_hash, - ut_fold_ull(table->id), table); - table->id = new_id; - - /* Add the table back to the hash table */ - HASH_INSERT(dict_table_t, id_hash, &dict_sys.table_id_hash, - ut_fold_ull(table->id), table); -} - /** Evict a table definition from the InnoDB data dictionary cache. @param[in,out] table cached table definition to be evicted @param[in] lru whether this is part of least-recently-used eviction @param[in] keep whether to keep (not free) the object */ -void dict_sys_t::remove(dict_table_t* table, bool lru, bool keep) +void dict_sys_t::remove(dict_table_t* table, bool lru, bool keep) noexcept { dict_foreign_t* foreign; dict_index_t* index; @@ -1838,16 +1842,12 @@ void dict_sys_t::remove(dict_table_t* table, bool lru, bool keep) } /* Remove table from the hash tables of tables */ - - HASH_DELETE(dict_table_t, name_hash, &table_hash, - my_crc32c(0, table->name.m_name, - strlen(table->name.m_name)), - table); - - hash_table_t* id_hash = table->is_temporary() - ? &temp_id_hash : &table_id_hash; - const ulint id_fold = ut_fold_ull(table->id); - HASH_DELETE(dict_table_t, id_hash, id_hash, id_fold, table); + table_hash.cell_get(my_crc32c(0, table->name.m_name, + strlen(table->name.m_name))) + ->remove(*table, &dict_table_t::name_hash); + (table->is_temporary() ? temp_id_hash : table_id_hash) + .cell_get(ut_fold_ull(table->id)) + ->remove(*table, &dict_table_t::id_hash); /* Remove table from LRU or non-LRU list. */ if (table->can_be_evicted) { @@ -4450,8 +4450,21 @@ dict_fs2utf8( } } +/** Insert a table into the hash tables +@param table the table +@param id_hash dict_sys.table_id_hash or dict_sys.temp_id_hash */ +static void hash_insert(dict_table_t *table, hash_table_t& id_hash) noexcept +{ + ut_ad(table->cached); + dict_sys.table_hash.cell_get(my_crc32c(0, table->name.m_name, + strlen(table->name.m_name)))-> + append(*table, &dict_table_t::name_hash); + id_hash.cell_get(ut_fold_ull(table->id))->append(*table, + &dict_table_t::id_hash); +} + /** Resize the hash tables based on the current buffer pool size. */ -void dict_sys_t::resize() +void dict_sys_t::resize() noexcept { ut_ad(this == &dict_sys); ut_ad(is_initialised()); @@ -4472,32 +4485,18 @@ void dict_sys_t::resize() table= UT_LIST_GET_NEXT(table_LRU, table)) { ut_ad(!table->is_temporary()); - ulint fold= my_crc32c(0, table->name.m_name, strlen(table->name.m_name)); - ulint id_fold= ut_fold_ull(table->id); - - HASH_INSERT(dict_table_t, name_hash, &table_hash, fold, table); - HASH_INSERT(dict_table_t, id_hash, &table_id_hash, id_fold, table); + hash_insert(table, table_id_hash); } for (dict_table_t *table = UT_LIST_GET_FIRST(table_non_LRU); table; table= UT_LIST_GET_NEXT(table_LRU, table)) - { - ulint fold= my_crc32c(0, table->name.m_name, strlen(table->name.m_name)); - ulint id_fold= ut_fold_ull(table->id); - - HASH_INSERT(dict_table_t, name_hash, &table_hash, fold, table); - - hash_table_t *id_hash= table->is_temporary() - ? &temp_id_hash : &table_id_hash; - - HASH_INSERT(dict_table_t, id_hash, id_hash, id_fold, table); - } + hash_insert(table, table->is_temporary() ? temp_id_hash : table_id_hash); unlock(); } /** Close the data dictionary cache on shutdown. */ -void dict_sys_t::close() +void dict_sys_t::close() noexcept { ut_ad(this == &dict_sys); if (!is_initialised()) return; @@ -4507,8 +4506,7 @@ void dict_sys_t::close() /* Free the hash elements. We don't remove them from table_hash because we are invoking table_hash.free() below. */ for (ulint i= table_hash.n_cells; i--; ) - while (dict_table_t *table= static_cast - (HASH_GET_FIRST(&table_hash, i))) + while (auto table= static_cast(table_hash.array[i].node)) dict_sys.remove(table); table_hash.free(); diff --git a/storage/innobase/dict/dict0load.cc b/storage/innobase/dict/dict0load.cc index 8d4c07740027e..26c46c2e00cef 100644 --- a/storage/innobase/dict/dict0load.cc +++ b/storage/innobase/dict/dict0load.cc @@ -2559,7 +2559,7 @@ static dict_table_t *dict_load_table_one(const span &name, } dict_table_t *dict_sys_t::load_table(const span &name, - dict_err_ignore_t ignore) + dict_err_ignore_t ignore) noexcept { if (dict_table_t *table= find_table(name)) return table; diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc index 65fe32553098e..fbceef640b36c 100644 --- a/storage/innobase/fil/fil0fil.cc +++ b/storage/innobase/fil/fil0fil.cc @@ -227,24 +227,15 @@ fil_validate_skip(void) } #endif /* UNIV_DEBUG */ -/*******************************************************************//** -Returns the table space by a given id, NULL if not found. -It is unsafe to dereference the returned pointer. It is fine to check -for NULL. */ -fil_space_t* -fil_space_get_by_id( -/*================*/ - ulint id) /*!< in: space id */ +fil_space_t *fil_space_get_by_id(ulint id) noexcept { - fil_space_t* space; - - ut_ad(fil_system.is_initialised()); - mysql_mutex_assert_owner(&fil_system.mutex); - - HASH_SEARCH(hash, &fil_system.spaces, id, - fil_space_t*, space,, space->id == id); - - return(space); + ut_ad(fil_system.is_initialised()); + mysql_mutex_assert_owner(&fil_system.mutex); + for (fil_space_t *space= static_cast + (fil_system.spaces.cell_get(id)->node); space; space= space->hash) + if (space->id == id) + return space; + return nullptr; } /** Look up a tablespace. @@ -810,7 +801,7 @@ inline pfs_os_file_t fil_node_t::close_to_free(bool detach_handle) pfs_os_file_t fil_system_t::detach(fil_space_t *space, bool detach_handle) { mysql_mutex_assert_owner(&fil_system.mutex); - HASH_DELETE(fil_space_t, hash, &spaces, space->id, space); + spaces.cell_get(space->id)->remove(*space, &fil_space_t::hash); if (space->is_in_unflushed_spaces) { @@ -979,9 +970,15 @@ fil_space_t *fil_space_t::create(ulint id, ulint flags, DBUG_EXECUTE_IF("fil_space_create_failure", return(NULL);); + fil_space_t** after = reinterpret_cast( + &fil_system.spaces.cell_get(id)->node); + for (; *after; after = &(*after)->hash) { + ut_a((*after)->id != id); + } + /* FIXME: if calloc() is defined as an inline function that calls memset() or bzero(), then GCC 6 -flifetime-dse can optimize it away */ - space= new (ut_zalloc_nokey(sizeof(*space))) fil_space_t; + *after = space = new (ut_zalloc_nokey(sizeof(*space))) fil_space_t; space->id = id; @@ -1005,20 +1002,6 @@ fil_space_t *fil_space_t::create(ulint id, ulint flags, space->latch.SRW_LOCK_INIT(fil_space_latch_key); - if (const fil_space_t *old_space = fil_space_get_by_id(id)) { - ib::error() << "Trying to add tablespace with id " << id - << " to the cache, but tablespace '" - << (old_space->chain.start - ? old_space->chain.start->name - : "") - << "' already exists in the cache!"; - space->~fil_space_t(); - ut_free(space); - return(NULL); - } - - HASH_INSERT(fil_space_t, hash, &fil_system.spaces, id, space); - if (opened) fil_system.add_opened_last_to_space_list(space); else diff --git a/storage/innobase/ha/ha0storage.cc b/storage/innobase/ha/ha0storage.cc index acde71b0557fc..4a99d5f6e69a3 100644 --- a/storage/innobase/ha/ha0storage.cc +++ b/storage/innobase/ha/ha0storage.cc @@ -29,46 +29,6 @@ Created September 22, 2007 Vasil Dimov #include "ha0storage.h" #include "hash0hash.h" #include "mem0mem.h" -#include "ut0rnd.h" - -/*******************************************************************//** -Retrieves a data from a storage. If it is present, a pointer to the -stored copy of data is returned, otherwise NULL is returned. */ -static -const void* -ha_storage_get( -/*===========*/ - ha_storage_t* storage, /*!< in: hash storage */ - const void* data, /*!< in: data to check for */ - ulint data_len) /*!< in: data length */ -{ - ha_storage_node_t* node; - ulint fold; - - /* avoid repetitive calls to ut_fold_binary() in the HASH_SEARCH - macro */ - fold = ut_fold_binary(static_cast(data), data_len); - -#define IS_FOUND \ - node->data_len == data_len && memcmp(node->data, data, data_len) == 0 - - HASH_SEARCH( - next, /* node->"next" */ - &storage->hash, /* the hash table */ - fold, /* key */ - ha_storage_node_t*, /* type of node->next */ - node, /* auxiliary variable */ - , /* assertion */ - IS_FOUND); /* search criteria */ - - if (node == NULL) { - - return(NULL); - } - /* else */ - - return(node->data); -} /*******************************************************************//** Copies data into the storage and returns a pointer to the copy. If the @@ -87,54 +47,29 @@ ha_storage_put_memlim( ulint data_len, /*!< in: data length */ ulint memlim) /*!< in: memory limit to obey */ { - void* raw; - ha_storage_node_t* node; - const void* data_copy; - ulint fold; - - /* check if data chunk is already present */ - data_copy = ha_storage_get(storage, data, data_len); - if (data_copy != NULL) { - - return(data_copy); - } - - /* not present */ - - /* check if we are allowed to allocate data_len bytes */ - if (memlim > 0 - && ha_storage_get_size(storage) + data_len > memlim) { - - return(NULL); - } - - /* we put the auxiliary node struct and the data itself in one - continuous block */ - raw = mem_heap_alloc(storage->heap, - sizeof(ha_storage_node_t) + data_len); - - node = (ha_storage_node_t*) raw; - data_copy = (byte*) raw + sizeof(*node); - - memcpy((byte*) raw + sizeof(*node), data, data_len); - - node->data_len = data_len; - node->data = data_copy; - - /* avoid repetitive calls to ut_fold_binary() in the HASH_INSERT - macro */ - fold = ut_fold_binary(static_cast(data), data_len); - - HASH_INSERT( - ha_storage_node_t, /* type used in the hash chain */ - next, /* node->"next" */ - &storage->hash, /* the hash table */ - fold, /* key */ - node); /* add this data to the hash */ - - /* the output should not be changed because it will spoil the - hash table */ - return(data_copy); + const uint32_t fold= my_crc32c(0, data, data_len); + ha_storage_node_t** after = reinterpret_cast + (&storage->hash.cell_get(fold)->node); + for (; *after; after= &(*after)->next) + if ((*after)->data_len == data_len && + !memcmp((*after)->data, data, data_len)) + return (*after)->data; + + /* not present */ + + /* check if we are allowed to allocate data_len bytes */ + if (memlim > 0 && ha_storage_get_size(storage) + data_len > memlim) + return nullptr; + + /* we put the auxiliary node struct and the data itself in one + continuous block */ + ha_storage_node_t *node= static_cast + (mem_heap_alloc(storage->heap, sizeof *node + data_len)); + node->data_len= data_len; + node->data= &node[1]; + memcpy(const_cast(node->data), data, data_len); + *after= node; + return node->data; } #ifdef UNIV_COMPILE_TEST_FUNCS diff --git a/storage/innobase/include/dict0boot.h b/storage/innobase/include/dict0boot.h index 3e14e0ace6963..e075e29e8206b 100644 --- a/storage/innobase/include/dict0boot.h +++ b/storage/innobase/include/dict0boot.h @@ -47,7 +47,7 @@ dict_hdr_get_new_id( /** Update dict_sys.row_id in the dictionary header file page. */ void dict_hdr_flush_row_id(row_id_t id); /** @return A new value for GEN_CLUST_INDEX(DB_ROW_ID) */ -inline row_id_t dict_sys_t::get_new_row_id() +inline row_id_t dict_sys_t::get_new_row_id() noexcept { row_id_t id= row_id.fetch_add(1); if (!(id % ROW_ID_WRITE_MARGIN)) @@ -56,7 +56,7 @@ inline row_id_t dict_sys_t::get_new_row_id() } /** Ensure that row_id is not smaller than id, on IMPORT TABLESPACE */ -inline void dict_sys_t::update_row_id(row_id_t id) +inline void dict_sys_t::update_row_id(row_id_t id) noexcept { row_id_t sys_id= row_id; while (id >= sys_id) diff --git a/storage/innobase/include/dict0dict.h b/storage/innobase/include/dict0dict.h index b9a8c0e70e7e1..0197a790faa13 100644 --- a/storage/innobase/include/dict0dict.h +++ b/storage/innobase/include/dict0dict.h @@ -395,15 +395,6 @@ dict_index_remove_from_cache( dict_index_t* index); /**********************************************************************//** -Change the id of a table object in the dictionary cache. This is used in -DISCARD TABLESPACE. */ -void -dict_table_change_id_in_cache( -/*==========================*/ - dict_table_t* table, /*!< in/out: table object already in cache */ - table_id_t new_id) /*!< in: new id to set */ - MY_ATTRIBUTE((nonnull)); -/**********************************************************************//** Removes a foreign constraint struct from the dictionary cache. */ void dict_foreign_remove_from_cache( @@ -1385,19 +1376,19 @@ class dict_sys_t static const char fatal_msg[]; /** @return A new value for GEN_CLUST_INDEX(DB_ROW_ID) */ - inline row_id_t get_new_row_id(); + inline row_id_t get_new_row_id() noexcept; /** Ensure that row_id is not smaller than id, on IMPORT TABLESPACE */ - inline void update_row_id(row_id_t id); + inline void update_row_id(row_id_t id) noexcept; /** Recover the global DB_ROW_ID sequence on database startup */ - void recover_row_id(row_id_t id) + void recover_row_id(row_id_t id) noexcept { row_id= ut_uint64_align_up(id, ROW_ID_WRITE_MARGIN) + ROW_ID_WRITE_MARGIN; } /** @return a new temporary table ID */ - table_id_t acquire_temporary_table_id() + table_id_t acquire_temporary_table_id() noexcept { return temp_table_id.fetch_add(1, std::memory_order_relaxed); } @@ -1407,55 +1398,32 @@ class dict_sys_t @return temporary table @retval nullptr if the table does not exist (should only happen during the rollback of CREATE...SELECT) */ - dict_table_t *acquire_temporary_table(table_id_t id) - { - ut_ad(frozen()); - dict_table_t *table; - ulint fold = ut_fold_ull(id); - HASH_SEARCH(id_hash, &temp_id_hash, fold, dict_table_t*, table, - ut_ad(table->cached), table->id == id); - if (UNIV_LIKELY(table != nullptr)) - { - DBUG_ASSERT(table->is_temporary()); - DBUG_ASSERT(table->id >= DICT_HDR_FIRST_ID); - table->acquire(); - } - return table; - } + dict_table_t *acquire_temporary_table(table_id_t id) const noexcept; /** Look up a persistent table. @param id table ID @return table @retval nullptr if not cached */ - dict_table_t *find_table(table_id_t id) - { - ut_ad(frozen()); - dict_table_t *table; - ulint fold= ut_fold_ull(id); - HASH_SEARCH(id_hash, &table_id_hash, fold, dict_table_t*, table, - ut_ad(table->cached), table->id == id); - DBUG_ASSERT(!table || !table->is_temporary()); - return table; - } + dict_table_t *find_table(table_id_t id) const noexcept; - bool is_initialised() const { return m_initialised; } + bool is_initialised() const noexcept { return m_initialised; } /** Initialise the data dictionary cache. */ - void create(); + void create() noexcept; /** Close the data dictionary cache on shutdown. */ - void close(); + void close() noexcept; /** Resize the hash tables based on the current buffer pool size. */ - void resize(); + void resize() noexcept; /** Add a table definition to the data dictionary cache */ - inline void add(dict_table_t* table); + inline void add(dict_table_t *table) noexcept; /** Remove a table definition from the data dictionary cache. @param[in,out] table cached table definition to be evicted @param[in] lru whether this is part of least-recently-used evictiono @param[in] keep whether to keep (not free) the object */ - void remove(dict_table_t* table, bool lru = false, bool keep = false); + void remove(dict_table_t *table, bool lru= false, bool keep= false) noexcept; #ifdef UNIV_DEBUG /** Find a table */ @@ -1552,24 +1520,13 @@ class dict_sys_t /** Evict unused, unlocked tables from table_LRU. @param half whether to consider half the tables only (instead of all) @return number of tables evicted */ - ulint evict_table_LRU(bool half); + ulint evict_table_LRU(bool half) noexcept; /** Look up a table in the dictionary cache. @param name table name @return table handle @retval nullptr if not found */ - dict_table_t *find_table(const span &name) const - { - ut_ad(frozen()); - for (dict_table_t *table= static_cast - (HASH_GET_FIRST(&table_hash, table_hash.calc_hash - (my_crc32c(0, name.data(), name.size())))); - table; table= table->name_hash) - if (strlen(table->name.m_name) == name.size() && - !memcmp(table->name.m_name, name.data(), name.size())) - return table; - return nullptr; - } + dict_table_t *find_table(const span &name) const noexcept; /** Look up or load a table definition @param name table name @@ -1577,13 +1534,14 @@ class dict_sys_t @return table handle @retval nullptr if not found */ dict_table_t *load_table(const span &name, - dict_err_ignore_t ignore= DICT_ERR_IGNORE_NONE); + dict_err_ignore_t ignore= DICT_ERR_IGNORE_NONE) + noexcept; /** Attempt to load the system tables on startup @return whether any discrepancy with the expected definition was found */ - bool load_sys_tables(); + bool load_sys_tables() noexcept; /** Create or check system tables on startup */ - dberr_t create_or_check_sys_tables(); + dberr_t create_or_check_sys_tables() noexcept; }; /** the data dictionary cache */ diff --git a/storage/innobase/include/fil0fil.h b/storage/innobase/include/fil0fil.h index 7e000147b2fc6..435ed405e5c8c 100644 --- a/storage/innobase/include/fil0fil.h +++ b/storage/innobase/include/fil0fil.h @@ -1846,12 +1846,11 @@ fil_delete_file( /*============*/ const char* path); /*!< in: filepath of the ibd tablespace */ -/*******************************************************************//** -Returns the table space by a given id, NULL if not found. */ -fil_space_t* -fil_space_get_by_id( -/*================*/ - ulint id); /*!< in: space id */ +/** Look up a table space by a given id. +@param id tablespace identifier +@return tablespace object +@retval nullptr if not found */ +fil_space_t *fil_space_get_by_id(ulint id) noexcept; /** Note that a non-predefined persistent tablespace has been modified by redo log. diff --git a/storage/innobase/include/hash0hash.h b/storage/innobase/include/hash0hash.h index 867ad9e010931..552c2fa3e89fb 100644 --- a/storage/innobase/include/hash0hash.h +++ b/storage/innobase/include/hash0hash.h @@ -28,7 +28,6 @@ Created 5/20/1997 Heikki Tuuri #include "ut0rnd.h" #include "ut0new.h" -struct hash_table_t; struct hash_cell_t { /** singly-linked, nullptr terminated list of hash buckets */ @@ -39,7 +38,7 @@ struct hash_cell_t @param insert the being-inserted element @param next the next-element pointer in T */ template - void append(T &insert, T *T::*next) + void append(T &insert, T *T::*next) noexcept { void **after; for (after= &node; *after; @@ -47,122 +46,21 @@ struct hash_cell_t insert.*next= nullptr; *after= &insert; } -}; -/*******************************************************************//** -Inserts a struct to a hash table. */ - -#define HASH_INSERT(TYPE, NAME, TABLE, FOLD, DATA)\ -do {\ - hash_cell_t* cell3333;\ - TYPE* struct3333;\ -\ - (DATA)->NAME = NULL;\ -\ - cell3333 = &(TABLE)->array[(TABLE)->calc_hash(FOLD)]; \ -\ - if (cell3333->node == NULL) {\ - cell3333->node = DATA;\ - } else {\ - struct3333 = (TYPE*) cell3333->node;\ -\ - while (struct3333->NAME != NULL) {\ -\ - struct3333 = (TYPE*) struct3333->NAME;\ - }\ -\ - struct3333->NAME = DATA;\ - }\ -} while (0) - -#ifdef UNIV_HASH_DEBUG -# define HASH_ASSERT_VALID(DATA) ut_a((void*) (DATA) != (void*) -1) -# define HASH_INVALIDATE(DATA, NAME) *(void**) (&DATA->NAME) = (void*) -1 -#else -# define HASH_ASSERT_VALID(DATA) do {} while (0) -# define HASH_INVALIDATE(DATA, NAME) do {} while (0) -#endif - -/*******************************************************************//** -Deletes a struct from a hash table. */ - -#define HASH_DELETE(TYPE, NAME, TABLE, FOLD, DATA)\ -do {\ - hash_cell_t* cell3333;\ - TYPE* struct3333;\ -\ - cell3333 = &(TABLE)->array[(TABLE)->calc_hash(FOLD)]; \ -\ - if (cell3333->node == DATA) {\ - HASH_ASSERT_VALID(DATA->NAME);\ - cell3333->node = DATA->NAME;\ - } else {\ - struct3333 = (TYPE*) cell3333->node;\ -\ - while (struct3333->NAME != DATA) {\ -\ - struct3333 = (TYPE*) struct3333->NAME;\ - ut_a(struct3333);\ - }\ -\ - struct3333->NAME = DATA->NAME;\ - }\ - HASH_INVALIDATE(DATA, NAME);\ -} while (0) - -/*******************************************************************//** -Gets the first struct in a hash chain, NULL if none. */ - -#define HASH_GET_FIRST(TABLE, HASH_VAL) (TABLE)->array[HASH_VAL].node - -/*******************************************************************//** -Gets the next struct in a hash chain, NULL if none. */ - -#define HASH_GET_NEXT(NAME, DATA) ((DATA)->NAME) - -/********************************************************************//** -Looks for a struct in a hash table. */ -#define HASH_SEARCH(NAME, TABLE, FOLD, TYPE, DATA, ASSERTION, TEST)\ -{\ - (DATA) = (TYPE) HASH_GET_FIRST(TABLE, (TABLE)->calc_hash(FOLD)); \ - HASH_ASSERT_VALID(DATA);\ -\ - while ((DATA) != NULL) {\ - ASSERTION;\ - if (TEST) {\ - break;\ - } else {\ - HASH_ASSERT_VALID(HASH_GET_NEXT(NAME, DATA));\ - (DATA) = (TYPE) HASH_GET_NEXT(NAME, DATA);\ - }\ - }\ -} - -/********************************************************************//** -Looks for an item in all hash buckets. */ -#define HASH_SEARCH_ALL(NAME, TABLE, TYPE, DATA, ASSERTION, TEST) \ -do { \ - ulint i3333; \ - \ - for (i3333 = (TABLE)->n_cells; i3333--; ) { \ - (DATA) = (TYPE) HASH_GET_FIRST(TABLE, i3333); \ - \ - while ((DATA) != NULL) { \ - HASH_ASSERT_VALID(DATA); \ - ASSERTION; \ - \ - if (TEST) { \ - break; \ - } \ - \ - (DATA) = (TYPE) HASH_GET_NEXT(NAME, DATA); \ - } \ - \ - if ((DATA) != NULL) { \ - break; \ - } \ - } \ -} while (0) + /** Remove an element. + @tparam T type of the element + @param element the being-removed element + @param next the next-element pointer in T */ + template + void remove(T &element, T *T::*next) noexcept + { + T **prev= reinterpret_cast(&node); + while (*prev != &element) + prev= &((*prev)->*next); + *prev= element.*next; + element.*next= nullptr; + } +}; /** Hash table with singly-linked overflow lists */ struct hash_table_t @@ -174,17 +72,21 @@ struct hash_table_t /** Create the hash table. @param n the lower bound of n_cells */ - void create(ulint n) + void create(ulint n) noexcept { n_cells= ut_find_prime(n); array= static_cast(ut_zalloc_nokey(n_cells * sizeof *array)); } /** Clear the hash table. */ - void clear() { memset(array, 0, n_cells * sizeof *array); } + void clear() noexcept { memset(array, 0, n_cells * sizeof *array); } /** Free the hash table. */ - void free() { ut_free(array); array= nullptr; } + void free() noexcept { ut_free(array); array= nullptr; } + + ulint calc_hash(ulint fold) const noexcept + { return ut_hash_ulint(fold, n_cells); } - ulint calc_hash(ulint fold) const { return ut_hash_ulint(fold, n_cells); } + hash_cell_t *cell_get(ulint fold) const noexcept + { return &array[calc_hash(fold)]; } }; diff --git a/storage/innobase/include/lock0lock.h b/storage/innobase/include/lock0lock.h index 826239dddcb4d..f239fa0664e08 100644 --- a/storage/innobase/include/lock0lock.h +++ b/storage/innobase/include/lock0lock.h @@ -1174,9 +1174,9 @@ lock_rec_create( trx mutex */ /** Remove a record lock request, waiting or granted, on a discarded page -@param hash hash table -@param in_lock lock object */ -void lock_rec_discard(lock_sys_t::hash_table &lock_hash, lock_t *in_lock); +@param in_lock lock object +@param cell hash table cell containing in_lock */ +void lock_rec_discard(lock_t *in_lock, hash_cell_t &cell) noexcept; /** Create a new record lock and inserts it to the lock queue, without checking for deadlocks or conflicts. diff --git a/storage/innobase/include/lock0priv.inl b/storage/innobase/include/lock0priv.inl index 67826fb10013c..3c8ec01367b8d 100644 --- a/storage/innobase/include/lock0priv.inl +++ b/storage/innobase/include/lock0priv.inl @@ -180,7 +180,7 @@ lock_rec_get_next_on_page_const( const page_id_t page_id{lock->un_member.rec_lock.page_id}; - while (!!(lock= static_cast(HASH_GET_NEXT(hash, lock)))) + while (!!(lock= static_cast(lock->hash))) if (lock->un_member.rec_lock.page_id == page_id) break; return lock; diff --git a/storage/innobase/include/trx0i_s.h b/storage/innobase/include/trx0i_s.h index caacfa0972a99..f549745baa276 100644 --- a/storage/innobase/include/trx0i_s.h +++ b/storage/innobase/include/trx0i_s.h @@ -70,20 +70,6 @@ do { \ } \ } while (0) -/** A row of INFORMATION_SCHEMA.innodb_locks */ -struct i_s_locks_row_t; - -/** Objects of trx_i_s_cache_t::locks_hash */ -struct i_s_hash_chain_t; - -/** Objects of this type are added to the hash table -trx_i_s_cache_t::locks_hash */ -struct i_s_hash_chain_t { - i_s_locks_row_t* value; /*!< row of - INFORMATION_SCHEMA.innodb_locks*/ - i_s_hash_chain_t* next; /*!< next item in the hash chain */ -}; - /** This structure represents INFORMATION_SCHEMA.innodb_locks row */ struct i_s_locks_row_t { trx_id_t lock_trx_id; /*!< transaction identifier */ @@ -106,7 +92,7 @@ struct i_s_locks_row_t { table_id_t lock_table_id; /*!< table identifier from lock_get_table_id */ - i_s_hash_chain_t hash_chain; /*!< hash table chain node for + i_s_locks_row_t *next; /*!< hash table chain node for trx_i_s_cache_t::locks_hash */ /* @} */ }; diff --git a/storage/innobase/include/univ.i b/storage/innobase/include/univ.i index 66544842d26ad..4f0e83e0b88f2 100644 --- a/storage/innobase/include/univ.i +++ b/storage/innobase/include/univ.i @@ -153,7 +153,6 @@ using the call command. */ ut_ad(lock_rec_validate_page()) assertions. */ #define UNIV_LRU_DEBUG /* debug the buffer pool LRU */ -#define UNIV_HASH_DEBUG /* debug HASH_ macros */ #define UNIV_IBUF_DEBUG /* debug the insert buffer */ #define UNIV_PERF_DEBUG /* debug flag that enables light weight performance diff --git a/storage/innobase/include/ut0rnd.h b/storage/innobase/include/ut0rnd.h index 511eb21fd11ae..7f396dd4b706a 100644 --- a/storage/innobase/include/ut0rnd.h +++ b/storage/innobase/include/ut0rnd.h @@ -81,6 +81,7 @@ ut_hash_ulint( /*==========*/ ulint key, /*!< in: value to be hashed */ ulint table_size); /*!< in: hash table size */ +# if SIZEOF_SIZE_T < 8 /*************************************************************//** Folds a 64-bit integer. @return folded value */ @@ -90,6 +91,9 @@ ut_fold_ull( /*========*/ ib_uint64_t d) /*!< in: 64-bit integer */ MY_ATTRIBUTE((const)); +# else +# define ut_fold_ull(d) d +# endif /***********************************************************//** Looks for a prime number slightly greater than the given argument. The prime is chosen so that it is not near any power of 2. diff --git a/storage/innobase/include/ut0rnd.inl b/storage/innobase/include/ut0rnd.inl index 37da323f8f38b..83449c738ca72 100644 --- a/storage/innobase/include/ut0rnd.inl +++ b/storage/innobase/include/ut0rnd.inl @@ -47,6 +47,7 @@ ut_hash_ulint( return(key % table_size); } +# if SIZEOF_SIZE_T < 8 /*************************************************************//** Folds a 64-bit integer. @return folded value */ @@ -59,6 +60,7 @@ ut_fold_ull( return(ut_fold_ulint_pair((ulint) d & ULINT32_MASK, (ulint) (d >> 32))); } +# endif /* SIZEOF_SIZE_T < 8 */ #endif /* !UNIV_INNOCHECKSUM */ /*************************************************************//** diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc index 7e3b3513af438..51f52ac0d9805 100644 --- a/storage/innobase/lock/lock0lock.cc +++ b/storage/innobase/lock/lock0lock.cc @@ -2363,8 +2363,7 @@ static void lock_rec_dequeue_from_page(lock_t *in_lock, bool owns_wait_mutex) const ulint rec_fold = page_id.fold(); hash_cell_t &cell = *lock_hash.cell_get(rec_fold); lock_sys.assert_locked(cell); - - HASH_DELETE(lock_t, hash, &lock_hash, rec_fold, in_lock); + cell.remove(*in_lock, &lock_t::hash); UT_LIST_REMOVE(in_lock->trx->lock.trx_locks, in_lock); MONITOR_INC(MONITOR_RECLOCK_REMOVED); @@ -2414,16 +2413,14 @@ static void lock_rec_dequeue_from_page(lock_t *in_lock, bool owns_wait_mutex) } /** Remove a record lock request, waiting or granted, on a discarded page -@param hash hash table -@param in_lock lock object */ +@param in_lock lock object +@param cell hash table cell containing in_lock */ TRANSACTIONAL_TARGET -void lock_rec_discard(lock_sys_t::hash_table &lock_hash, lock_t *in_lock) +void lock_rec_discard(lock_t *in_lock, hash_cell_t &cell) noexcept { ut_ad(!in_lock->is_table()); - lock_hash.assert_locked(in_lock->un_member.rec_lock.page_id); - HASH_DELETE(lock_t, hash, &lock_hash, - in_lock->un_member.rec_lock.page_id.fold(), in_lock); + cell.remove(*in_lock, &lock_t::hash); ut_d(uint32_t old_locks); { trx_t *trx= in_lock->trx; @@ -2441,17 +2438,16 @@ void lock_rec_discard(lock_sys_t::hash_table &lock_hash, lock_t *in_lock) Removes record lock objects set on an index page which is discarded. This function does not move locks, or check for waiting locks, therefore the lock bitmaps must already be reset when this function is called. */ +template static void -lock_rec_free_all_from_discard_page(page_id_t id, const hash_cell_t &cell, - lock_sys_t::hash_table &lock_hash) +lock_rec_free_all_from_discard_page(page_id_t id, hash_cell_t &cell) noexcept { for (lock_t *lock= lock_sys_t::get_first(cell, id); lock; ) { - ut_ad(&lock_hash != &lock_sys.rec_hash || - lock_rec_find_set_bit(lock) == ULINT_UNDEFINED); + ut_ad(!assert || lock_rec_find_set_bit(lock) == ULINT_UNDEFINED); ut_ad(!lock->is_waiting()); lock_t *next_lock= lock_rec_get_next_on_page(lock); - lock_rec_discard(lock_hash, lock); + lock_rec_discard(lock, cell); lock= next_lock; } } @@ -2468,15 +2464,15 @@ ATTRIBUTE_COLD void lock_discard_for_index(const dict_index_t &index) const ulint n= lock_sys.rec_hash.pad(lock_sys.rec_hash.n_cells); for (ulint i= 0; i < n; i++) { - for (lock_t *lock= static_cast(lock_sys.rec_hash.array[i].node); - lock; ) + hash_cell_t &cell= lock_sys.rec_hash.array[i]; + for (lock_t *lock= static_cast(cell.node); lock; ) { ut_ad(!lock->is_table()); if (lock->index == &index) { ut_ad(!lock->is_waiting()); - lock_rec_discard(lock_sys.rec_hash, lock); - lock= static_cast(lock_sys.rec_hash.array[i].node); + lock_rec_discard(lock, cell); + lock= static_cast(cell.node); } else lock= lock->hash; @@ -3269,7 +3265,7 @@ lock_update_merge_right( /* Reset the locks on the supremum of the left page, releasing waiting transactions */ lock_rec_reset_and_release_wait(g.cell1(), l, PAGE_HEAP_NO_SUPREMUM); - lock_rec_free_all_from_discard_page(l, g.cell1(), lock_sys.rec_hash); + lock_rec_free_all_from_discard_page(l, g.cell1()); ut_d(lock_assert_no_spatial(l)); } @@ -3301,7 +3297,7 @@ void lock_update_copy_and_discard(const buf_block_t &new_block, page_id_t old) /* Move the locks on the supremum of the old page to the supremum of new */ lock_rec_move(g.cell1(), new_block, id, g.cell2(), old, PAGE_HEAP_NO_SUPREMUM, PAGE_HEAP_NO_SUPREMUM); - lock_rec_free_all_from_discard_page(old, g.cell2(), lock_sys.rec_hash); + lock_rec_free_all_from_discard_page(old, g.cell2()); } /*************************************************************//** @@ -3359,7 +3355,7 @@ void lock_update_merge_left(const buf_block_t& left, const rec_t *orig_pred, of the left page */ lock_rec_move(g.cell1(), left, l, g.cell2(), right, PAGE_HEAP_NO_SUPREMUM, PAGE_HEAP_NO_SUPREMUM); - lock_rec_free_all_from_discard_page(right, g.cell2(), lock_sys.rec_hash); + lock_rec_free_all_from_discard_page(right, g.cell2()); /* there should exist no page lock on the right page, otherwise, it will be blocked from merge */ @@ -3450,21 +3446,18 @@ lock_update_discard( } while (heap_no != PAGE_HEAP_NO_SUPREMUM); } - lock_rec_free_all_from_discard_page(page_id, g.cell2(), - lock_sys.rec_hash); + lock_rec_free_all_from_discard_page(page_id, g.cell2()); } else { const auto fold = page_id.fold(); auto cell = lock_sys.prdt_hash.cell_get(fold); auto latch = lock_sys_t::hash_table::latch(cell); latch->acquire(); - lock_rec_free_all_from_discard_page(page_id, *cell, - lock_sys.prdt_hash); + lock_rec_free_all_from_discard_page(page_id, *cell); latch->release(); cell = lock_sys.prdt_page_hash.cell_get(fold); latch = lock_sys_t::hash_table::latch(cell); latch->acquire(); - lock_rec_free_all_from_discard_page(page_id, *cell, - lock_sys.prdt_page_hash); + lock_rec_free_all_from_discard_page(page_id, *cell); latch->release(); } } @@ -5118,25 +5111,13 @@ Calculates the number of record lock structs in the record lock hash table. TRANSACTIONAL_TARGET static ulint lock_get_n_rec_locks() { - ulint n_locks = 0; - ulint i; - - lock_sys.assert_locked(); - - for (i = 0; i < lock_sys.rec_hash.n_cells; i++) { - const lock_t* lock; - - for (lock = static_cast( - HASH_GET_FIRST(&lock_sys.rec_hash, i)); - lock != 0; - lock = static_cast( - HASH_GET_NEXT(hash, lock))) { - - n_locks++; - } - } - - return(n_locks); + ulint n_locks= 0; + lock_sys.assert_locked(); + for (ulint i= 0; i < lock_sys.rec_hash.n_cells; i++) + for (auto lock= static_cast(lock_sys.rec_hash.array[i].node); + lock; lock= lock->hash) + n_locks++; + return n_locks; } #endif /* PRINT_NUM_OF_LOCK_STRUCTS */ @@ -5645,10 +5626,8 @@ lock_rec_validate( lock_sys.assert_locked(); for (const lock_t* lock = static_cast( - HASH_GET_FIRST(&lock_sys.rec_hash, start)); - lock != NULL; - lock = static_cast(HASH_GET_NEXT(hash, lock))) { - + lock_sys.rec_hash.array[start].node); + lock; lock = lock->hash) { ut_ad(!lock->trx->read_only || !lock->trx->is_autocommit_non_locking()); ut_ad(!lock->is_table()); diff --git a/storage/innobase/lock/lock0prdt.cc b/storage/innobase/lock/lock0prdt.cc index 2975659138d4e..3ea05ddb74198 100644 --- a/storage/innobase/lock/lock0prdt.cc +++ b/storage/innobase/lock/lock0prdt.cc @@ -895,7 +895,7 @@ void lock_sys_t::prdt_page_free_from_discard(const page_id_t id, bool all) for (lock_t *lock= get_first(*cell, id), *next; lock; lock= next) { next= lock_rec_get_next_on_page(lock); - lock_rec_discard(prdt_page_hash, lock); + lock_rec_discard(lock, *cell); } if (all) @@ -907,7 +907,7 @@ void lock_sys_t::prdt_page_free_from_discard(const page_id_t id, bool all) for (lock_t *lock= get_first(*cell, id), *next; lock; lock= next) { next= lock_rec_get_next_on_page(lock); - lock_rec_discard(prdt_hash, lock); + lock_rec_discard(lock, *cell); } } @@ -919,7 +919,7 @@ void lock_sys_t::prdt_page_free_from_discard(const page_id_t id, bool all) for (lock_t *lock= get_first(*cell, id), *next; lock; lock= next) { next= lock_rec_get_next_on_page(lock); - lock_rec_discard(rec_hash, lock); + lock_rec_discard(lock, *cell); } latch->release(); diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc index 207006ba2d3b4..056c5be7fea85 100644 --- a/storage/innobase/row/row0mysql.cc +++ b/storage/innobase/row/row0mysql.cc @@ -2321,6 +2321,9 @@ row_discard_tablespace( trx_t* trx, /*!< in/out: transaction handle */ dict_table_t* table) /*!< in/out: table to be discarded */ { + ut_ad(table->magic_n == DICT_TABLE_MAGIC_N); + ut_ad(!table->is_temporary()); + dberr_t err; /* How do we prevent crashes caused by ongoing operations on @@ -2378,8 +2381,14 @@ row_discard_tablespace( /* All persistent operations successful, update the data dictionary memory cache. */ + ut_ad(dict_sys.locked()); - dict_table_change_id_in_cache(table, new_id); + /* Remove the table from the hash table of id's */ + dict_sys.table_id_hash.cell_get(ut_fold_ull(table->id)) + ->remove(*table, &dict_table_t::id_hash); + table->id = new_id; + dict_sys.table_id_hash.cell_get(ut_fold_ull(table->id)) + ->append(*table, &dict_table_t::id_hash); dict_index_t* index = UT_LIST_GET_FIRST(table->indexes); diff --git a/storage/innobase/trx/trx0i_s.cc b/storage/innobase/trx/trx0i_s.cc index 2dc39118d3ddf..4a661c5118307 100644 --- a/storage/innobase/trx/trx0i_s.cc +++ b/storage/innobase/trx/trx0i_s.cc @@ -59,47 +59,6 @@ now, then 39th chunk would accommodate 1677416425 rows and all chunks would accommodate 3354832851 rows. */ #define MEM_CHUNKS_IN_TABLE_CACHE 39 -/** The following are some testing auxiliary macros. Do not enable them -in a production environment. */ -/* @{ */ - -#if 0 -/** If this is enabled then lock folds will always be different -resulting in equal rows being put in a different cells of the hash -table. Checking for duplicates will be flawed because different -fold will be calculated when a row is searched in the hash table. */ -#define TEST_LOCK_FOLD_ALWAYS_DIFFERENT -#endif - -#if 0 -/** This effectively kills the search-for-duplicate-before-adding-a-row -function, but searching in the hash is still performed. It will always -be assumed that lock is not present and insertion will be performed in -the hash table. */ -#define TEST_NO_LOCKS_ROW_IS_EVER_EQUAL_TO_LOCK_T -#endif - -#if 0 -/** This aggressively repeats adding each row many times. Depending on -the above settings this may be noop or may result in lots of rows being -added. */ -#define TEST_ADD_EACH_LOCKS_ROW_MANY_TIMES -#endif - -#if 0 -/** Very similar to TEST_NO_LOCKS_ROW_IS_EVER_EQUAL_TO_LOCK_T but hash -table search is not performed at all. */ -#define TEST_DO_NOT_CHECK_FOR_DUPLICATE_ROWS -#endif - -#if 0 -/** Do not insert each row into the hash table, duplicates may appear -if this is enabled, also if this is enabled searching into the hash is -noop because it will be empty. */ -#define TEST_DO_NOT_INSERT_INTO_THE_HASH_TABLE -#endif -/* @} */ - /** Memory limit passed to ha_storage_put_memlim(). @param cache hash storage @return maximum allowed allocation size */ @@ -162,6 +121,13 @@ struct trx_i_s_cache_t { bool is_truncated; /*!< this is true if the memory limit was hit and thus the data in the cache is truncated */ + + /** Adds an element. + @param lock element to be added + @param heap_no record lock heap number, or 0xFFFF for table lock + @return the existing or added lock + @retval nullptr if memory cannot be allocated */ + i_s_locks_row_t *add(const lock_t &lock, uint16_t heap_no) noexcept; }; /** This is the intermediate buffer where data needed to fill the @@ -778,7 +744,7 @@ static bool fill_locks_row( row->lock_table_id = table->id; - row->hash_chain.value = row; + row->next = nullptr; ut_ad(i_s_locks_row_validate(row)); return true; @@ -819,112 +785,18 @@ static ulint fold_lock( /*======*/ - const lock_t* lock, /*!< in: lock object to fold */ - ulint heap_no)/*!< in: lock's record number + const lock_t& lock, /*!< in: lock object to fold */ + uint16_t heap_no)/*!< in: lock's record number or 0xFFFF if the lock is a table lock */ { -#ifdef TEST_LOCK_FOLD_ALWAYS_DIFFERENT - static ulint fold = 0; - - return(fold++); -#else - ulint ret; - - if (!lock->is_table()) { - ut_a(heap_no != 0xFFFF); - ret = ut_fold_ulint_pair((ulint) lock->trx->id, - lock->un_member.rec_lock.page_id. - fold()); - ret = ut_fold_ulint_pair(ret, heap_no); - } else { - /* this check is actually not necessary for continuing - correct operation, but something must have gone wrong if - it fails. */ - ut_a(heap_no == 0xFFFF); - - ret = (ulint) lock_get_table(*lock)->id; - } - - return(ret); -#endif -} - -/*******************************************************************//** -Checks whether i_s_locks_row_t object represents a lock_t object. -@return TRUE if they match */ -static -ibool -locks_row_eq_lock( -/*==============*/ - const i_s_locks_row_t* row, /*!< in: innodb_locks row */ - const lock_t* lock, /*!< in: lock object */ - ulint heap_no)/*!< in: lock's record number - or 0xFFFF if the lock - is a table lock */ -{ - ut_ad(i_s_locks_row_validate(row)); -#ifdef TEST_NO_LOCKS_ROW_IS_EVER_EQUAL_TO_LOCK_T - return(0); -#else - if (!lock->is_table()) { - ut_a(heap_no != 0xFFFF); - - return(row->lock_trx_id == lock->trx->id - && row->lock_page == lock->un_member.rec_lock.page_id - && row->lock_rec == heap_no); - } else { - /* this check is actually not necessary for continuing - correct operation, but something must have gone wrong if - it fails. */ - ut_a(heap_no == 0xFFFF); - - return(row->lock_trx_id == lock->trx->id - && row->lock_table_id == lock_get_table(*lock)->id); - } -#endif -} - -/*******************************************************************//** -Searches for a row in the innodb_locks cache that has a specified id. -This happens in O(1) time since a hash table is used. Returns pointer to -the row or NULL if none is found. -@return row or NULL */ -static -i_s_locks_row_t* -search_innodb_locks( -/*================*/ - trx_i_s_cache_t* cache, /*!< in: cache */ - const lock_t* lock, /*!< in: lock to search for */ - uint16_t heap_no)/*!< in: lock's record number - or 0xFFFF if the lock - is a table lock */ -{ - i_s_hash_chain_t* hash_chain; - - HASH_SEARCH( - /* hash_chain->"next" */ - next, - /* the hash table */ - &cache->locks_hash, - /* fold */ - fold_lock(lock, heap_no), - /* the type of the next variable */ - i_s_hash_chain_t*, - /* auxiliary variable */ - hash_chain, - /* assertion on every traversed item */ - ut_ad(i_s_locks_row_validate(hash_chain->value)), - /* this determines if we have found the lock */ - locks_row_eq_lock(hash_chain->value, lock, heap_no)); - - if (hash_chain == NULL) { - - return(NULL); - } - /* else */ - - return(hash_chain->value); + ut_ad((heap_no == 0xFFFF) == lock.is_table()); + if (heap_no == 0xFFFF) + return ulint(lock.un_member.tab_lock.table->id); + char buf[8 + 8]; + memcpy(buf, &lock.trx->id, 8); + memcpy(buf + 8, &lock.un_member.rec_lock.page_id, 8); + return my_crc32c(heap_no, buf, sizeof buf); } /*******************************************************************//** @@ -933,67 +805,40 @@ Returns a pointer to the added row. If the row is already present then no row is added and a pointer to the existing row is returned. If row can not be allocated then NULL is returned. @return row */ -static -i_s_locks_row_t* -add_lock_to_cache( -/*==============*/ - trx_i_s_cache_t* cache, /*!< in/out: cache */ - const lock_t* lock, /*!< in: the element to add */ - uint16_t heap_no)/*!< in: lock's record number - or 0 if the lock - is a table lock */ +i_s_locks_row_t * +trx_i_s_cache_t::add(const lock_t &lock, uint16_t heap_no) noexcept { - i_s_locks_row_t* dst_row; - -#ifdef TEST_ADD_EACH_LOCKS_ROW_MANY_TIMES - ulint i; - for (i = 0; i < 10000; i++) { -#endif -#ifndef TEST_DO_NOT_CHECK_FOR_DUPLICATE_ROWS - /* quit if this lock is already present */ - dst_row = search_innodb_locks(cache, lock, heap_no); - if (dst_row != NULL) { - - ut_ad(i_s_locks_row_validate(dst_row)); - return(dst_row); - } -#endif - - dst_row = (i_s_locks_row_t*) - table_cache_create_empty_row(&cache->innodb_locks, cache); - - /* memory could not be allocated */ - if (dst_row == NULL) { - - return(NULL); - } - - if (!fill_locks_row(dst_row, lock, heap_no, cache)) { - - /* memory could not be allocated */ - cache->innodb_locks.rows_used--; - return(NULL); - } - -#ifndef TEST_DO_NOT_INSERT_INTO_THE_HASH_TABLE - HASH_INSERT( - /* the type used in the hash chain */ - i_s_hash_chain_t, - /* hash_chain->"next" */ - next, - /* the hash table */ - &cache->locks_hash, - /* fold */ - fold_lock(lock, heap_no), - /* add this data to the hash */ - &dst_row->hash_chain); -#endif -#ifdef TEST_ADD_EACH_LOCKS_ROW_MANY_TIMES - } /* for()-loop */ -#endif + ut_ad(lock.is_table() == (heap_no == 0xFFFF)); + i_s_locks_row_t** after= reinterpret_cast + (&locks_hash.cell_get(fold_lock(lock, heap_no))->node); + while (i_s_locks_row_t *row= *after) + { + ut_ad(i_s_locks_row_validate(row)); + if (row->lock_trx_id == lock.trx->id && + (heap_no == 0xFFFF + ? row->lock_table_id == lock.un_member.tab_lock.table->id + : (row->lock_rec == heap_no && + row->lock_page == lock.un_member.rec_lock.page_id))) + return row; + after= &row->next; + } + i_s_locks_row_t *dst_row= static_cast + (table_cache_create_empty_row(&innodb_locks, this)); + if (dst_row) + { + if (!fill_locks_row(dst_row, &lock, heap_no, this)) + { + innodb_locks.rows_used--; + dst_row= nullptr; + } + else + { + *after= dst_row; + ut_ad(i_s_locks_row_validate(dst_row)); + } + } - ut_ad(i_s_locks_row_validate(dst_row)); - return(dst_row); + return dst_row; } /*******************************************************************//** @@ -1057,12 +902,10 @@ add_trx_relevant_locks_to_cache( i_s_locks_row_t* blocking_lock_row; lock_queue_iterator_t iter; - uint16_t wait_lock_heap_no - = wait_lock_get_heap_no(wait_lock); + uint16_t heap_no = wait_lock_get_heap_no(wait_lock); /* add the requested lock */ - *requested_lock_row = add_lock_to_cache(cache, wait_lock, - wait_lock_heap_no); + *requested_lock_row = cache->add(*wait_lock, heap_no); /* memory could not be allocated */ if (*requested_lock_row == NULL) { @@ -1083,13 +926,8 @@ add_trx_relevant_locks_to_cache( /* add the lock that is blocking wait_lock */ - blocking_lock_row - = add_lock_to_cache( - cache, curr_lock, - /* heap_no is the same - for the wait and waited - locks */ - wait_lock_heap_no); + blocking_lock_row = cache->add(*curr_lock, + heap_no); /* memory could not be allocated */ if (blocking_lock_row == NULL) {