summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugene Kosov <claprix@yandex.ru>2019-09-23 16:26:44 +0300
committerEugene Kosov <claprix@yandex.ru>2019-09-27 11:12:44 +0300
commit77279bf00054dd77814eaafd00afcef1e65859d4 (patch)
treedaa3001e80cb76fcb9e31f11449e4afe0f95c337
parent1f4ee3fa5a80e9715b0dc77b72fabb95a4045745 (diff)
downloadmariadb-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.result18
-rw-r--r--mysql-test/suite/innodb/t/instant_alter_debug.test24
-rw-r--r--storage/innobase/btr/btr0pcur.cc1
-rw-r--r--storage/innobase/handler/handler0alter.cc27
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;