Commit eaeb8ec4 authored by Marko Mäkelä's avatar Marko Mäkelä

MDEV-24653 Assertion block->page.id.page_no() == index->page failed in 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.
parent 0e10d7ea
...@@ -263,7 +263,6 @@ a b vb ...@@ -263,7 +263,6 @@ a b vb
4 NULL NULL 4 NULL NULL
5 NULL NULL 5 NULL NULL
DROP TABLE t1; 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 # MDEV-21045 AddressSanitizer: use-after-poison in mem_heap_dup / row_log_table_get_pk_col
# #
...@@ -282,3 +281,21 @@ connection default; ...@@ -282,3 +281,21 @@ connection default;
SET DEBUG_SYNC='RESET'; SET DEBUG_SYNC='RESET';
disconnect con2; disconnect con2;
DROP TABLE t1; 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;
...@@ -292,8 +292,6 @@ CHECK TABLE t1; ...@@ -292,8 +292,6 @@ CHECK TABLE t1;
SELECT * FROM t1; SELECT * FROM t1;
DROP TABLE t1; DROP TABLE t1;
SET GLOBAL innodb_purge_rseg_truncate_frequency = @save_frequency;
--echo # --echo #
--echo # MDEV-21045 AddressSanitizer: use-after-poison in mem_heap_dup / row_log_table_get_pk_col --echo # MDEV-21045 AddressSanitizer: use-after-poison in mem_heap_dup / row_log_table_get_pk_col
--echo # --echo #
...@@ -319,3 +317,26 @@ SET DEBUG_SYNC='now SIGNAL update'; ...@@ -319,3 +317,26 @@ SET DEBUG_SYNC='now SIGNAL update';
SET DEBUG_SYNC='RESET'; SET DEBUG_SYNC='RESET';
--disconnect con2 --disconnect con2
DROP TABLE t1; 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;
/***************************************************************************** /*****************************************************************************
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved. 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 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 the terms of the GNU General Public License as published by the Free Software
...@@ -128,13 +128,14 @@ btr_pcur_store_position( ...@@ -128,13 +128,14 @@ btr_pcur_store_position(
cursor->old_stored = true; cursor->old_stored = true;
if (page_is_empty(block->frame)) { 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 /* It must be an empty index tree; NOTE that in this case
we do not store the modify_clock, but always do a search we do not store the modify_clock, but always do a search
if we restore the cursor position */ if we restore the cursor position */
ut_a(!page_has_siblings(block->frame)); ut_a(!page_has_siblings(block->frame));
ut_ad(page_is_leaf(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)) { if (page_rec_is_supremum_low(offs)) {
cursor->rel_pos = BTR_PCUR_AFTER_LAST_IN_TREE; cursor->rel_pos = BTR_PCUR_AFTER_LAST_IN_TREE;
...@@ -150,7 +151,15 @@ btr_pcur_store_position( ...@@ -150,7 +151,15 @@ btr_pcur_store_position(
rec = page_rec_get_prev(rec); rec = page_rec_get_prev(rec);
ut_ad(!page_rec_is_infimum(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; cursor->rel_pos = BTR_PCUR_AFTER;
} else if (page_rec_is_infimum_low(offs)) { } else if (page_rec_is_infimum_low(offs)) {
...@@ -160,7 +169,9 @@ btr_pcur_store_position( ...@@ -160,7 +169,9 @@ btr_pcur_store_position(
ut_ad(!page_has_prev(block->frame)); ut_ad(!page_has_prev(block->frame));
rec = page_rec_get_next(rec); rec = page_rec_get_next(rec);
if (page_rec_is_supremum(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; goto before_first;
} }
} }
......
/***************************************************************************** /*****************************************************************************
Copyright (c) 2005, 2019, Oracle and/or its affiliates. All Rights Reserved. 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 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 the terms of the GNU General Public License as published by the Free Software
...@@ -4482,11 +4482,13 @@ innobase_add_instant_try( ...@@ -4482,11 +4482,13 @@ innobase_add_instant_try(
const rec_t* rec = btr_pcur_get_rec(&pcur); const rec_t* rec = btr_pcur_get_rec(&pcur);
que_thr_t* thr = pars_complete_graph_for_exec( que_thr_t* thr = pars_complete_graph_for_exec(
NULL, trx, ctx->heap, NULL); NULL, trx, ctx->heap, NULL);
const bool is_root = block->page.id.page_no() == index->page;
dberr_t err; dberr_t err;
if (rec_is_metadata(rec, index)) { if (rec_is_metadata(rec, index)) {
ut_ad(page_rec_is_user_rec(rec)); 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)) { && page_rec_is_last(rec, block->frame)) {
goto empty_table; goto empty_table;
} }
...@@ -4528,7 +4530,7 @@ innobase_add_instant_try( ...@@ -4528,7 +4530,7 @@ innobase_add_instant_try(
} }
btr_pcur_close(&pcur); btr_pcur_close(&pcur);
goto func_exit; goto func_exit;
} else if (page_rec_is_supremum(rec)) { } else if (is_root && page_rec_is_supremum(rec)) {
empty_table: empty_table:
/* The table is empty. */ /* The table is empty. */
ut_ad(fil_page_index_page_check(block->frame)); ut_ad(fil_page_index_page_check(block->frame));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment