diff options
author | Eugene Kosov <claprix@yandex.ru> | 2019-09-23 16:26:44 +0300 |
---|---|---|
committer | Eugene Kosov <claprix@yandex.ru> | 2019-09-27 11:12:44 +0300 |
commit | 77279bf00054dd77814eaafd00afcef1e65859d4 (patch) | |
tree | daa3001e80cb76fcb9e31f11449e4afe0f95c337 | |
parent | 1f4ee3fa5a80e9715b0dc77b72fabb95a4045745 (diff) | |
download | mariadb-git-bb-10.4-MDEV-20117.tar.gz |
MDEV-20117 Assertion `0' failed in row_sel_get_clust_rec_for_mysqlbb-10.4-MDEV-20117
Test does UPDATE -> DELETE -> ALTER DROP COLUMNS
Crash happens when:
purge thread deletes index record ->
ALTER ->
purge thread deletes undo record for UPDATE but index now has fewer
columns than expected
The idea of the fix is to prevent converting instant index to plain index
when it's empty.
innobase_alter_try(): remove one empty_table code path. DBUG_EXECUTE_IF() was
added to skip delete marked records which is needed for reliable and
reproducible test.
btr_pcur_store_position(): removed assertion which became invalid in this patch.
-rw-r--r-- | mysql-test/suite/innodb/r/instant_alter_debug.result | 18 | ||||
-rw-r--r-- | mysql-test/suite/innodb/t/instant_alter_debug.test | 24 | ||||
-rw-r--r-- | storage/innobase/btr/btr0pcur.cc | 1 | ||||
-rw-r--r-- | storage/innobase/handler/handler0alter.cc | 27 |
4 files changed, 58 insertions, 12 deletions
diff --git a/mysql-test/suite/innodb/r/instant_alter_debug.result b/mysql-test/suite/innodb/r/instant_alter_debug.result index 7ab24a7671b..65a9eddf582 100644 --- a/mysql-test/suite/innodb/r/instant_alter_debug.result +++ b/mysql-test/suite/innodb/r/instant_alter_debug.result @@ -327,4 +327,22 @@ FROM information_schema.global_status WHERE variable_name = 'innodb_instant_alter_column'; instants 22 +# +# MDEV-20117 Assertion `0' failed in row_sel_get_clust_rec_for_mysql +# +CREATE TABLE t1 (a INT PRIMARY KEY, b INT, c INT, d INT, e INT) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1, NULL, NULL, NULL, NULL); +connect purge_control,localhost,root; +START TRANSACTION WITH CONSISTENT SNAPSHOT; +connection default; +UPDATE t1 SET b=1; +DELETE FROM t1; +SET DEBUG_DBUG = '+d,innodb_test_MDEV-20117'; +ALTER TABLE t1 DROP b, DROP c, DROP d, DROP e; +disconnect purge_control; +InnoDB 0 transactions not purged +SELECT * FROM t1; +a +DROP TABLE t1; +SET DEBUG_DBUG = 'RESET'; SET GLOBAL innodb_purge_rseg_truncate_frequency = @save_frequency; diff --git a/mysql-test/suite/innodb/t/instant_alter_debug.test b/mysql-test/suite/innodb/t/instant_alter_debug.test index 267e2a2c22d..e5da032f3fd 100644 --- a/mysql-test/suite/innodb/t/instant_alter_debug.test +++ b/mysql-test/suite/innodb/t/instant_alter_debug.test @@ -260,6 +260,7 @@ connection default; SET DEBUG_SYNC = 'now WAIT_FOR copied'; let $wait_all_purged = 1; --source include/wait_all_purged.inc +let $wait_all_purged = 0; INSERT INTO t1 SET a=1; INSERT INTO t1 SET a=2,c=4; SET DEBUG_SYNC = 'now SIGNAL logged'; @@ -361,4 +362,27 @@ SELECT variable_value-@old_instant instants FROM information_schema.global_status WHERE variable_name = 'innodb_instant_alter_column'; + +--echo # +--echo # MDEV-20117 Assertion `0' failed in row_sel_get_clust_rec_for_mysql +--echo # + +CREATE TABLE t1 (a INT PRIMARY KEY, b INT, c INT, d INT, e INT) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1, NULL, NULL, NULL, NULL); + +connect (purge_control,localhost,root); +START TRANSACTION WITH CONSISTENT SNAPSHOT; +connection default; + +UPDATE t1 SET b=1; +DELETE FROM t1; +SET DEBUG_DBUG = '+d,innodb_test_MDEV-20117'; +ALTER TABLE t1 DROP b, DROP c, DROP d, DROP e; +disconnect purge_control; + +--source include/wait_all_purged.inc +SELECT * FROM t1; +DROP TABLE t1; +SET DEBUG_DBUG = 'RESET'; + SET GLOBAL innodb_purge_rseg_truncate_frequency = @save_frequency; diff --git a/storage/innobase/btr/btr0pcur.cc b/storage/innobase/btr/btr0pcur.cc index a66fcc15187..2862c6ab0b3 100644 --- a/storage/innobase/btr/btr0pcur.cc +++ b/storage/innobase/btr/btr0pcur.cc @@ -151,7 +151,6 @@ before_first: ut_ad(!page_rec_is_infimum(rec)); if (UNIV_UNLIKELY(rec_is_metadata(rec, *index))) { - ut_ad(index->table->instant); ut_ad(page_get_n_recs(block->frame) == 1); ut_ad(page_is_leaf(block->frame)); ut_ad(page_get_page_no(block->frame) == index->page); diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index ab3ec7ba249..00dbcce528f 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -5809,6 +5809,13 @@ add_all_virtual: ut_ad(btr_pcur_is_before_first_on_page(&pcur)); btr_pcur_move_to_next_on_page(&pcur); + DBUG_EXECUTE_IF( + "innodb_test_MDEV-20117", + while (rec_is_delete_marked(pcur.btr_cur.page_cur.rec, + user_table->not_redundant())) { + btr_pcur_move_to_next_on_page(&pcur); + }); + buf_block_t* block = btr_pcur_get_block(&pcur); ut_ad(page_is_leaf(block->frame)); ut_ad(!page_has_prev(block->frame)); @@ -5818,12 +5825,20 @@ add_all_virtual: NULL, trx, ctx->heap, NULL); dberr_t err = DB_SUCCESS; + if (rec_is_metadata(rec, *index)) { ut_ad(page_rec_is_user_rec(rec)); if (!rec_is_alter_metadata(rec, *index) && !page_has_next(block->frame) && page_rec_is_last(rec, block->frame)) { - goto empty_table; + /* The table is empty. */ + ut_ad(fil_page_index_page_check(block->frame)); + ut_ad(!page_has_siblings(block->frame)); + ut_ad(block->page.id.page_no() == index->page); + /* MDEV-17383: free metadata BLOBs! */ + btr_page_empty(block, NULL, index, 0, &mtr); + index->clear_instant_alter(); + goto func_exit; } if (!metadata_changed) { @@ -5902,16 +5917,6 @@ add_all_virtual: } btr_pcur_close(&pcur); goto func_exit; - } else if (page_rec_is_supremum(rec)) { -empty_table: - /* The table is empty. */ - ut_ad(fil_page_index_page_check(block->frame)); - ut_ad(!page_has_siblings(block->frame)); - ut_ad(block->page.id.page_no() == index->page); - /* MDEV-17383: free metadata BLOBs! */ - btr_page_empty(block, NULL, index, 0, &mtr); - index->clear_instant_alter(); - goto func_exit; } else if (!user_table->is_instant()) { ut_ad(!user_table->not_redundant()); goto func_exit; |