midenok / mariadb

MariaDB server is a community developed fork of MySQL server. Started by core members of the original MySQL team, MariaDB actively works with outside developers to deliver the most featureful, stable, and sanely licensed open SQL server in the industry.
GNU General Public License v2.0
0 stars 0 forks source link

MDEV-22061 InnoDB: Assertion of missing row in sec index row_start upon REPLACE on a system-versioned table #75

Open midenok opened 4 years ago

midenok commented 4 years ago

Reproduce

--source include/have_innodb.inc

create or replace table t1 (
  a int,
  b int,
  row_start bigint(20) unsigned generated always as row start,
  row_end bigint(20) unsigned generated always as row end,
  unique key (b,row_end),
  key (row_start),
  period for system_time (row_start,row_end)
) engine=innodb with system versioning;

insert into t1 (a, b) values (1, 2);
replace into t1 (a, b) values (3, 2);
replace into t1 (a, b) values (4, 2);

# cleanup
drop table t1;

Result

#3  0x00007fe11af8e006 in __GI___assert_fail (assertion=0x174da80 "btr_validate_index(index, 0, false)", file=0x174c460 "/home/midenok/src/mariadb/10.3/src/storage/innobase/row/row0upd.cc", line=2443, function=0x174d9f4 "dberr_t row_upd_sec_index_entry(upd_node_t *, que_thr_t *)") at assert.c:101
#4  0x0000000000ff8d50 in row_upd_sec_index_entry (node=0x7fe0a802c8b8, thr=0x7fe0a802cc20) at /home/midenok/src/mariadb/10.3/src/storage/innobase/row/row0upd.cc:2443
#5  0x0000000000ff35ed in row_upd_sec_step (node=0x7fe0a802c8b8, thr=0x7fe0a802cc20) at /home/midenok/src/mariadb/10.3/src/storage/innobase/row/row0upd.cc:2567
#6  0x0000000000fef8c7 in row_upd (node=0x7fe0a802c8b8, thr=0x7fe0a802cc20) at /home/midenok/src/mariadb/10.3/src/storage/innobase/row/row0upd.cc:3336
#7  0x0000000000fef175 in row_upd_step (thr=0x7fe0a802cc20) at /home/midenok/src/mariadb/10.3/src/storage/innobase/row/row0upd.cc:3451
#8  0x0000000000f73c21 in row_update_for_mysql (prebuilt=0x7fe0a802bd60) at /home/midenok/src/mariadb/10.3/src/storage/innobase/row/row0mysql.cc:1888
#9  0x0000000000d98cde in ha_innobase::update_row (this=0x7fe0a801a770, old_row=0x7fe0a801aed8 "\241\003", new_row=0x7fe0a801aeb8 "\371\004") at /home/midenok/src/mariadb/10.3/src/storage/innobase/handler/ha_innodb.cc:8826
#10 0x0000000000b18cac in handler::ha_update_row (this=0x7fe0a801a770, old_data=0x7fe0a801aed8 "\241\003", new_data=0x7fe0a801aeb8 "\371\004") at /home/midenok/src/mariadb/10.3/src/sql/handler.cc:6498
#11 0x000000000074b2f5 in write_record (thd=0x7fe0a8000d28, table=0x7fe0a802b128, info=0x7fe0f405b720) at /home/midenok/src/mariadb/10.3/src/sql/sql_insert.cc:1953
#12 0x0000000000747811 in mysql_insert (thd=0x7fe0a8000d28, table_list=0x7fe0a8013d08, fields=..., values_list=..., update_fields=..., update_values=..., duplic=DUP_REPLACE, ignore=false) at /home/midenok/src/mariadb/10.3/src/sql/sql_insert.cc:1072
#13 0x0000000000798ab5 in mysql_execute_command (thd=0x7fe0a8000d28) at /home/midenok/src/mariadb/10.3/src/sql/sql_parse.cc:4454
#14 0x0000000000790de0 in mysql_parse (thd=0x7fe0a8000d28, rawbuf=0x7fe0a8013c10 "replace into t1 (a, b) values (4, 2)", length=36, parser_state=0x7fe0f405e5e8, is_com_multi=false, is_next_command=false) at /home/midenok/src/mariadb/10.3/src/sql/sql_parse.cc:7818

frame 4

