Skip to content

Commit

Permalink
MDEV-18322 Assertion "wrong page type" on instant ALTER TABLE
Browse files Browse the repository at this point in the history
row_ins_clust_index_entry_low(): Invoke btr_set_instant() in the same
mini-transaction that has successfully inserted the metadata record.
In this way, if inserting the metadata record fails before any
undo log record was written for it, the index root page will remain
consistent.

innobase_instant_try(): Remove the btr_set_instant() call.

This is a 10.6 version of c17aca2.

Tested by: Matthias Leich
Reviewed by: Thirunarayanan Balathandayuthapani
  • Loading branch information
dr-m committed Dec 14, 2023
1 parent f21a6cb commit 655f78a
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 16 deletions.
24 changes: 24 additions & 0 deletions mysql-test/suite/innodb/r/instant_alter_bugs.result
Original file line number Diff line number Diff line change
Expand Up @@ -493,6 +493,30 @@ DROP TABLE t1;
CREATE TABLE t1 (i int AS (0) STORED, j INT) ENGINE=InnoDB;
ALTER TABLE t1 ADD COLUMN i INT GENERATED ALWAYS AS (1), DROP COLUMN i;
DROP TABLE t1;
#
# MDEV-18322 Assertion "wrong_page_type" on instant ALTER
#
BEGIN NOT ATOMIC
DECLARE c TEXT
DEFAULT(SELECT CONCAT('CREATE TABLE t1 (c',
GROUP_CONCAT(seq SEPARATOR ' CHAR(200), c'),
' CHAR(211)) ENGINE=InnoDB ROW_FORMAT=REDUNDANT')
FROM seq_1_to_40);
EXECUTE IMMEDIATE c;
END;
$$
INSERT INTO t1 SET c1=NULL;
ALTER TABLE t1 ADD c41 INT FIRST;
ERROR 42000: Row size too large. The maximum row size for the used table type, not counting BLOBs, is 8123. This includes storage overhead, check the manual. You have to change some columns to TEXT or BLOBs
ALTER TABLE t1 ADD c41 INT FIRST;
ERROR 42000: Row size too large. The maximum row size for the used table type, not counting BLOBs, is 8123. This includes storage overhead, check the manual. You have to change some columns to TEXT or BLOBs
CHECK TABLE t1;
Table Op Msg_type Msg_text
test.t1 check status OK
SELECT COUNT(*) FROM t1;
COUNT(*)
1
DROP TABLE t1;
# End of 10.4 tests
SET GLOBAL innodb_stats_persistent = @save_stats_persistent;
# End of 10.6 tests
25 changes: 25 additions & 0 deletions mysql-test/suite/innodb/t/instant_alter_bugs.test
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
--source include/have_innodb.inc
--source include/have_sequence.inc

SET @save_stats_persistent = @@GLOBAL.innodb_stats_persistent;
SET GLOBAL innodb_stats_persistent = 0;
Expand Down Expand Up @@ -529,6 +530,30 @@ CREATE TABLE t1 (i int AS (0) STORED, j INT) ENGINE=InnoDB;
ALTER TABLE t1 ADD COLUMN i INT GENERATED ALWAYS AS (1), DROP COLUMN i;
DROP TABLE t1;

--echo #
--echo # MDEV-18322 Assertion "wrong_page_type" on instant ALTER
--echo #

DELIMITER $$;
BEGIN NOT ATOMIC
DECLARE c TEXT
DEFAULT(SELECT CONCAT('CREATE TABLE t1 (c',
GROUP_CONCAT(seq SEPARATOR ' CHAR(200), c'),
' CHAR(211)) ENGINE=InnoDB ROW_FORMAT=REDUNDANT')
FROM seq_1_to_40);
EXECUTE IMMEDIATE c;
END;
$$
DELIMITER ;$$
INSERT INTO t1 SET c1=NULL;
--error ER_TOO_BIG_ROWSIZE
ALTER TABLE t1 ADD c41 INT FIRST;
--error ER_TOO_BIG_ROWSIZE
ALTER TABLE t1 ADD c41 INT FIRST;
CHECK TABLE t1;
SELECT COUNT(*) FROM t1;
DROP TABLE t1;

