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

MDEV-30106 InnoDB fails to validate the change buffer on startup

ibuf_init_at_db_start(): Validate the change buffer root page.
A later version may stop creating a change buffer, and this
validation check will prevent a downgrade from such later versions.

ibuf_max_size_update(): If the change buffer was not loaded, do nothing.

dict_boot(): Merge the local variable "error" to "err". Ignore
failures of ibuf_init_at_db_start() if innodb_force_recovery>=4.
parent e0d672f3
......@@ -19,6 +19,7 @@ call mtr.add_suppression("InnoDB: Obtaining redo log encryption key version 1 fa
call mtr.add_suppression("InnoDB: Decrypting checkpoint failed");
call mtr.add_suppression("InnoDB: Are you sure you are using the right ib_logfile0 to start up the database\\? Log sequence number in the ib_logfile0 is 1213964,");
call mtr.add_suppression("InnoDB: Log file .*ib_logfile1 is of different size 1048576 bytes than other log files 2097152 bytes!");
call mtr.add_suppression("InnoDB: The change buffer is corrupted");
--enable_query_log
let bugdir= $MYSQLTEST_VARDIR/tmp/log_corruption;
......
......@@ -313,9 +313,9 @@ dict_boot(void)
dict_mem_index_add_field(index, "NAME", 0);
index->id = DICT_TABLES_ID;
dberr_t error = dict_index_add_to_cache(
dberr_t err = dict_index_add_to_cache(
index, mach_read_from_4(dict_hdr + DICT_HDR_TABLES));
ut_a(error == DB_SUCCESS);
ut_a(err == DB_SUCCESS);
ut_ad(!table->is_instant());
table->indexes.start->n_core_null_bytes = static_cast<uint8_t>(
UT_BITS_IN_BYTES(unsigned(table->indexes.start->n_nullable)));
......@@ -325,9 +325,9 @@ dict_boot(void)
dict_mem_index_add_field(index, "ID", 0);
index->id = DICT_TABLE_IDS_ID;
error = dict_index_add_to_cache(
err = dict_index_add_to_cache(
index, mach_read_from_4(dict_hdr + DICT_HDR_TABLE_IDS));
ut_a(error == DB_SUCCESS);
ut_a(err == DB_SUCCESS);
/*-------------------------*/
table = dict_mem_table_create("SYS_COLUMNS", fil_system.sys_space,
......@@ -355,9 +355,9 @@ dict_boot(void)
dict_mem_index_add_field(index, "POS", 0);
index->id = DICT_COLUMNS_ID;
error = dict_index_add_to_cache(
err = dict_index_add_to_cache(
index, mach_read_from_4(dict_hdr + DICT_HDR_COLUMNS));
ut_a(error == DB_SUCCESS);
ut_a(err == DB_SUCCESS);
ut_ad(!table->is_instant());
table->indexes.start->n_core_null_bytes = static_cast<uint8_t>(
UT_BITS_IN_BYTES(unsigned(table->indexes.start->n_nullable)));
......@@ -398,9 +398,9 @@ dict_boot(void)
dict_mem_index_add_field(index, "ID", 0);
index->id = DICT_INDEXES_ID;
error = dict_index_add_to_cache(
err = dict_index_add_to_cache(
index, mach_read_from_4(dict_hdr + DICT_HDR_INDEXES));
ut_a(error == DB_SUCCESS);
ut_a(err == DB_SUCCESS);
ut_ad(!table->is_instant());
table->indexes.start->n_core_null_bytes = static_cast<uint8_t>(
UT_BITS_IN_BYTES(unsigned(table->indexes.start->n_nullable)));
......@@ -427,9 +427,9 @@ dict_boot(void)
dict_mem_index_add_field(index, "POS", 0);
index->id = DICT_FIELDS_ID;
error = dict_index_add_to_cache(
err = dict_index_add_to_cache(
index, mach_read_from_4(dict_hdr + DICT_HDR_FIELDS));
ut_a(error == DB_SUCCESS);
ut_a(err == DB_SUCCESS);
ut_ad(!table->is_instant());
table->indexes.start->n_core_null_bytes = static_cast<uint8_t>(
UT_BITS_IN_BYTES(unsigned(table->indexes.start->n_nullable)));
......@@ -440,9 +440,11 @@ dict_boot(void)
/* Initialize the insert buffer table and index for each tablespace */
dberr_t err = ibuf_init_at_db_start();
err = ibuf_init_at_db_start();
if (err == DB_SUCCESS) {
if (err == DB_SUCCESS
|| srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE) {
err = DB_SUCCESS;
/* Load definitions of other indexes on system tables */
dict_load_sys_table(dict_sys.sys_tables);
......
......@@ -50,6 +50,7 @@ Created 7/19/1997 Heikki Tuuri
#include "que0que.h"
#include "srv0start.h" /* srv_shutdown_state */
#include "rem0cmp.h"
#include "log.h"
/* STRUCTURE OF AN INSERT BUFFER RECORD
......@@ -408,35 +409,24 @@ ibuf_init_at_db_start(void)
ulint n_used;
ut_ad(!ibuf.index);
dberr_t err;
mtr_t mtr;
mtr.start();
compile_time_assert(IBUF_SPACE_ID == TRX_SYS_SPACE);
compile_time_assert(IBUF_SPACE_ID == 0);
mtr_x_lock_space(fil_system.sys_space, &mtr);
buf_block_t* header_page = buf_page_get(
buf_block_t* header_page = buf_page_get_gen(
page_id_t(IBUF_SPACE_ID, FSP_IBUF_HEADER_PAGE_NO),
0, RW_X_LATCH, &mtr);
0, RW_X_LATCH, nullptr, BUF_GET,
__FILE__, __LINE__, &mtr, &err);
if (!header_page) {
err_exit:
sql_print_error("InnoDB: The change buffer is corrupted");
mtr.commit();
return DB_DECRYPTION_FAILED;
return err;
}
/* At startup we intialize ibuf to have a maximum of
CHANGE_BUFFER_DEFAULT_SIZE in terms of percentage of the
buffer pool size. Once ibuf struct is initialized this
value is updated with the user supplied size by calling
ibuf_max_size_update(). */
ibuf.max_size = ((buf_pool_get_curr_size() >> srv_page_size_shift)
* CHANGE_BUFFER_DEFAULT_SIZE) / 100;
mutex_create(LATCH_ID_IBUF, &ibuf_mutex);
mutex_create(LATCH_ID_IBUF_PESSIMISTIC_INSERT,
&ibuf_pessimistic_insert_mutex);
mutex_enter(&ibuf_mutex);
fseg_n_reserved_pages(*header_page,
IBUF_HEADER + IBUF_TREE_SEG_HEADER
+ header_page->frame, &n_used, &mtr);
......@@ -448,15 +438,39 @@ ibuf_init_at_db_start(void)
{
buf_block_t* block;
block = buf_page_get(
block = buf_page_get_gen(
page_id_t(IBUF_SPACE_ID, FSP_IBUF_TREE_ROOT_PAGE_NO),
0, RW_X_LATCH, &mtr);
0, RW_X_LATCH, nullptr, BUF_GET,
__FILE__, __LINE__, &mtr, &err);
if (!block) goto err_exit;
buf_block_dbg_add_level(block, SYNC_IBUF_TREE_NODE);
root = buf_block_get_frame(block);
}
if (page_is_comp(root) || fil_page_get_type(root) != FIL_PAGE_INDEX
|| btr_page_get_index_id(root) != DICT_IBUF_ID_MIN) {
err = DB_CORRUPTION;
goto err_exit;
}
/* At startup we initialize ibuf to have a maximum of
CHANGE_BUFFER_DEFAULT_SIZE in terms of percentage of the
buffer pool size. Once ibuf struct is initialized this
value is updated with the user supplied size by calling
ibuf_max_size_update(). */
ibuf.max_size = ((buf_pool_get_curr_size() >> srv_page_size_shift)
* CHANGE_BUFFER_DEFAULT_SIZE) / 100;
mutex_create(LATCH_ID_IBUF, &ibuf_mutex);
mutex_create(LATCH_ID_IBUF_PESSIMISTIC_INSERT,
&ibuf_pessimistic_insert_mutex);
mutex_enter(&ibuf_mutex);
ibuf_size_update(root);
mutex_exit(&ibuf_mutex);
......@@ -507,6 +521,7 @@ ibuf_max_size_update(
ulint new_val) /*!< in: new value in terms of
percentage of the buffer pool size */
{
if (UNIV_UNLIKELY(!ibuf.index)) return;
ulint new_size = ((buf_pool_get_curr_size() >> srv_page_size_shift)
* new_val) / 100;
mutex_enter(&ibuf_mutex);
......
......@@ -2056,7 +2056,8 @@ void innodb_shutdown()
|| srv_force_recovery >= SRV_FORCE_NO_TRX_UNDO);
ut_ad(lock_sys.is_initialised() || !srv_was_started);
ut_ad(log_sys.is_initialised() || !srv_was_started);
ut_ad(ibuf.index || !srv_was_started);
ut_ad(ibuf.index || !srv_was_started
|| srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE);
dict_stats_deinit();
......
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