summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarko Mäkelä <marko.makela@mariadb.com>2022-11-28 11:34:22 +0200
committerMarko Mäkelä <marko.makela@mariadb.com>2022-11-28 11:34:22 +0200
commitdb14eb16f9977453467ec4765f481bb2f71814ba (patch)
treeb8702f3ac2be4dc68f1b9101dbc53350983c0a06
parente0d672f30b8a7d5486c367b5ed8ec58e41c1b6b1 (diff)
downloadmariadb-git-db14eb16f9977453467ec4765f481bb2f71814ba.tar.gz
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.
-rw-r--r--mysql-test/suite/innodb/t/log_corruption.test1
-rw-r--r--storage/innobase/dict/dict0boot.cc26
-rw-r--r--storage/innobase/ibuf/ibuf0ibuf.cc55
-rw-r--r--storage/innobase/srv/srv0start.cc3
4 files changed, 52 insertions, 33 deletions
diff --git a/mysql-test/suite/innodb/t/log_corruption.test b/mysql-test/suite/innodb/t/log_corruption.test
index 7c7f32b8d85..a3ab4510743 100644
--- a/mysql-test/suite/innodb/t/log_corruption.test
+++ b/mysql-test/suite/innodb/t/log_corruption.test
@@ -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;
diff --git a/storage/innobase/dict/dict0boot.cc b/storage/innobase/dict/dict0boot.cc
index bd2cf4ffdd8..1414f21221f 100644
--- a/storage/innobase/dict/dict0boot.cc
+++ b/storage/innobase/dict/dict0boot.cc
@@ -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);
diff --git a/storage/innobase/ibuf/ibuf0ibuf.cc b/storage/innobase/ibuf/ibuf0ibuf.cc
index ee462bc68c2..d88c2b0027e 100644
--- a/storage/innobase/ibuf/ibuf0ibuf.cc
+++ b/storage/innobase/ibuf/ibuf0ibuf.cc
@@ -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);
diff --git a/storage/innobase/srv/srv0start.cc b/storage/innobase/srv/srv0start.cc
index c0b2f5e02f0..ae4f831bf2d 100644
--- a/storage/innobase/srv/srv0start.cc
+++ b/storage/innobase/srv/srv0start.cc
@@ -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();