2416            case ROW_NOT_FOUND:
....
2435                    ib::error()
2436                            << "Record in index " << index->name
2437                            << " of table " << index->table->name
2438                            << " was not found on update: " << *entry
2439                            << " at: " << rec_index_print(rec, index);
2440    #ifdef UNIV_DEBUG
2441                    mtr_commit(&mtr);
2442                    mtr_start(&mtr);
2443                    ut_ad(btr_validate_index(index, 0, false));
2444                    ut_ad(0);
(rr) p rec_print(stdout, rec, index)
PHYSICAL RECORD: n_fields 2; compact format; info bits 0
 0: len 8; hex 0000000000000024; asc        $;;
 1: len 6; hex 000000000202; asc       ;;
(rr) p index->name.m_name
$3 = 0x7fe0a8020a40 "row_start"
midenok commented 4 years ago

1-st REPLACE

break mysql_parse
  commands
    btc
  end
break row_ins_sec_index_entry
  condition $bpnum 0 == strcmp(index.name.m_name, "row_start")
  commands
    p dtuple_print(stdout, entry)
    c
  end
disable $bpnum
break row_upd_sec_step
  condition $bpnum 0 == strcmp(node->index.name.m_name, "row_start")
  commands
    p dtuple_print(stdout, node->row)
    p dtuple_print(stdout, node->upd_row)
    c
  end
disable $bpnum

Result

