[MDEV-29603] btr_cur_open_at_index_side() is missing some consistency checks Created: 2022-09-22  Updated: 2023-07-24  Resolved: 2022-11-17

Status: Closed
Project: MariaDB Server
Component/s: Storage Engine - InnoDB
Affects Version/s: 10.3, 10.4, 10.5, 10.6, 10.7, 10.8, 10.9, 10.10
Fix Version/s: 10.11.2, 10.6.12, 10.7.8, 10.8.7, 10.9.5, 10.10.3

Type: Bug Priority: Critical
Reporter: Marko Mäkelä Assignee: Marko Mäkelä
Resolution: Fixed Votes: 0
Labels: corruption

Issue Links:
Blocks
is blocked by MDEV-13542 Crashing on a corrupted page is unhel... Closed
Problem/Incident
causes MDEV-30289 mtr_t::m_memo is causing frequent mem... Closed
causes MDEV-30524 btr_cur_t::open_leaf() opens non-leaf... Closed
causes MDEV-31120 Duplicate entry allowed into a UNIQUE... Closed

 Description   

In MDEV-13542, many sources of crash on a corrupted page were fixed, but something in the function btr_cur_open_at_index_side() was missed.

		if (height == ULINT_UNDEFINED) {
			/* We are in the root node */
 
			height = btr_page_get_level(page);
			ut_a(height >= level);

This assertion could fail if a nonzero parameter level was supplied to the function. That is only the case when the inline wrapper function btr_pcur_open_at_index_side() is invoked with level>0, which in turn is only possible in the following functions, related to InnoDB persistent statistics:

  • dict_stats_analyze_index_level()
  • dict_stats_analyze_index_for_n_prefix()

It would seem to make sense to remove the parameter level from the normal functions, and to write a special function that would be used when computing persistent statistics.

Furthermore, btr_cur_open_at_index_side() currently fails to return DB_CORRUPTION on PAGE_LEVEL mismatch or when from_left ? !page_has_prev(page) : !page_has_next(page) does not hold.



 Comments   
Comment by Matthias Leich [ 2022-11-03 ]

Dominant bad effect
mysqld: /data/Server/bb-10.6-MDEV-29603/storage/innobase/dict/dict0dict.cc:3739: ulint dict_index_check_search_tuple(const dict_index_t*, const dtuple_t*): Assertion `dtuple_get_n_fields_cmp(tuple) <= dict_index_get_n_unique_in_tree(index)' failed.
(rr) bt
#0  __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50
#1  0x00007faaee4ea859 in __GI_abort () at abort.c:79
#2  0x00007faaee4ea729 in __assert_fail_base (fmt=0x7faaee680588 "%s%s%s:%u: %s%sAssertion `%s' failed.\n%n", assertion=0x556529ac46c0 "dtuple_get_n_fields_cmp(tuple) <= dict_index_get_n_unique_in_tree(index)", 
    file=0x556529ac0320 "/data/Server/bb-10.6-MDEV-29603/storage/innobase/dict/dict0dict.cc", line=3739, function=<optimized out>) at assert.c:92
#3  0x00007faaee4fbf36 in __GI___assert_fail (assertion=assertion@entry=0x556529ac46c0 "dtuple_get_n_fields_cmp(tuple) <= dict_index_get_n_unique_in_tree(index)", 
    file=file@entry=0x556529ac0320 "/data/Server/bb-10.6-MDEV-29603/storage/innobase/dict/dict0dict.cc", line=line@entry=3739, 
    function=function@entry=0x556529ac4740 "ulint dict_index_check_search_tuple(const dict_index_t*, const dtuple_t*)") at assert.c:101
#4  0x0000556528d67266 in dict_index_check_search_tuple (index=index@entry=0x616002586a08, tuple=tuple@entry=0x62d0012fc9b0) at /data/Server/bb-10.6-MDEV-29603/storage/innobase/include/data0data.inl:253
#5  0x0000556528c473f9 in btr_cur_search_to_nth_level (level=level@entry=0, tuple=tuple@entry=0x62d0012fc9b0, mode=mode@entry=PAGE_CUR_LE, latch_mode=latch_mode@entry=BTR_MODIFY_TREE, cursor=cursor@entry=0x7faacb5a0630, 
    mtr=mtr@entry=0x7faacb5a0d50, autoinc=<optimized out>) at /data/Server/bb-10.6-MDEV-29603/storage/innobase/btr/btr0cur.cc:1293
#6  0x0000556528a29bad in btr_pcur_open (mtr=0x7faacb5a0d50, autoinc=0, cursor=0x7faacb5a0630, latch_mode=BTR_MODIFY_TREE, mode=PAGE_CUR_LE, tuple=0x62d0012fc9b0)
    at /data/Server/bb-10.6-MDEV-29603/storage/innobase/include/btr0pcur.inl:325
#7  row_search_index_entry (entry=entry@entry=0x62d0012fc9b0, mode=mode@entry=BTR_MODIFY_TREE, pcur=pcur@entry=0x7faacb5a0630, mtr=mtr@entry=0x7faacb5a0d50) at /data/Server/bb-10.6-MDEV-29603/storage/innobase/row/row0row.cc:1286
#8  0x00005565289dce57 in row_log_table_apply_update (thr=thr@entry=0x619002a3b0c0, new_trx_id_col=new_trx_id_col@entry=1, mrec=mrec@entry=0x7faac6995198 "", offsets=offsets@entry=0x60400007e690, 
    offsets_heap=offsets_heap@entry=0x62d0013ce400, heap=heap@entry=0x62d0012fc400, dup=<optimized out>, old_pk=<optimized out>) at /data/Server/bb-10.6-MDEV-29603/storage/innobase/row/row0log.cc:2095
#9  0x00005565289def22 in row_log_table_apply_op (thr=thr@entry=0x619002a3b0c0, new_trx_id_col=new_trx_id_col@entry=1, dup=dup@entry=0x7faacb5a1c20, error=error@entry=0x7faacb5a1510, 
    offsets_heap=offsets_heap@entry=0x62d0013ce400, heap=heap@entry=0x62d0012fc400, mrec=0x7faac6995198 "", mrec_end=<optimized out>, offsets=<optimized out>)
    at /data/Server/bb-10.6-MDEV-29603/storage/innobase/row/row0log.cc:2392
#10 0x00005565289e3c4b in row_log_table_apply_ops (thr=thr@entry=0x619002a3b0c0, dup=dup@entry=0x7faacb5a1c20, stage=stage@entry=0x6020004f14f0) at /data/Server/bb-10.6-MDEV-29603/storage/innobase/row/row0log.cc:2762
#11 0x00005565289e49ff in row_log_table_apply (thr=0x619002a3b0c0, old_table=<optimized out>, table=table@entry=0x7faacb5a34a0, stage=<optimized out>, new_table=<optimized out>)
    at /data/Server/bb-10.6-MDEV-29603/storage/innobase/row/row0log.cc:2870
#12 0x000055652865fa9b in ha_innobase::inplace_alter_table (this=0x61d000461eb8, altered_table=<optimized out>, ha_alter_info=0x7faacb5a2da0) at /data/Server/bb-10.6-MDEV-29603/storage/innobase/handler/handler0alter.cc:8666
#13 0x00005565275fa1a6 in handler::ha_inplace_alter_table (ha_alter_info=0x7faacb5a2da0, altered_table=0x7faacb5a34a0, this=<optimized out>) at /data/Server/bb-10.6-MDEV-29603/sql/handler.h:4676
#14 mysql_inplace_alter_table (thd=thd@entry=0x62b0001ff218, table_list=<optimized out>, table=table@entry=0x619002b03998, altered_table=<optimized out>, ha_alter_info=0x7faacb5a2da0, target_mdl_request=<optimized out>, 
    ddl_log_state=<optimized out>, trigger_param=<optimized out>, alter_ctx=<optimized out>) at /data/Server/bb-10.6-MDEV-29603/sql/sql_table.cc:7420
#15 0x00005565276311e4 in mysql_alter_table (thd=thd@entry=0x62b0001ff218, new_db=new_db@entry=0x62b000203c48, new_name=new_name@entry=0x62b000204060, create_info=0x7faacb5a5820, table_list=<optimized out>, 
    table_list@entry=0x62b0002063d0, alter_info=<optimized out>, order_num=<optimized out>, order=<optimized out>, ignore=<optimized out>, if_exists=<optimized out>) at /data/Server/bb-10.6-MDEV-29603/sql/sql_table.cc:10335
#16 0x00005565277b9c7b in Sql_cmd_alter_table::execute (this=<optimized out>, thd=0x62b0001ff218) at /data/Server/bb-10.6-MDEV-29603/sql/structs.h:568
#17 0x0000556527382bc1 in mysql_execute_command (thd=thd@entry=0x62b0001ff218, is_called_from_prepared_stmt=is_called_from_prepared_stmt@entry=false) at /data/Server/bb-10.6-MDEV-29603/sql/sql_parse.cc:5997
#18 0x0000556527339d24 in mysql_parse (thd=thd@entry=0x62b0001ff218, rawbuf=<optimized out>, length=<optimized out>, parser_state=parser_state@entry=0x7faacb5a7130) at /data/Server/bb-10.6-MDEV-29603/sql/sql_parse.cc:8016
#19 0x00005565273682d1 in dispatch_command (command=command@entry=COM_QUERY, thd=thd@entry=0x62b0001ff218, 
    packet=packet@entry=0x62900185b219 "ALTER TABLE `t6` PAGE_COMPRESSED=0 ENCRYPTION_KEY_ID=2 /* E_R Thread20 QNO 8 CON_ID 35 */ ", packet_length=packet_length@entry=90, blocking=blocking@entry=true)
    at /data/Server/bb-10.6-MDEV-29603/sql/sql_class.h:1362
#20 0x000055652736efb8 in do_command (thd=0x62b0001ff218, blocking=blocking@entry=true) at /data/Server/bb-10.6-MDEV-29603/sql/sql_parse.cc:1409
#21 0x00005565277a2fdd in do_handle_one_connection (connect=<optimized out>, connect@entry=0x608000003838, put_in_cache=put_in_cache@entry=true) at /data/Server/bb-10.6-MDEV-29603/sql/sql_connect.cc:1416
#22 0x00005565277a3b26 in handle_one_connection (arg=0x608000003838) at /data/Server/bb-10.6-MDEV-29603/sql/sql_connect.cc:1318
#23 0x00007faaeea12609 in start_thread (arg=<optimized out>) at pthread_create.c:477
#24 0x00007faaee5e7293 in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:95
(rr)
pluto:/data/results/1667480093/TBR-562$ _RR_TRACE_DIR=./1/rr/ rr replay --mark-stdio
 
The bad effect TBR-562 was observed first time April 2020 and last time before December 2020.
 

Comment by Marko Mäkelä [ 2022-11-04 ]

In row_log_table_update(), we are creating a search tuple for a secondary index, but the cursor that is passed to btr_pcur_open() points to the clustered index of the table. The branch contains many changes related to iterating B-trees, including some that may ultimately be part of MDEV-29835 rather than this ticket. Previously, several pointers to an index were being passed to btr_pcur_open(). When I removed the redundant function parameter and the redundant data member btr_cur_t::index, I forgot to assign page_cur_t::index in this code path.

Comment by Marko Mäkelä [ 2022-11-04 ]

I am working on a change that simplifies the way how dict_stats_analyze_index() works. That is the only user of code that needs to open the first or last page at a specific tree level, actually always the first page, and always S-latched. This will depend on the ability of mtr_t::rollback_to_savepoint() to shrink the mtr_t::m_memo, or on a new operation that will rollback to savepoint everything but the last object (that is, release all upper page latches, but retain the index latch and one page latch).

I already refactored mtr_t::m_memo to use std::vector instead of the homebrew mtr_buf_t. That change should also be helpful in a reimplementation of the B-tree cursor operations in MDEV-29835.

Comment by Marko Mäkelä [ 2022-11-17 ]

The function btr_cur_open_at_index_side() was replaced with btr_cur_t::open_leaf() and a statistics-specific function page_cur_open_level(). Some redundant parameters around InnoDB cursor opeartions and the redundant data member btr_cur_t::index were removed, mtr_t::m_memo was replaced with std::vector and many operations related to mtr_t::m_memo were simplified.

Thanks to mleich for testing and vlad.lesin for reviewing the changes. This paves the way to fix MDEV-29835.

Generated at Thu Feb 08 10:09:53 UTC 2024 using Jira 8.20.16#820016-sha1:9d11dbea5f4be3d4cc21f03a88dd11d8c8687422.