Bug #60003 DELETE TABLE command may leak ADAPTIVE HASH INDEX of InnoDB
Submitted: 8 Feb 2011 7:43 Modified: 9 Feb 2011 2:53
Reporter: Yasufumi Kinoshita Email Updates:
Status: Not a Bug Impact on me:
None 
Category:MySQL Server: InnoDB Plugin storage engine Severity:S2 (Serious)
Version:5.1.54 5.5.8 OS:Any
Assigned to: CPU Architecture:Any

[8 Feb 2011 7:43] Yasufumi Kinoshita
Description:
Generally in InnoDB,
deleting entries from the adaptive hash index
needs dict_index_t.
(Because btr_search_drop_page_hash_index() uses block->index)

However, (when innodb_file_per_table is enabled,)
row_drop_table_for_mysql() calls
dict_table_remove_from_cache()
"before buf_LRU_invalidate_tablespace()"
(buf_LRU_invalidate_tablespace() is called from fil_delete_tablespace())

Then,
in buf_LRU_invalidate_tablespace(),
buf_LRU_drop_page_hash_for_tablespace() is called at first,
so, even if btr_search_drop_page_hash_when_freed() is called,
it return without any operation.

So, the adaptive hash index entries for the table might be remained
even after deleting the table space.

How to repeat:
enable innodb_file_per_table

-----
mysqldump
restore
delete table
-----
loop?
[8 Feb 2011 11:40] Yasufumi Kinoshita
It might be wider problem.
It is not depend on innodb_file_per_table.

The adaptive index entry should be deleted before dict_index_remove_from_cache().
So, I think,

always dict_index_remove_from_cache() should call like
btr_search_drop_page_hash_index_on_index(index) before free index->heap,
to remove all adaptive hash index entries about the index.
[8 Feb 2011 12:06] Yasufumi Kinoshita
It may be critical problem.
There are slight possibility that the leaked wrong entries may lead the adaptive hash search to wrong page/ptr.
[8 Feb 2011 18:56] Mark Callaghan
I was curious about the path to btr_search_drop_page_hash_index prior to the call to dict_index_remove_from_cache. This is it.

#0  btr_search_drop_page_hash_index (block=0x2aaaaae0b130) at ./include/btr0sea.ic:98
#1  0x00000000008f8e1c in btr_free_root (space=0, zip_size=0, root_page_no=50, mtr=0x41a340f0) at btr/btr0btr.c:926
#2  0x0000000000931bb7 in dict_drop_index_tree (rec=0x2aaaab240196 "", mtr=0x41a340f0) at dict/dict0crea.c:732
#3  0x00000000008cd46f in row_upd_clust_step (node=0x12167c18, thr=0x12169848) at row/row0upd.c:1903
#4  0x00000000008cd8b3 in row_upd (node=0x12167c18, thr=0x12169848) at row/row0upd.c:2045
#5  0x00000000008cdb89 in row_upd_step (thr=0x12169848) at row/row0upd.c:2178
#6  0x00000000008a2e53 in que_thr_step (thr=0x12169848) at que/que0que.c:1227
#7  0x00000000008a30ff in que_run_threads_low (thr=0x12169848) at que/que0que.c:1306
#8  0x00000000008a320a in que_run_threads (thr=0x12169848) at que/que0que.c:1343
#9  0x00000000008a33e6 in que_eval_sql (info=0x1215a258, 
    sql=0xb6d868 "PROCEDURE DROP_TABLE_PROC () IS\nsys_foreign_id CHAR;\ntable_id CHAR;\nindex_id CHAR;\nforeign_id CHAR;\nfound INT;\nBEGIN\nSELECT ID INTO table_id\nFROM SYS_TABLES\nWHERE NAME = :table_name\nLOCK IN SHARE MODE"..., reserve_dict_mutex=0, trx=0x12159b58) at que/que0que.c:1426
#10 0x00000000008bc399 in row_drop_table_for_mysql (name=0x41a348f0 "test/i", trx=0x12159b58, drop_db=0, delayed_drop=1) at row/row0mysql.c:3253
#11 0x00000000008584a7 in ha_innobase::delete_table (this=0x1215eb90, name=0x41a35ee0 "./test/i", delayed_drop=1 '\001') at handler/ha_innodb.cc:7525
#12 0x000000000075578e in handler::ha_delete_table (this=0x1215eb90, name=0x41a35ee0 "./test/i", delayed_drop=1 '\001') at handler.cc:3445
#13 0x000000000075bef4 in ha_delete_table (thd=0x121305e0, table_type=0x1167cea0, path=0x41a35ee0 "./test/i", db=0x12150030 "test", alias=0x121375a0 "i", generate_warning=true, filep=0x41a36190) at handler.cc:2030
#14 0x0000000000787cab in mysql_rm_table_part2 (thd=0x121305e0, tables=0x1215e840, if_exists=false, drop_temporary=false, drop_view=false, dont_log_query=false) at sql_table.cc:2074
#15 0x0000000000788316 in mysql_rm_table (thd=0x121305e0, tables=0x1215e840, if_exists=0 '\0', drop_temporary=0 '\0') at sql_table.cc:1850
#16 0x0000000000614e59 in mysql_execute_command (thd=0x121305e0, last_timer=0x41a37f08) at sql_parse.cc:3775
#17 0x000000000061a686 in mysql_parse (thd=0x121305e0, rawbuf=0x1215f010 "drop table i", length=12, found_semicolon=0x41a37ea0, last_timer=0x41a37f08) at sql_parse.cc:6487
#18 0x000000000061ca30 in dispatch_command (command=COM_QUERY, thd=0x121305e0, packet=0x121515c1 "drop table i", packet_length=12) at sql_parse.cc:1324
#19 0x000000000061e28b in do_command (thd=0x121305e0) at sql_parse.cc:938
#20 0x0000000000608e0d in handle_one_connection (arg=0x121305e0) at sql_connect.cc:1184
#21 0x00000031ef2062f7 in start_thread () from /lib64/libpthread.so.0
#22 0x00000031ee6d1e3d in clone () from /lib64/libc.so.6
[9 Feb 2011 2:53] Yasufumi Kinoshita
Sorry, it was my miss to trace.
Thanks you.