Commit 890f2ad7 authored by Eugene Kosov's avatar Eugene Kosov

MDEV-20931 ALTER...IMPORT can crash the server

Main idea: don't log-and-crash but propogate error to the upper layers of stack
to handle it and show to a user.
parent 89445b64
call mtr.add_suppression("Table `test`.`t2` should have 2 indexes but the tablespace has 1 indexes");
call mtr.add_suppression("Index for table 't2' is corrupt; try to repair it");
call mtr.add_suppression("Trying to read page number 23 in space .*, space name test/t2, which is outside the tablespace bounds. Byte offset 0, len 16384");
CREATE TABLE t1 (
id INT AUTO_INCREMENT PRIMARY KEY,
not_id INT,
data CHAR(255),
data2 BLOB
) ENGINE=INNODB;
ALTER TABLE t1 MODIFY not_id INT UNIQUE KEY;
connect purge_control,localhost,root,,;
START TRANSACTION WITH CONSISTENT SNAPSHOT;
connection default;
DELETE FROM t1 WHERE id % 2 = 1;
FLUSH TABLES t1 FOR EXPORT;
UNLOCK TABLES;
connection purge_control;
COMMIT;
connection default;
DROP TABLE t1;
CREATE TABLE t2 (
id INT AUTO_INCREMENT PRIMARY KEY,
not_id INT UNIQUE KEY,
data CHAR(255),
data2 BLOB
) ENGINE=INNODB;
ALTER TABLE t2 DISCARD TABLESPACE;
ALTER TABLE t2 IMPORT TABLESPACE;
ERROR HY000: Index for table 't2' is corrupt; try to repair it
DROP TABLE t2;
--source include/have_innodb.inc
call mtr.add_suppression("Table `test`.`t2` should have 2 indexes but the tablespace has 1 indexes");
call mtr.add_suppression("Index for table 't2' is corrupt; try to repair it");
call mtr.add_suppression("Trying to read page number 23 in space .*, space name test/t2, which is outside the tablespace bounds. Byte offset 0, len 16384");
let MYSQLD_DATADIR = `SELECT @@datadir`;
CREATE TABLE t1 (
id INT AUTO_INCREMENT PRIMARY KEY,
not_id INT,
data CHAR(255),
data2 BLOB
) ENGINE=INNODB;
--disable_query_log
--let i = 0
while ($i != 1000) {
eval INSERT INTO t1 VALUES (DEFAULT, $i, REPEAT('b', 255), REPEAT('a', 5000));
--inc $i
}
--enable_query_log
ALTER TABLE t1 MODIFY not_id INT UNIQUE KEY;
connect (purge_control,localhost,root,,);
START TRANSACTION WITH CONSISTENT SNAPSHOT;
connection default;
DELETE FROM t1 WHERE id % 2 = 1;
FLUSH TABLES t1 FOR EXPORT;
--copy_file $MYSQLD_DATADIR/test/t1.ibd $MYSQLD_DATADIR/test/tmp.ibd
--copy_file $MYSQLD_DATADIR/test/t1.cfg $MYSQLD_DATADIR/test/tmp.cfg
perl;
use strict;
die unless open(FILE, "+<$ENV{MYSQLD_DATADIR}/test/tmp.ibd");
die unless truncate(FILE, 16384*23);
close(FILE);
EOF
UNLOCK TABLES;
connection purge_control;
COMMIT;
connection default;
DROP TABLE t1;
CREATE TABLE t2 (
id INT AUTO_INCREMENT PRIMARY KEY,
not_id INT UNIQUE KEY,
data CHAR(255),
data2 BLOB
) ENGINE=INNODB;
ALTER TABLE t2 DISCARD TABLESPACE;
--copy_file $MYSQLD_DATADIR/test/tmp.ibd $MYSQLD_DATADIR/test/t2.ibd
--copy_file $MYSQLD_DATADIR/test/tmp.cfg $MYSQLD_DATADIR/test/t2.cfg
--error ER_NOT_KEYFILE
ALTER TABLE t2 IMPORT TABLESPACE;
DROP TABLE t2;
--remove_file $MYSQLD_DATADIR/test/tmp.ibd
--remove_file $MYSQLD_DATADIR/test/t2.ibd
...@@ -3141,7 +3141,7 @@ btr_page_split_and_insert( ...@@ -3141,7 +3141,7 @@ btr_page_split_and_insert(
@param[in,out] page page to remove @param[in,out] page page to remove
@param[in] index index tree @param[in] index index tree
@param[in,out] mtr mini-transaction */ @param[in,out] mtr mini-transaction */
void dberr_t
btr_level_list_remove_func( btr_level_list_remove_func(
ulint space, ulint space,
const page_size_t& page_size, const page_size_t& page_size,
...@@ -3184,6 +3184,10 @@ btr_level_list_remove_func( ...@@ -3184,6 +3184,10 @@ btr_level_list_remove_func(
page_id_t(space, next_page_no), page_size, page_id_t(space, next_page_no), page_size,
RW_X_LATCH, index, mtr); RW_X_LATCH, index, mtr);
if (!next_block) {
return DB_ERROR;
}
page_t* next_page page_t* next_page
= buf_block_get_frame(next_block); = buf_block_get_frame(next_block);
#ifdef UNIV_BTR_DEBUG #ifdef UNIV_BTR_DEBUG
...@@ -3196,6 +3200,8 @@ btr_level_list_remove_func( ...@@ -3196,6 +3200,8 @@ btr_level_list_remove_func(
buf_block_get_page_zip(next_block), buf_block_get_page_zip(next_block),
prev_page_no, mtr); prev_page_no, mtr);
} }
return DB_SUCCESS;
} }
/****************************************************************//** /****************************************************************//**
...@@ -3675,7 +3681,10 @@ btr_compress( ...@@ -3675,7 +3681,10 @@ btr_compress(
btr_search_drop_page_hash_index(block); btr_search_drop_page_hash_index(block);
/* Remove the page from the level list */ /* Remove the page from the level list */
btr_level_list_remove(space, page_size, page, index, mtr); if (DB_SUCCESS != btr_level_list_remove(space, page_size,
page, index, mtr)) {
goto err_exit;
}
if (dict_index_is_spatial(index)) { if (dict_index_is_spatial(index)) {
rec_t* my_rec = father_cursor.page_cur.rec; rec_t* my_rec = father_cursor.page_cur.rec;
...@@ -3807,7 +3816,11 @@ btr_compress( ...@@ -3807,7 +3816,11 @@ btr_compress(
#endif /* UNIV_BTR_DEBUG */ #endif /* UNIV_BTR_DEBUG */
/* Remove the page from the level list */ /* Remove the page from the level list */
btr_level_list_remove(space, page_size, (page_t*)page, index, mtr); if (DB_SUCCESS != btr_level_list_remove(space, page_size,
(page_t*)page,
index, mtr)) {
goto err_exit;
}
ut_ad(btr_node_ptr_get_child_page_no( ut_ad(btr_node_ptr_get_child_page_no(
btr_cur_get_rec(&father_cursor), offsets) btr_cur_get_rec(&father_cursor), offsets)
...@@ -4186,7 +4199,8 @@ btr_discard_page( ...@@ -4186,7 +4199,8 @@ btr_discard_page(
} }
/* Remove the page from the level list */ /* Remove the page from the level list */
btr_level_list_remove(space, page_size, page, index, mtr); ut_a(DB_SUCCESS == btr_level_list_remove(space, page_size, page,
index, mtr));
#ifdef UNIV_ZIP_DEBUG #ifdef UNIV_ZIP_DEBUG
{ {
......
...@@ -344,10 +344,12 @@ btr_cur_latch_leaves( ...@@ -344,10 +344,12 @@ btr_cur_latch_leaves(
page_size, RW_X_LATCH, cursor->index, mtr); page_size, RW_X_LATCH, cursor->index, mtr);
latch_leaves.blocks[2] = get_block; latch_leaves.blocks[2] = get_block;
#ifdef UNIV_BTR_DEBUG #ifdef UNIV_BTR_DEBUG
if (get_block) {
ut_a(page_is_comp(get_block->frame) ut_a(page_is_comp(get_block->frame)
== page_is_comp(page)); == page_is_comp(page));
ut_a(btr_page_get_prev(get_block->frame) ut_a(btr_page_get_prev(get_block->frame)
== page_get_page_no(page)); == page_get_page_no(page));
}
#endif /* UNIV_BTR_DEBUG */ #endif /* UNIV_BTR_DEBUG */
if (spatial) { if (spatial) {
cursor->rtr_info->tree_blocks[ cursor->rtr_info->tree_blocks[
......
...@@ -487,7 +487,8 @@ btr_defragment_merge_pages( ...@@ -487,7 +487,8 @@ btr_defragment_merge_pages(
lock_update_merge_left(to_block, orig_pred, lock_update_merge_left(to_block, orig_pred,
from_block); from_block);
btr_search_drop_page_hash_index(from_block); btr_search_drop_page_hash_index(from_block);
btr_level_list_remove(space, page_size, (page_t*)from_page, index, mtr); ut_a(DB_SUCCESS == btr_level_list_remove(space, page_size,
(page_t*)from_page, index, mtr));
btr_page_get_father(index, from_block, mtr, &parent); btr_page_get_father(index, from_block, mtr, &parent);
btr_cur_node_ptr_delete(&parent, mtr); btr_cur_node_ptr_delete(&parent, mtr);
/* btr_blob_dbg_remove(from_page, index, /* btr_blob_dbg_remove(from_page, index,
......
...@@ -4360,6 +4360,10 @@ buf_page_get_low( ...@@ -4360,6 +4360,10 @@ buf_page_get_low(
return (NULL); return (NULL);
} }
if (local_err == DB_IO_ERROR) {
return NULL;
}
ib::fatal() << "Unable to read page " << page_id ib::fatal() << "Unable to read page " << page_id
<< " into the buffer pool after " << " into the buffer pool after "
<< BUF_PAGE_READ_MAX_RETRIES << BUF_PAGE_READ_MAX_RETRIES
......
...@@ -201,7 +201,8 @@ buf_read_page_low( ...@@ -201,7 +201,8 @@ buf_read_page_low(
} }
return(0); return(0);
} else if (IORequest::ignore_missing(type) } else if (IORequest::ignore_missing(type)
|| *err == DB_TABLESPACE_DELETED) { || *err == DB_TABLESPACE_DELETED
|| *err == DB_IO_ERROR) {
buf_read_page_handle_error(bpage); buf_read_page_handle_error(bpage);
return(0); return(0);
} }
......
...@@ -4794,27 +4794,30 @@ fil_node_complete_io(fil_node_t* node, const IORequest& type) ...@@ -4794,27 +4794,30 @@ fil_node_complete_io(fil_node_t* node, const IORequest& type)
} }
} }
/** Report information about an invalid page access. */ /** Compose error message about an invalid page access.
static @param[in] block_offset block offset
void @param[in] space_id space id
fil_report_invalid_page_access( @param[in] space_name space name
ulint block_offset, /*!< in: block offset */ @param[in] byte_offset byte offset
ulint space_id, /*!< in: space id */ @param[in] len I/O length
const char* space_name, /*!< in: space name */ @param[in] is_read I/O type
ulint byte_offset, /*!< in: byte offset */ @return std::string with error message */
ulint len, /*!< in: I/O length */ static std::string fil_invalid_page_access_msg(size_t block_offset,
bool is_read) /*!< in: I/O type */ size_t space_id,
const char *space_name,
size_t byte_offset, size_t len,
bool is_read)
{ {
ib::fatal() std::stringstream ss;
<< "Trying to " << (is_read ? "read" : "write") ss << "Trying to " << (is_read ? "read" : "write") << " page number "
<< " page number " << block_offset << " in" << block_offset << " in space " << space_id << ", space name "
" space " << space_id << ", space name " << space_name << "," << space_name << ", which is outside the tablespace bounds. Byte offset "
" which is outside the tablespace bounds. Byte offset " << byte_offset << ", len " << len
<< byte_offset << ", len " << len << << (space_id == 0 && !srv_was_started
(space_id == 0 && !srv_was_started
? "Please check that the configuration matches" ? "Please check that the configuration matches"
" the InnoDB system tablespace location (ibdata files)" " the InnoDB system tablespace location (ibdata files)"
: ""); : "");
return ss.str();
} }
/** Reads or writes data. This operation could be asynchronous (aio). /** Reads or writes data. This operation could be asynchronous (aio).
...@@ -4951,7 +4954,17 @@ fil_io( ...@@ -4951,7 +4954,17 @@ fil_io(
return(DB_ERROR); return(DB_ERROR);
} }
fil_report_invalid_page_access( if (space->purpose == FIL_TYPE_IMPORT) {
mutex_exit(&fil_system->mutex);
ib::error() << fil_invalid_page_access_msg(
page_id.page_no(), page_id.space(),
space->name, byte_offset, len,
req_type.is_read());
return DB_IO_ERROR;
}
ib::fatal() << fil_invalid_page_access_msg(
page_id.page_no(), page_id.space(), page_id.page_no(), page_id.space(),
space->name, byte_offset, len, space->name, byte_offset, len,
req_type.is_read()); req_type.is_read());
...@@ -5032,7 +5045,7 @@ fil_io( ...@@ -5032,7 +5045,7 @@ fil_io(
return(DB_ERROR); return(DB_ERROR);
} }
fil_report_invalid_page_access( ib::fatal() << fil_invalid_page_access_msg(
page_id.page_no(), page_id.space(), page_id.page_no(), page_id.space(),
space->name, byte_offset, len, req_type.is_read()); space->name, byte_offset, len, req_type.is_read());
} }
......
...@@ -731,7 +731,7 @@ btr_validate_index( ...@@ -731,7 +731,7 @@ btr_validate_index(
/*************************************************************//** /*************************************************************//**
Removes a page from the level list of pages. */ Removes a page from the level list of pages. */
UNIV_INTERN UNIV_INTERN
void MY_ATTRIBUTE((warn_unused_result)) dberr_t
btr_level_list_remove_func( btr_level_list_remove_func(
/*=======================*/ /*=======================*/
ulint space, /*!< in: space where removed */ ulint space, /*!< in: space where removed */
......
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