Thread 2 hit Breakpoint 5, row_upd_sec_step (node=0x7fe0a802c8b8, thr=0x7fe0a802cc20) at /home/midenok/src/mariadb/10.3/src/storage/innobase/row/row0upd.cc:2560
2560            ut_ad((node->state == UPD_NODE_UPDATE_ALL_SEC)
DATA TUPLE: 7 fields;
 0: len 4; hex 80000001; asc     ;;
 1: len 4; hex 80000002; asc     ;;
 2: len 8; hex 0000000000000024; asc        $;;
 3: len 8; hex ffffffffffffffff; asc         ;;
 4: len 6; hex 000000000200; asc       ;;
 5: len 6; hex 000000000024; asc      $;;
 6: len 7; hex 830000013702c3; asc     7  ;;
$4 = void
DATA TUPLE: 7 fields;
 0: len 4; hex 80000003; asc     ;;
 1: len 4; hex 80000002; asc     ;;
 2: len 8; hex 0000000000000000; asc         ;;
 3: len 8; hex ffffffffffffffff; asc         ;;
 4: len 6; hex 000000000200; asc       ;;
 5: len 6; hex 000000000024; asc      $;;
 6: len 7; hex 830000013702c3; asc     7  ;;
$5 = void

Thread 2 hit Breakpoint 4, row_ins_sec_index_entry (index=0x7fe0a801ff30, entry=0x7fe0a80366d0, thr=0x7fe0a802cc20, check_foreign=true) at /home/midenok/src/mariadb/10.3/src/storage/innobase/row/row0ins.cc:3234
3234            trx_id_t        trx_id  = 0;
DATA TUPLE: 2 fields;
 0: len 8; hex 0000000000000000; asc         ;;
 1: len 6; hex 000000000200; asc       ;;
$6 = void

Thread 2 hit Breakpoint 4, row_ins_sec_index_entry (index=0x7fe0a801ff30, entry=0x7fe0a801c3c0, thr=0x7fe0a802c588, check_foreign=true) at /home/midenok/src/mariadb/10.3/src/storage/innobase/row/row0ins.cc:3234
3234            trx_id_t        trx_id  = 0;
DATA TUPLE: 2 fields;
 0: len 8; hex 0000000000000024; asc        $;;
 1: len 6; hex 000000000202; asc       ;;
$7 = void

Cause

First row_upd_sec_step() and row_ins_sec_index_entry() have 0 in row_start field.

midenok commented 4 years ago

Update field for row_start added to update vector

#0  upd_node_t::make_versioned_helper (this=0x7fe0a802c8b8, trx=0x7fe115a3d0e8, idx=2) at /home/midenok/src/mariadb/10.3/src/storage/innobase/row/row0upd.cc:3514
#1  0x0000000000f8403a in upd_node_t::make_versioned_update (this=0x7fe0a802c8b8, trx=0x7fe115a3d0e8) at /home/midenok/src/mariadb/10.3/src/storage/innobase/include/row0upd.h:597
#2  0x0000000000f73bd8 in row_update_for_mysql (prebuilt=0x7fe0a802bd60) at /home/midenok/src/mariadb/10.3/src/storage/innobase/row/row0mysql.cc:1879
#3  0x0000000000d98cde in ha_innobase::update_row (this=0x7fe0a801a770, old_row=0x7fe0a801aed8 "\241\001", new_row=0x7fe0a801aeb8 "\371\003") at /home/midenok/src/mariadb/10.3/src/storage/innobase/handler/ha_innodb.cc:8826
#4  0x0000000000b18cac in handler::ha_update_row (this=0x7fe0a801a770, old_data=0x7fe0a801aed8 "\241\001", new_data=0x7fe0a801aeb8 "\371\003") at /home/midenok/src/mariadb/10.3/src/sql/handler.cc:6498
#5  0x000000000074b2f5 in write_record (thd=0x7fe0a8000d28, table=0x7fe0a802b128, info=0x7fe0f405b720) at /home/midenok/src/mariadb/10.3/src/sql/sql_insert.cc:1953
#6  0x0000000000747811 in mysql_insert (thd=0x7fe0a8000d28, table_list=0x7fe0a8013d08, fields=..., values_list=..., update_fields=..., update_values=..., duplic=DUP_REPLACE, ignore=false) at /home/midenok/src/mariadb/10.3/src/sql/sql_insert.cc:1072
#7  0x0000000000798ab5 in mysql_execute_command (thd=0x7fe0a8000d28) at /home/midenok/src/mariadb/10.3/src/sql/sql_parse.cc:4454
#8  0x0000000000790de0 in mysql_parse (thd=0x7fe0a8000d28, rawbuf=0x7fe0a8013c10 "replace into t1 (a, b) values (3, 2)", length=36, parser_state=0x7fe0f405e5e8, is_com_multi=false, is_next_command=false) at /home/midenok/src/mariadb/10.3/src/sql/sql_parse.cc:7818
3488    void upd_node_t::make_versioned_helper(const trx_t* trx, ulint idx)
3489    {
3490            ut_ad(in_mysql_interface); // otherwise needs to recalculate
3491                                       // node->cmpl_info
3492            ut_ad(idx == table->vers_start || idx == table->vers_end);
3493
3494            dict_index_t* clust_index = dict_table_get_first_index(table);
3495
3496            /* row_create_update_node_for_mysql() pre-allocated this much.
3497               At least one PK column always remains unchanged. */
3498            ut_ad(update->n_fields < ulint(table->n_cols + table->n_v_cols));
3499
3500            update->n_fields++;
3501            upd_field_t* ufield = upd_get_nth_field(update, update->n_fields - 1);
3502            const dict_col_t* col = dict_table_get_nth_col(table, idx);
3503
3504            upd_field_set_field_no(ufield, dict_col_get_clust_pos(col, clust_index),
3505                                   clust_index);
3506
3507            char* where = reinterpret_cast<char*>(update->vers_sys_value);
3508            if (col->vers_native()) {
3509                    mach_write_to_8(where, trx->id);
3510            } else {
3511                    thd_get_query_start_data(trx->mysql_thd, where);
3512            }
3513
3514            dfield_set_data(&ufield->new_val, update->vers_sys_value, col->len);
3515    }
(rr) x/8bx update->vers_sys_value
0x7fe0a802ca08: 0x00    0x00    0x00    0x00    0x00    0x00    0x00    0x27
(rr) p *ufield
$26 = {
  field_no = 5,
  orig_len = 0,
  exp = 0x0,
  new_val = {
    data = 0x7fe0a802ca08,
    ext = 0,
    spatial_status = 0,
    len = 8,
    type = {
      prtype = 18184,
      mtype = 6,
      len = 8,
      mbminlen = 0,
      mbmaxlen = 0
    }
  },
  old_v_val = 0x0
}
(rr) p ufield
$14 = (upd_field_t *) 0x7fe0a802ca70
(rr) p &update->fields[2]
$15 = (upd_field_t *) 0x7fe0a802ca70
(rr) p update
$16 = (upd_t *) 0x7fe0a802c9e0
(rr) p this
$17 = (upd_node_t *) 0x7fe0a802c8b8
(rr) p this->update
$18 = (upd_t *) 0x7fe0a802c9e0
midenok commented 4 years ago
#0  row_upd_sec_step (node=0x7fe0a802c8b8, thr=0x7fe0a802cc20) at /home/midenok/src/mariadb/10.3/src/storage/innobase/row/row0upd.cc:2560
#1  0x0000000000fef8c7 in row_upd (node=0x7fe0a802c8b8, thr=0x7fe0a802cc20) at /home/midenok/src/mariadb/10.3/src/storage/innobase/row/row0upd.cc:3336
#2  0x0000000000fef175 in row_upd_step (thr=0x7fe0a802cc20) at /home/midenok/src/mariadb/10.3/src/storage/innobase/row/row0upd.cc:3451
#3  0x0000000000f73c21 in row_update_for_mysql (prebuilt=0x7fe0a802bd60) at /home/midenok/src/mariadb/10.3/src/storage/innobase/row/row0mysql.cc:1888
#4  0x0000000000d98cde in ha_innobase::update_row (this=0x7fe0a801a770, old_row=0x7fe0a801aed8 "\241\001", new_row=0x7fe0a801aeb8 "\371\003") at /home/midenok/src/mariadb/10.3/src/storage/innobase/handler/ha_innodb.cc:8826
#5  0x0000000000b18cac in handler::ha_update_row (this=0x7fe0a801a770, old_data=0x7fe0a801aed8 "\241\001", new_data=0x7fe0a801aeb8 "\371\003") at /home/midenok/src/mariadb/10.3/src/sql/handler.cc:6498
#6  0x000000000074b2f5 in write_record (thd=0x7fe0a8000d28, table=0x7fe0a802b128, info=0x7fe0f405b720) at /home/midenok/src/mariadb/10.3/src/sql/sql_insert.cc:1953
#7  0x0000000000747811 in mysql_insert (thd=0x7fe0a8000d28, table_list=0x7fe0a8013d08, fields=..., values_list=..., update_fields=..., update_values=..., duplic=DUP_REPLACE, ignore=false) at /home/midenok/src/mariadb/10.3/src/sql/sql_insert.cc:1072
#8  0x0000000000798ab5 in mysql_execute_command (thd=0x7fe0a8000d28) at /home/midenok/src/mariadb/10.3/src/sql/sql_parse.cc:4454
#9  0x0000000000790de0 in mysql_parse (thd=0x7fe0a8000d28, rawbuf=0x7fe0a8013c10 "replace into t1 (a, b) values (3, 2)", length=36, parser_state=0x7fe0f405e5e8, is_com_multi=false, is_next_command=false) at /home/midenok/src/mariadb/10.3/src/sql/sql_parse.cc:7818
(rr) call dtuple_print(stdout, node->upd_row)
DATA TUPLE: 7 fields;
 0: len 4; hex 80000003; asc     ;;
 1: len 4; hex 80000002; asc     ;;
 2: len 8; hex 0000000000000000; asc         ;;
 3: len 8; hex ffffffffffffffff; asc         ;;
 4: len 6; hex 000000000200; asc       ;;
 5: len 6; hex 000000000024; asc      $;;
 6: len 7; hex 830000013702c3; asc     7  ;;
(rr) p node->upd_row->fields[2]
$21 = {
  data = 0x7fe0a803ba0c,
  ext = 0,
  spatial_status = 0,
  len = 8,
  type = {
    prtype = 18184,
    mtype = 6,
    len = 8,
    mbminlen = 0,
    mbmaxlen = 0
  }
}
(rr) p &node->upd_row->fields[2]
$22 = (dfield_t *) 0x7fe0a801d998
(rr) p node->upd_row
$23 = (dtuple_t *) 0x7fe0a801d930
(rr) p node
$24 = (upd_node_t *) 0x7fe0a802c8b8

Cause

data for node->update and node->upd_row is different.

midenok commented 4 years ago

Data copied to upd_row

#0  0x0000000000fec9d2 in dfield_copy_data (field1=0x7fe0a801d998, field2=0x7fe0a802ca50) at /home/midenok/src/mariadb/10.3/src/storage/innobase/include/data0data.ic:153
#1  0x0000000000fed3e5 in row_upd_replace (row=0x7fe0a801d930, ext=0x7fe0a802c9b8, index=0x7fe0a801e9e0, update=0x7fe0a802c9e0, heap=0x7fe0a801c600) at /home/midenok/src/mariadb/10.3/src/storage/innobase/row/row0upd.cc:1634
#2  0x0000000000ff4c66 in row_upd_store_row (node=0x7fe0a802c8b8, thd=0x7fe0a8000d28, mysql_table=0x7fe0a802b128) at /home/midenok/src/mariadb/10.3/src/storage/innobase/row/row0upd.cc:2268
#3  0x0000000000ff3139 in row_upd_clust_step (node=0x7fe0a802c8b8, thr=0x7fe0a802cc20) at /home/midenok/src/mariadb/10.3/src/storage/innobase/row/row0upd.cc:3211
#4  0x0000000000fef662 in row_upd (node=0x7fe0a802c8b8, thr=0x7fe0a802cc20) at /home/midenok/src/mariadb/10.3/src/storage/innobase/row/row0upd.cc:3307
#5  0x0000000000fef175 in row_upd_step (thr=0x7fe0a802cc20) at /home/midenok/src/mariadb/10.3/src/storage/innobase/row/row0upd.cc:3451
#6  0x0000000000f73c21 in row_update_for_mysql (prebuilt=0x7fe0a802bd60) at /home/midenok/src/mariadb/10.3/src/storage/innobase/row/row0mysql.cc:1888
#7  0x0000000000d98cde in ha_innobase::update_row (this=0x7fe0a801a770, old_row=0x7fe0a801aed8 "\241\001", new_row=0x7fe0a801aeb8 "\371\003") at /home/midenok/src/mariadb/10.3/src/storage/innobase/handler/ha_innodb.cc:8826
#8  0x0000000000b18cac in handler::ha_update_row (this=0x7fe0a801a770, old_data=0x7fe0a801aed8 "\241\001", new_data=0x7fe0a801aeb8 "\371\003") at /home/midenok/src/mariadb/10.3/src/sql/handler.cc:6498
#9  0x000000000074b2f5 in write_record (thd=0x7fe0a8000d28, table=0x7fe0a802b128, info=0x7fe0f405b720) at /home/midenok/src/mariadb/10.3/src/sql/sql_insert.cc:1953
#10 0x0000000000747811 in mysql_insert (thd=0x7fe0a8000d28, table_list=0x7fe0a8013d08, fields=..., values_list=..., update_fields=..., update_values=..., duplic=DUP_REPLACE, ignore=false) at /home/midenok/src/mariadb/10.3/src/sql/sql_insert.cc:1072
#11 0x0000000000798ab5 in mysql_execute_command (thd=0x7fe0a8000d28) at /home/midenok/src/mariadb/10.3/src/sql/sql_parse.cc:4454
#12 0x0000000000790de0 in mysql_parse (thd=0x7fe0a8000d28, rawbuf=0x7fe0a8013c10 "replace into t1 (a, b) values (3, 2)", length=36, parser_state=0x7fe0f405e5e8, is_com_multi=false, is_next_command=false) at /home/midenok/src/mariadb/10.3/src/sql/sql_parse.cc:7818
1623                    for (i = 0; i < upd_get_n_fields(update); i++) {
1624
1625                            const upd_field_t*      upd_field
1626                                    = upd_get_nth_field(update, i);
1627
1628                            if (upd_field->field_no != clust_pos
1629                                || upd_fld_is_virtual_col(upd_field)) {
1630
1631                                    continue;
1632                            }
1633
1634                            dfield_copy_data(dfield, &upd_field->new_val);
1635                            break;
1636                    }
(rr) p upd_field
$30 = (const upd_field_t *) 0x7fe0a802ca40
(rr) p *upd_field
$31 = {
  field_no = 5,
  orig_len = 0,
  exp = 0x0,
  new_val = {
    data = 0x7fe0a803ba0c,
    ext = 0,
    spatial_status = 0,
    len = 8,
    type = {
      prtype = 18184,
      mtype = 6,
      len = 8,
      mbminlen = 0,
      mbmaxlen = 0
    }
  },
  old_v_val = 0x0
}
(rr) p update
$32 = (const upd_t *) 0x7fe0a802c9e0
(rr) p i
$36 = 1
(rr) p update->fields[1]
$37 = {
  field_no = 5,
  orig_len = 0,
  exp = 0x0,
  new_val = {
    data = 0x7fe0a803ba0c,
    ext = 0,
    spatial_status = 0,
    len = 8,
    type = {
      prtype = 18184,
      mtype = 6,
      len = 8,
      mbminlen = 0,
      mbmaxlen = 0
    }
  },
  old_v_val = 0x0
}
(rr) p update->fields[2]
$38 = {
  field_no = 5,
  orig_len = 0,
  exp = 0x0,
  new_val = {
    data = 0x7fe0a802ca08,
    ext = 0,
    spatial_status = 0,
    len = 8,
    type = {
      prtype = 18184,
      mtype = 6,
      len = 8,
      mbminlen = 0,
      mbmaxlen = 0
    }
  },
  old_v_val = 0x0
}

Cause

We appended new upd_field to update vector while we ought to modify existing one.