--echo # End of 10.4 tests

SET GLOBAL innodb_stats_persistent = @save_stats_persistent;
Expand Down
16 changes: 6 additions & 10 deletions storage/innobase/handler/handler0alter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6201,24 +6201,20 @@ static bool innobase_instant_try(
/* Convert the table to the instant ALTER TABLE format. */
mtr.commit();
mtr.start();
index->set_modified(mtr);
if (buf_block_t* root = btr_root_block_get(index, RW_SX_LATCH, &mtr,
if (buf_block_t* root = btr_root_block_get(index, RW_S_LATCH, &mtr,
&err)) {
if (fil_page_get_type(root->page.frame) != FIL_PAGE_INDEX) {
DBUG_ASSERT("wrong page type" == 0);
err = DB_CORRUPTION;
goto func_exit;
}

btr_set_instant(root, *index, &mtr);
mtr.commit();
mtr.start();
index->set_modified(mtr);
err = row_ins_clust_index_entry_low(
BTR_NO_LOCKING_FLAG, BTR_MODIFY_TREE, index,
index->n_uniq, entry, 0, thr);
}
mtr.commit();
mtr.start();

err = row_ins_clust_index_entry_low(
BTR_NO_LOCKING_FLAG, BTR_MODIFY_TREE, index,
index->n_uniq, entry, 0, thr);
goto func_exit;
}

Expand Down
21 changes: 15 additions & 6 deletions storage/innobase/row/row0ins.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2634,14 +2634,17 @@ row_ins_clust_index_entry_low(
ut_ad(!dict_index_is_online_ddl(index));
ut_ad(!index->table->persistent_autoinc);
ut_ad(!index->is_instant());
ut_ad(!entry->info_bits);
mtr.set_log_mode(MTR_LOG_NO_REDO);
} else {
index->set_modified(mtr);

if (UNIV_UNLIKELY(entry->is_metadata())) {
if (UNIV_UNLIKELY(entry->info_bits != 0)) {
ut_ad(entry->is_metadata());
ut_ad(index->is_instant());
ut_ad(!dict_index_is_online_ddl(index));
ut_ad(mode == BTR_MODIFY_TREE);
ut_ad(flags == BTR_NO_LOCKING_FLAG);
} else {
if (mode == BTR_MODIFY_LEAF
&& dict_index_is_online_ddl(index)) {
Expand Down Expand Up @@ -2766,11 +2769,6 @@ row_ins_clust_index_entry_low(

skip_bulk_insert:
if (UNIV_UNLIKELY(entry->info_bits != 0)) {
ut_ad(entry->is_metadata());
ut_ad(flags == BTR_NO_LOCKING_FLAG);
ut_ad(index->is_instant());
ut_ad(!dict_index_is_online_ddl(index));

const rec_t* rec = btr_pcur_get_rec(&pcur);

if (rec_get_info_bits(rec, page_rec_is_comp(rec))
Expand Down Expand Up @@ -2874,9 +2872,20 @@ row_ins_clust_index_entry_low(
}
}

if (err == DB_SUCCESS && entry->info_bits) {
if (buf_block_t* root
= btr_root_block_get(index, RW_X_LATCH, &mtr,
&err)) {
btr_set_instant(root, *index, &mtr);
} else {
ut_ad("cannot find root page" == 0);
}
}

mtr.commit();

if (big_rec) {
ut_ad(err == DB_SUCCESS);
/* Online table rebuild could read (and
ignore) the incomplete record at this point.
If online rebuild is in progress, the
Expand Down

0 comments on commit 655f78a

Please sign in to comment.