MDEV-22646 Assertion `table2->cached' failed in dict_table_t::add_to_cache

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.
parent ca3aa679
...@@ -6631,29 +6631,19 @@ btr_blob_free( ...@@ -6631,29 +6631,19 @@ btr_blob_free(
mtr_t* mtr) /*!< in: mini-transaction to commit */ mtr_t* mtr) /*!< in: mini-transaction to commit */
{ {
buf_pool_t* buf_pool = buf_pool_from_block(block); buf_pool_t* buf_pool = buf_pool_from_block(block);
ulint space = block->page.id.space(); const page_id_t page_id = block->page.id;
ulint page_no = block->page.id.page_no();
ut_ad(mtr_is_block_fix(mtr, block, MTR_MEMO_PAGE_X_FIX, index->table)); ut_ad(mtr_is_block_fix(mtr, block, MTR_MEMO_PAGE_X_FIX, index->table));
mtr_commit(mtr); mtr_commit(mtr);
buf_pool_mutex_enter(buf_pool); buf_pool_mutex_enter(buf_pool);
/* Only free the block if it is still allocated to if (buf_page_t* bpage = buf_page_hash_get(buf_pool, page_id)) {
the same file page. */ if (!buf_LRU_free_page(bpage, all)
&& all && bpage->zip.data) {
if (buf_block_get_state(block)
== BUF_BLOCK_FILE_PAGE
&& block->page.id.space() == space
&& block->page.id.page_no() == page_no) {
if (!buf_LRU_free_page(&block->page, all)
&& all && block->page.zip.data) {
/* Attempt to deallocate the uncompressed page /* Attempt to deallocate the uncompressed page
if the whole block cannot be deallocted. */ if the whole block cannot be deallocted. */
buf_LRU_free_page(&block->page, false); buf_LRU_free_page(bpage, false);
} }
} }
......
This diff is collapsed.
...@@ -2698,7 +2698,7 @@ buf_pool_resize() ...@@ -2698,7 +2698,7 @@ buf_pool_resize()
btr_search_s_unlock_all(); btr_search_s_unlock_all();
} }
btr_search_disable(true); btr_search_disable();
if (btr_search_disabled) { if (btr_search_disabled) {
ib::info() << "disabled adaptive hash index."; ib::info() << "disabled adaptive hash index.";
...@@ -3072,10 +3072,6 @@ buf_pool_resize() ...@@ -3072,10 +3072,6 @@ buf_pool_resize()
srv_lock_table_size = 5 * (srv_buf_pool_size / UNIV_PAGE_SIZE); srv_lock_table_size = 5 * (srv_buf_pool_size / UNIV_PAGE_SIZE);
lock_sys_resize(srv_lock_table_size); lock_sys_resize(srv_lock_table_size);
/* normalize btr_search_sys */
btr_search_sys_resize(
buf_pool_get_curr_size() / sizeof(void*) / 64);
/* normalize dict_sys */ /* normalize dict_sys */
dict_resize(); dict_resize();
...@@ -3100,7 +3096,7 @@ buf_pool_resize() ...@@ -3100,7 +3096,7 @@ buf_pool_resize()
#ifdef BTR_CUR_HASH_ADAPT #ifdef BTR_CUR_HASH_ADAPT
/* enable AHI if needed */ /* enable AHI if needed */
if (btr_search_disabled) { if (btr_search_disabled) {
btr_search_enable(); btr_search_enable(true);
ib::info() << "Re-enabled adaptive hash index."; ib::info() << "Re-enabled adaptive hash index.";
} }
#endif /* BTR_CUR_HASH_ADAPT */ #endif /* BTR_CUR_HASH_ADAPT */
......
...@@ -3124,10 +3124,10 @@ fil_reinit_space_header_for_table( ...@@ -3124,10 +3124,10 @@ fil_reinit_space_header_for_table(
dict_table_x_unlock_indexes(table); dict_table_x_unlock_indexes(table);
row_mysql_unlock_data_dictionary(trx); row_mysql_unlock_data_dictionary(trx);
DEBUG_SYNC_C("buffer_pool_scan");
/* Lock the search latch in shared mode to prevent user /* Lock the search latch in shared mode to prevent user
from disabling AHI during the scan */ from disabling AHI during the scan */
btr_search_s_lock_all(); btr_search_s_lock_all();
DEBUG_SYNC_C("buffer_pool_scan");
buf_LRU_flush_or_remove_pages(id, NULL); buf_LRU_flush_or_remove_pages(id, NULL);
btr_search_s_unlock_all(); btr_search_s_unlock_all();
......
...@@ -18134,7 +18134,7 @@ innodb_adaptive_hash_index_update( ...@@ -18134,7 +18134,7 @@ innodb_adaptive_hash_index_update(
if (*(my_bool*) save) { if (*(my_bool*) save) {
btr_search_enable(); btr_search_enable();
} else { } else {
btr_search_disable(true); btr_search_disable();
} }
mysql_mutex_lock(&LOCK_global_system_variables); mysql_mutex_lock(&LOCK_global_system_variables);
} }
......
...@@ -36,23 +36,17 @@ Created 2/17/1996 Heikki Tuuri ...@@ -36,23 +36,17 @@ Created 2/17/1996 Heikki Tuuri
void void
btr_search_sys_create(ulint hash_size); btr_search_sys_create(ulint hash_size);
/** Resize hash index hash table.
@param[in] hash_size hash index hash table size */
void
btr_search_sys_resize(ulint hash_size);
/** Frees the adaptive search system at a database shutdown. */ /** Frees the adaptive search system at a database shutdown. */
void void
btr_search_sys_free(); btr_search_sys_free();
/** Disable the adaptive hash search system and empty the index. /** Disable the adaptive hash search system and empty the index. */
@param need_mutex need to acquire dict_sys->mutex */ void btr_search_disable();
void
btr_search_disable( /** Enable the adaptive hash search system.
bool need_mutex); @param[in] resize Flag to indicate call during buf_pool_resize() */
/** Enable the adaptive hash search system. */
void void
btr_search_enable(); btr_search_enable(bool resize=false);
/*********************************************************************//** /*********************************************************************//**
Updates the search info. */ Updates the search info. */
...@@ -209,7 +203,6 @@ btr_get_search_table(const dict_index_t* index); ...@@ -209,7 +203,6 @@ btr_get_search_table(const dict_index_t* index);
# define btr_search_move_or_delete_hash_entries(new_block, block, index) # 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_insert(cursor)
# define btr_search_update_hash_on_delete(cursor) # define btr_search_update_hash_on_delete(cursor)
# define btr_search_sys_resize(hash_size)
#endif /* BTR_CUR_HASH_ADAPT */ #endif /* BTR_CUR_HASH_ADAPT */
#ifdef BTR_CUR_ADAPT #ifdef BTR_CUR_ADAPT
......
...@@ -1333,7 +1333,8 @@ srv_printf_innodb_monitor( ...@@ -1333,7 +1333,8 @@ srv_printf_innodb_monitor(
ibuf_print(file); ibuf_print(file);
#ifdef BTR_CUR_HASH_ADAPT #ifdef BTR_CUR_HASH_ADAPT
for (ulint i = 0; i < btr_ahi_parts; ++i) { btr_search_x_lock_all();
for (ulint i = 0; i < btr_ahi_parts && btr_search_enabled; ++i) {
const hash_table_t* table = btr_search_sys->hash_tables[i]; const hash_table_t* table = btr_search_sys->hash_tables[i];
ut_ad(table->magic_n == HASH_TABLE_MAGIC_N); ut_ad(table->magic_n == HASH_TABLE_MAGIC_N);
...@@ -1357,6 +1358,7 @@ srv_printf_innodb_monitor( ...@@ -1357,6 +1358,7 @@ srv_printf_innodb_monitor(
", node heap has " ULINTPF " buffer(s)\n", ", node heap has " ULINTPF " buffer(s)\n",
table->n_cells, heap->base.count - !heap->free_block); table->n_cells, heap->base.count - !heap->free_block);
} }
btr_search_x_unlock_all();
fprintf(file, fprintf(file,
"%.2f hash searches/s, %.2f non-hash searches/s\n", "%.2f hash searches/s, %.2f non-hash searches/s\n",
......
...@@ -2847,7 +2847,7 @@ innodb_shutdown() ...@@ -2847,7 +2847,7 @@ innodb_shutdown()
#ifdef BTR_CUR_HASH_ADAPT #ifdef BTR_CUR_HASH_ADAPT
if (dict_sys) { if (dict_sys) {
btr_search_disable(true); btr_search_disable();
} }
#endif /* BTR_CUR_HASH_ADAPT */ #endif /* BTR_CUR_HASH_ADAPT */
if (ibuf) { if (ibuf) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment