Skip to content

Commit

Permalink
MDEV-24653 Assertion block->page.id.page_no() == index->page failed i…
Browse files Browse the repository at this point in the history
…n innobase_add_instant_try()

We may end up with an empty leaf page (containing only an ADD COLUMN
metadata record) that is not the root page.

innobase_add_instant_try(): Disable an optimization for a non-canonical
empty table that contains a metadata record somewhere else than in
the root page.

btr_pcur_store_position(): Tolerate a non-canonical empty table.
  • Loading branch information
dr-m committed Jan 25, 2021
1 parent 0e10d7e commit eaeb8ec
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 10 deletions.
19 changes: 18 additions & 1 deletion mysql-test/suite/innodb/r/instant_alter_debug.result
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,6 @@ a b vb
4 NULL NULL
5 NULL NULL
DROP TABLE t1;
SET GLOBAL innodb_purge_rseg_truncate_frequency = @save_frequency;
#
# MDEV-21045 AddressSanitizer: use-after-poison in mem_heap_dup / row_log_table_get_pk_col
#
Expand All @@ -282,3 +281,21 @@ connection default;
SET DEBUG_SYNC='RESET';
disconnect con2;
DROP TABLE t1;
#
# MDEV-24653 Assertion block->page.id.page_no() == index->page failed
# in innobase_add_instant_try()
#
SET @saved_limit = @@GLOBAL.innodb_limit_optimistic_insert_debug;
SET GLOBAL innodb_limit_optimistic_insert_debug = 2;
CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB;
INSERT INTO t1 VALUES (1),(2),(3),(4);
ALTER TABLE t1 ADD COLUMN b INT;
DELETE FROM t1;
InnoDB 0 transactions not purged
ALTER TABLE t1 ADD COLUMN c INT;
SELECT * FROM t1;
a b c
DROP TABLE t1;
SET GLOBAL innodb_limit_optimistic_insert_debug = @saved_limit;
# End of 10.3 tests
SET GLOBAL innodb_purge_rseg_truncate_frequency = @save_frequency;
25 changes: 23 additions & 2 deletions mysql-test/suite/innodb/t/instant_alter_debug.test
Original file line number Diff line number Diff line change
Expand Up @@ -292,8 +292,6 @@ CHECK TABLE t1;
SELECT * FROM t1;
DROP TABLE t1;

SET GLOBAL innodb_purge_rseg_truncate_frequency = @save_frequency;

--echo #
--echo # MDEV-21045 AddressSanitizer: use-after-poison in mem_heap_dup / row_log_table_get_pk_col
--echo #
Expand All @@ -319,3 +317,26 @@ SET DEBUG_SYNC='now SIGNAL update';
SET DEBUG_SYNC='RESET';
--disconnect con2
DROP TABLE t1;

--echo #
--echo # MDEV-24653 Assertion block->page.id.page_no() == index->page failed
--echo # in innobase_add_instant_try()
--echo #

SET @saved_limit = @@GLOBAL.innodb_limit_optimistic_insert_debug;
SET GLOBAL innodb_limit_optimistic_insert_debug = 2;

CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB;
INSERT INTO t1 VALUES (1),(2),(3),(4);
ALTER TABLE t1 ADD COLUMN b INT;
DELETE FROM t1;
--source include/wait_all_purged.inc
ALTER TABLE t1 ADD COLUMN c INT;

SELECT * FROM t1;
DROP TABLE t1;
SET GLOBAL innodb_limit_optimistic_insert_debug = @saved_limit;

--echo # End of 10.3 tests

SET GLOBAL innodb_purge_rseg_truncate_frequency = @save_frequency;
19 changes: 15 additions & 4 deletions storage/innobase/btr/btr0pcur.cc
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2016, 2020, MariaDB Corporation.
Copyright (c) 2016, 2021, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Expand Down Expand Up @@ -128,13 +128,14 @@ btr_pcur_store_position(
cursor->old_stored = true;

if (page_is_empty(block->frame)) {
ut_ad(block->page.id.page_no() == index->page);
empty_table:
/* It must be an empty index tree; NOTE that in this case
we do not store the modify_clock, but always do a search
if we restore the cursor position */

ut_a(!page_has_siblings(block->frame));
ut_ad(page_is_leaf(block->frame));
ut_ad(block->page.id.page_no() == index->page);

if (page_rec_is_supremum_low(offs)) {
cursor->rel_pos = BTR_PCUR_AFTER_LAST_IN_TREE;
Expand All @@ -150,7 +151,15 @@ btr_pcur_store_position(
rec = page_rec_get_prev(rec);

ut_ad(!page_rec_is_infimum(rec));
ut_ad(!rec_is_metadata(rec, index));

if (UNIV_UNLIKELY(rec_is_metadata(rec, index))) {
/* The table may be empty such that it only
contains a metadata record, in a leaf page
that is not the root page. */
ut_ad(index->is_primary());
ut_ad(block->page.id.page_no() != index->page);
goto empty_table;
}

cursor->rel_pos = BTR_PCUR_AFTER;
} else if (page_rec_is_infimum_low(offs)) {
Expand All @@ -160,7 +169,9 @@ btr_pcur_store_position(
ut_ad(!page_has_prev(block->frame));
rec = page_rec_get_next(rec);
if (page_rec_is_supremum(rec)) {
ut_ad(page_has_next(block->frame));
ut_ad(page_has_next(block->frame)
|| block->page.id.page_no()
!= index->page);
goto before_first;
}
}
Expand Down
8 changes: 5 additions & 3 deletions storage/innobase/handler/handler0alter.cc
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 2005, 2019, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2013, 2020, MariaDB Corporation.
Copyright (c) 2013, 2021, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Expand Down Expand Up @@ -4482,11 +4482,13 @@ innobase_add_instant_try(
const rec_t* rec = btr_pcur_get_rec(&pcur);
que_thr_t* thr = pars_complete_graph_for_exec(
NULL, trx, ctx->heap, NULL);
const bool is_root = block->page.id.page_no() == index->page;

dberr_t err;
if (rec_is_metadata(rec, index)) {
ut_ad(page_rec_is_user_rec(rec));
if (!page_has_next(block->frame)
if (is_root
&& !page_has_next(block->frame)
&& page_rec_is_last(rec, block->frame)) {
goto empty_table;
}
Expand Down Expand Up @@ -4528,7 +4530,7 @@ innobase_add_instant_try(
}
btr_pcur_close(&pcur);
goto func_exit;
} else if (page_rec_is_supremum(rec)) {
} else if (is_root && page_rec_is_supremum(rec)) {
empty_table:
/* The table is empty. */
ut_ad(fil_page_index_page_check(block->frame));
Expand Down

0 comments on commit eaeb8ec

Please sign in to comment.