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

MDEV-24512 Assertion failed in rec_is_metadata() in btr_discard_only_page_on_level()

btr_discard_only_page_on_level(): Attempt to read the MDEV-15562 metadata
record from the leaf page, not the root page. In the root, the leftmost
(in this case, the only) node pointer would look like a metadata record.

This corruption bug was introduced in
commit 0e5a4ac2 (MDEV-15562).
The scenario is rare: a column was dropped instantly or the order of
columns was changed instantly, and then the table became empty in such
a way that in the last step, the root page had one child page.
Normally, a non-leaf B-tree page would always contain at least 2 children.
parent 734c587f
...@@ -327,7 +327,6 @@ FROM information_schema.global_status ...@@ -327,7 +327,6 @@ FROM information_schema.global_status
WHERE variable_name = 'innodb_instant_alter_column'; WHERE variable_name = 'innodb_instant_alter_column';
instants instants
22 22
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
# #
...@@ -370,3 +369,18 @@ b ...@@ -370,3 +369,18 @@ b
SET DEBUG_SYNC='RESET'; SET DEBUG_SYNC='RESET';
disconnect con2; disconnect con2;
DROP TABLE t1; DROP TABLE t1;
#
# MDEV-24512 Assertion failed in rec_is_metadata()
# in btr_discard_only_page_on_level()
#
SET @save_limit= @@GLOBAL.innodb_limit_optimistic_insert_debug;
SET GLOBAL innodb_limit_optimistic_insert_debug=2;
CREATE TABLE t1 (c CHAR(1) UNIQUE) ENGINE=InnoDB;
ALTER TABLE t1 ADD c2 INT NOT NULL DEFAULT 0 FIRST;
INSERT INTO t1 (c) VALUES ('x'),('d'),('r'),('f'),('y'),('u'),('m'),('d');
ERROR 23000: Duplicate entry 'd' for key 'c'
SET GLOBAL innodb_limit_optimistic_insert_debug=@save_limit;
SELECT * FROM t1;
c2 c
DROP TABLE t1;
SET GLOBAL innodb_purge_rseg_truncate_frequency = @save_frequency;
...@@ -361,8 +361,6 @@ SELECT variable_value-@old_instant instants ...@@ -361,8 +361,6 @@ SELECT variable_value-@old_instant instants
FROM information_schema.global_status FROM information_schema.global_status
WHERE variable_name = 'innodb_instant_alter_column'; WHERE variable_name = 'innodb_instant_alter_column';
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 #
...@@ -414,3 +412,21 @@ SELECT * FROM t1; ...@@ -414,3 +412,21 @@ SELECT * FROM t1;
SET DEBUG_SYNC='RESET'; SET DEBUG_SYNC='RESET';
--disconnect con2 --disconnect con2
DROP TABLE t1; DROP TABLE t1;
--echo #
--echo # MDEV-24512 Assertion failed in rec_is_metadata()
--echo # in btr_discard_only_page_on_level()
--echo #
SET @save_limit= @@GLOBAL.innodb_limit_optimistic_insert_debug;
SET GLOBAL innodb_limit_optimistic_insert_debug=2;
CREATE TABLE t1 (c CHAR(1) UNIQUE) ENGINE=InnoDB;
ALTER TABLE t1 ADD c2 INT NOT NULL DEFAULT 0 FIRST;
--error ER_DUP_ENTRY
INSERT INTO t1 (c) VALUES ('x'),('d'),('r'),('f'),('y'),('u'),('m'),('d');
SET GLOBAL innodb_limit_optimistic_insert_debug=@save_limit;
SELECT * FROM t1;
DROP TABLE t1;
SET GLOBAL innodb_purge_rseg_truncate_frequency = @save_frequency;
...@@ -4094,12 +4094,13 @@ btr_discard_only_page_on_level( ...@@ -4094,12 +4094,13 @@ btr_discard_only_page_on_level(
mtr_t* mtr) /*!< in: mtr */ mtr_t* mtr) /*!< in: mtr */
{ {
ulint page_level = 0; ulint page_level = 0;
trx_id_t max_trx_id;
ut_ad(!index->is_dummy); ut_ad(!index->is_dummy);
/* Save the PAGE_MAX_TRX_ID from the leaf page. */ /* Save the PAGE_MAX_TRX_ID from the leaf page. */
max_trx_id = page_get_max_trx_id(buf_block_get_frame(block)); const trx_id_t max_trx_id = page_get_max_trx_id(block->frame);
const rec_t* r = page_rec_get_next(page_get_infimum_rec(block->frame));
ut_ad(rec_is_metadata(r, *index) == index->is_instant());
while (block->page.id.page_no() != dict_index_get_page(index)) { while (block->page.id.page_no() != dict_index_get_page(index)) {
btr_cur_t cursor; btr_cur_t cursor;
...@@ -4154,9 +4155,6 @@ btr_discard_only_page_on_level( ...@@ -4154,9 +4155,6 @@ btr_discard_only_page_on_level(
const rec_t* rec = NULL; const rec_t* rec = NULL;
rec_offs* offsets = NULL; rec_offs* offsets = NULL;
if (index->table->instant) { if (index->table->instant) {
const rec_t* r = page_rec_get_next(page_get_infimum_rec(
block->frame));
ut_ad(rec_is_metadata(r, *index) == index->is_instant());
if (rec_is_alter_metadata(r, *index)) { if (rec_is_alter_metadata(r, *index)) {
heap = mem_heap_create(srv_page_size); heap = mem_heap_create(srv_page_size);
offsets = rec_get_offsets(r, index, NULL, true, offsets = rec_get_offsets(r, index, NULL, true,
......
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